/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2022 by Hitachi Vantara : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/

package org.pentaho.di.trans.steps.rssoutput;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.Date;


import org.apache.commons.vfs2.FileObject;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.ResultFile;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleStepException;
import org.pentaho.di.core.vfs.KettleVFS;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.BaseStep;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;

import com.rometools.modules.georss.GeoRSSModule;
import com.rometools.modules.georss.SimpleModuleImpl;
import com.rometools.modules.georss.W3CGeoModuleImpl;
import com.rometools.rome.feed.synd.SyndContent;
import com.rometools.rome.feed.synd.SyndContentImpl;
import com.rometools.rome.feed.synd.SyndEntry;
import com.rometools.rome.feed.synd.SyndEntryImpl;
import com.rometools.rome.feed.synd.SyndFeedImpl;
import com.rometools.rome.feed.synd.SyndImage;
import com.rometools.rome.feed.synd.SyndImageImpl;
import com.rometools.rome.io.SyndFeedOutput;
import com.rometools.modules.georss.geometries.Position;

/**
 * Output rows to RSS feed and create a file.
 *
 * @author Samatar
 * @since 6-nov-2007
 */
public class RssOutput extends BaseStep implements StepInterface {
  private static Class<?> PKG = RssOutput.class; // for i18n purposes, needed by Translator2!!

  private RssOutputMeta meta;
  private RssOutputData data;

  public RssOutput( StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr, TransMeta transMeta,
    Trans trans ) {
    super( stepMeta, stepDataInterface, copyNr, transMeta, trans );
  }

  public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException {
    meta = (RssOutputMeta) smi;
    data = (RssOutputData) sdi;

    Object[] r = getRow(); // this also waits for a previous step to be finished.

    if ( r == null ) { // no more input to be expected...

      if ( !first ) {
        if ( !meta.isCustomRss() ) {
          // No more input..so write and close the file.
          WriteToFile(
            data.channeltitlevalue, data.channellinkvalue, data.channeldescriptionvalue,
            data.channelpubdatevalue, data.channelcopyrightvalue, data.channelimagelinkvalue,
            data.channelimagedescriptionvalue, data.channelimagelinkvalue, data.channelimageurlvalue,
            data.channellanguagevalue, data.channelauthorvalue );
        } else {

          // Write to document
          OutputFormat format = org.dom4j.io.OutputFormat.createPrettyPrint();
          // Set encoding ...
          if ( Utils.isEmpty( meta.getEncoding() ) ) {
            format.setEncoding( "iso-8859-1" );
          } else {
            format.setEncoding( meta.getEncoding() );
          }

          try {
            XMLWriter writer = new XMLWriter( new FileWriter( new File( data.filename ) ), format );
            writer.write( data.document );
            writer.close();
          } catch ( Exception e ) {
            // Ignore errors
          } finally {
            data.document = null;
          }

        }
      }
      setOutputDone();
      return false;
    }

    if ( first ) {
      first = false;
      data.inputRowMeta = getInputRowMeta();
      data.outputRowMeta = data.inputRowMeta.clone();
      meta.getFields( data.outputRowMeta, getStepname(), null, null, this, repository, metaStore );
      // Let's check for filename...

      if ( meta.isFilenameInField() ) {
        if ( Utils.isEmpty( meta.getFileNameField() ) ) {
          logError( BaseMessages.getString( PKG, "RssOutput.Log.FilenameFieldMissing" ) );
          setErrors( 1 );
          stopAll();
          return false;
        }

        // get filename field index
        data.indexOfFieldfilename = data.inputRowMeta.indexOfValue( meta.getFileNameField() );
        if ( data.indexOfFieldfilename < 0 ) {
          // The field is unreachable !
          logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getFileNameField() ) );
          throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
            .getFileNameField() ) );
        }

      } else {
        data.filename = buildFilename();
      }

      // Check if filename is empty..
      if ( Utils.isEmpty( data.filename ) ) {
        logError( BaseMessages.getString( PKG, "RssOutput.Log.FilenameEmpty" ) );
        throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.FilenameEmpty" ) );
      }

      // Do we need to create parent folder ?
      if ( meta.isCreateParentFolder() ) {
        // Check for parent folder
        FileObject parentfolder = null;
        try {
          // Get parent folder
          parentfolder = KettleVFS.getFileObject( data.filename, getTransMeta() ).getParent();
          if ( !parentfolder.exists() ) {
            if ( log.isDetailed() ) {
              logDetailed( BaseMessages.getString( PKG, "RssOutput.Log.ParentFolderExists", parentfolder
                .getName().toString() ) );
            }
            parentfolder.createFolder();
            if ( log.isDetailed() ) {
              logDetailed( BaseMessages.getString( PKG, "RssOutput.Log.CanNotCreateParentFolder", parentfolder
                .getName().toString() ) );
            }
          }
        } catch ( Exception e ) {
          // The field is unreachable !
          logError( BaseMessages.getString( PKG, "RssOutput.Log.CanNotCreateParentFolder", parentfolder
            .getName().toString() ) );
          throw new KettleException( BaseMessages.getString(
            PKG, "RssOutput.Log.CanNotCreateParentFolder", parentfolder.getName().toString() ) );

        } finally {
          if ( parentfolder != null ) {
            try {
              parentfolder.close();
            } catch ( Exception ex ) { /* Ignore */
            }
          }
        }
      }

      if ( !meta.isCustomRss() ) {
        // Let's check for mandatory fields ...
        if ( Utils.isEmpty( meta.getChannelTitle() ) ) {
          logError( BaseMessages.getString( PKG, "RssOutput.Log.ChannelTitleMissing" ) );
          setErrors( 1 );
          stopAll();
          return false;
        }
        if ( Utils.isEmpty( meta.getChannelDescription() ) ) {
          logError( BaseMessages.getString( PKG, "RssOutput.Log.ChannelDescription" ) );
          setErrors( 1 );
          stopAll();
          return false;
        }
        if ( Utils.isEmpty( meta.getChannelLink() ) ) {
          logError( BaseMessages.getString( PKG, "RssOutput.Log.ChannelLink" ) );
          setErrors( 1 );
          stopAll();
          return false;
        }

        // Let's take the index of channel title field ...
        data.indexOfFieldchanneltitle = data.inputRowMeta.indexOfValue( meta.getChannelTitle() );
        if ( data.indexOfFieldchanneltitle < 0 ) {
          // The field is unreachable !
          logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getChannelTitle() ) );
          throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
            .getChannelTitle() ) );
        }
        data.channeltitlevalue = data.inputRowMeta.getString( r, data.indexOfFieldchanneltitle );

        // Let's take the index of channel description field ...
        data.indexOfFieldchanneldescription = data.inputRowMeta.indexOfValue( meta.getChannelDescription() );
        if ( data.indexOfFieldchanneldescription < 0 ) {
          // The field is unreachable !
          logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getChannelDescription() ) );
          throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
            .getChannelDescription() ) );
        }

        data.channeldescriptionvalue = data.inputRowMeta.getString( r, data.indexOfFieldchanneldescription );

        // Let's take the index of channel link field ...
        data.indexOfFieldchannellink = data.inputRowMeta.indexOfValue( meta.getChannelLink() );
        if ( data.indexOfFieldchannellink < 0 ) {
          // The field is unreachable !
          logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getChannelLink() ) );
          throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
            .getChannelLink() ) );
        }

        data.channellinkvalue = data.inputRowMeta.getString( r, data.indexOfFieldchannellink );

        if ( !Utils.isEmpty( meta.getItemTitle() ) ) {
          // Let's take the index of item title field ...
          data.indexOfFielditemtitle = data.inputRowMeta.indexOfValue( meta.getItemTitle() );
          if ( data.indexOfFielditemtitle < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getItemTitle() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getItemTitle() ) );
          }
        }

        if ( !Utils.isEmpty( meta.getItemDescription() ) ) {
          // Let's take the index of item description field ...
          data.indexOfFielditemdescription = data.inputRowMeta.indexOfValue( meta.getItemDescription() );
          if ( data.indexOfFielditemdescription < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getItemDescription() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getItemDescription() ) );
          }
        }
        if ( meta.AddGeoRSS() ) {
          if ( Utils.isEmpty( meta.getGeoPointLong() ) ) {
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.GeoPointLatEmpty" ) );
          }
          if ( Utils.isEmpty( meta.getGeoPointLong() ) ) {
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.GeoPointLongEmpty" ) );
          }

          // Let's take the index of item geopointX field ...
          data.indexOfFielditempointx = data.inputRowMeta.indexOfValue( meta.getGeoPointLat() );
          if ( data.indexOfFielditempointx < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getGeoPointLat() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getGeoPointLat() ) );
          }
          // Let's take the index of item geopointY field ...
          data.indexOfFielditempointy = data.inputRowMeta.indexOfValue( meta.getGeoPointLong() );
          if ( data.indexOfFielditempointy < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getGeoPointLong() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getGeoPointLong() ) );
          }
        }

        // It's time to check non empty fields !
        // Channel PubDate field ...
        if ( !Utils.isEmpty( meta.getChannelPubDate() ) ) {
          data.indexOfFieldchannelpubdate = data.inputRowMeta.indexOfValue( meta.getChannelPubDate() );
          if ( data.indexOfFieldchannelpubdate < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getChannelPubDate() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getChannelPubDate() ) );
          }

          data.channelpubdatevalue = data.inputRowMeta.getDate( r, data.indexOfFieldchannelpubdate );
        }
        // Channel Language field ...
        if ( !Utils.isEmpty( meta.getChannelLanguage() ) ) {
          data.indexOfFieldchannellanguage = data.inputRowMeta.indexOfValue( meta.getChannelLanguage() );
          if ( data.indexOfFieldchannellanguage < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getChannelLanguage() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getChannelLanguage() ) );
          }

          data.channellanguagevalue = data.inputRowMeta.getString( r, data.indexOfFieldchannellanguage );
        }

        // Channel Copyright field ...
        if ( !Utils.isEmpty( meta.getChannelCopyright() ) ) {
          data.indexOfFieldchannelcopyright = data.inputRowMeta.indexOfValue( meta.getChannelCopyright() );
          if ( data.indexOfFieldchannelcopyright < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getChannelCopyright() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getChannelCopyright() ) );
          }

          data.channelcopyrightvalue = data.inputRowMeta.getString( r, data.indexOfFieldchannelcopyright );
        }

        // Channel Author field ...
        if ( !Utils.isEmpty( meta.getChannelAuthor() ) ) {
          data.indexOfFieldchannelauthor = data.inputRowMeta.indexOfValue( meta.getChannelAuthor() );
          if ( data.indexOfFieldchannelauthor < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getChannelAuthor() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getChannelAuthor() ) );
          }

          data.channelauthorvalue = data.inputRowMeta.getString( r, data.indexOfFieldchannelauthor );
        }

        // Channel Image field ...
        if ( meta.AddImage() ) {
          // Channel image title
          if ( !Utils.isEmpty( meta.getChannelImageTitle() ) ) {
            data.indexOfFieldchannelimagetitle = data.inputRowMeta.indexOfValue( meta.getChannelImageTitle() );
            if ( data.indexOfFieldchannelimagetitle < 0 ) {
              // The field is unreachable !
              logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
                .getChannelImageTitle() ) );
              throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
                .getChannelImageTitle() ) );
            }

            data.channelimagetitlevalue = data.inputRowMeta.getString( r, data.indexOfFieldchannelimagetitle );
          }

          // Channel link title
          if ( !Utils.isEmpty( meta.getChannelImageLink() ) ) {
            data.indexOfFieldchannelimagelink = data.inputRowMeta.indexOfValue( meta.getChannelImageLink() );
            if ( data.indexOfFieldchannelimagelink < 0 ) {
              // The field is unreachable !
              logError( BaseMessages
                .getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getChannelImageLink() ) );
              throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
                .getChannelImageLink() ) );
            }

            data.channelimagelinkvalue = data.inputRowMeta.getString( r, data.indexOfFieldchannelimagelink );
          }

          // Channel url title
          if ( !Utils.isEmpty( meta.getChannelImageUrl() ) ) {
            data.indexOfFieldchannelimageurl = data.inputRowMeta.indexOfValue( meta.getChannelImageUrl() );
            if ( data.indexOfFieldchannelimageurl < 0 ) {
              // The field is unreachable !
              logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getChannelImageUrl() ) );
              throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
                .getChannelImageUrl() ) );
            }

            data.channelimageurlvalue = data.inputRowMeta.getString( r, data.indexOfFieldchannelimageurl );
          }

          // Channel description title
          if ( !Utils.isEmpty( meta.getChannelImageDescription() ) ) {
            data.indexOfFieldchannelimagedescription =
              data.inputRowMeta.indexOfValue( meta.getChannelImageDescription() );
            if ( data.indexOfFieldchannelimagedescription < 0 ) {
              // The field is unreachable !
              logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
                .getChannelImageDescription() ) );
              throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
                .getChannelImageDescription() ) );
            }

            data.channelimagedescriptionvalue =
              data.inputRowMeta.getString( r, data.indexOfFieldchannelimagedescription );
          }

        }

        // Item link field ...
        if ( !Utils.isEmpty( meta.getItemLink() ) ) {
          data.indexOfFielditemlink = data.inputRowMeta.indexOfValue( meta.getItemLink() );
          if ( data.indexOfFielditemlink < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getItemLink() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getItemLink() ) );
          }

        }

        // Item pubdate field ...
        if ( !Utils.isEmpty( meta.getItemPubDate() ) ) {
          data.indexOfFielditempubdate = data.inputRowMeta.indexOfValue( meta.getItemPubDate() );
          if ( data.indexOfFielditempubdate < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getItemPubDate() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getItemPubDate() ) );
          }
        }

        // Item author field ...
        if ( !Utils.isEmpty( meta.getItemAuthor() ) ) {
          data.indexOfFielditemauthor = data.inputRowMeta.indexOfValue( meta.getItemAuthor() );
          if ( data.indexOfFielditemauthor < 0 ) {
            // The field is unreachable !
            logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta.getItemAuthor() ) );
            throw new KettleException( BaseMessages.getString( PKG, "RssOutput.Log.ErrorFindingField", meta
              .getItemAuthor() ) );
          }
        }
      } else {
        // Custom RSS
        // Check Custom channel fields
        data.customchannels = new int[meta.getChannelCustomFields().length];
        for ( int i = 0; i < meta.getChannelCustomFields().length; i++ ) {
          data.customchannels[i] = data.inputRowMeta.indexOfValue( meta.getChannelCustomFields()[i] );
          if ( data.customchannels[i] < 0 ) { // couldn't find field!

            throw new KettleStepException( BaseMessages.getString( PKG, "RssOutput.Exception.FieldRequired", meta
              .getChannelCustomFields()[i] ) );
          }
        }
        // Check Custom channel fields
        data.customitems = new int[meta.getItemCustomFields().length];
        for ( int i = 0; i < meta.getItemCustomFields().length; i++ ) {
          data.customitems[i] = data.inputRowMeta.indexOfValue( meta.getItemCustomFields()[i] );
          if ( data.customitems[i] < 0 ) { // couldn't find field!

            throw new KettleStepException( BaseMessages.getString( PKG, "RssOutput.Exception.FieldRequired", meta
              .getItemCustomFields()[i] ) );
          }
        }
        // Prepare Output RSS Custom document
        data.document = DocumentHelper.createDocument();
        data.rssElement = data.document.addElement( "rss" );
        data.rssElement.addAttribute( "version", "2.0" );
        // add namespaces here ...
        for ( int i = 0; i < meta.getNameSpaces().length; i++ ) {
          data.rssElement.addNamespace(
            environmentSubstitute( meta.getNameSpacesTitle()[i] ),
            environmentSubstitute( meta.getNameSpaces()[i] ) );
        }

        // Add channel
        data.channel = data.rssElement.addElement( "channel" );

        // Set channel Only the first time ...
        for ( int i = 0; i < data.customchannels.length; i++ ) {
          String channelname = environmentSubstitute( meta.getChannelCustomTags()[i] );
          String channelvalue = data.inputRowMeta.getString( r, data.customchannels[i] );

          if ( log.isDetailed() ) {
            logDetailed( "outputting channel value <"
              + channelname + ">" + channelvalue + "<" + channelname + "/>" );
          }

          // add Channel
          Element channeltag = data.channel.addElement( channelname );
          channeltag.setText( channelvalue );

        }
      }
    } // end test first time

    // Let's get value for each item...
    if ( !meta.isCustomRss() ) {
      String itemtitlevalue = null;
      String itemauthorvalue = null;
      String itemlinkvalue = null;
      Date itemdatevalue = null;
      String itemdescvalue = null;
      String itemgeopointx = null;
      String itemgeopointy = null;

      if ( data.indexOfFielditemtitle > -1 ) {
        itemtitlevalue = data.inputRowMeta.getString( r, data.indexOfFielditemtitle );
      }
      if ( data.indexOfFielditemauthor > -1 ) {
        itemauthorvalue = data.inputRowMeta.getString( r, data.indexOfFielditemauthor );
      }
      if ( data.indexOfFielditemlink > -1 ) {
        itemlinkvalue = data.inputRowMeta.getString( r, data.indexOfFielditemlink );
      }
      if ( data.indexOfFielditempubdate > -1 ) {
        itemdatevalue = data.inputRowMeta.getDate( r, data.indexOfFielditempubdate );
      }
      if ( data.indexOfFielditemdescription > -1 ) {
        itemdescvalue = data.inputRowMeta.getString( r, data.indexOfFielditemdescription );
      }
      if ( data.indexOfFielditempointx > -1 ) {
        itemgeopointx = data.inputRowMeta.getString( r, data.indexOfFielditempointx );
      }
      if ( data.indexOfFielditempointy > -1 ) {
        itemgeopointy = data.inputRowMeta.getString( r, data.indexOfFielditempointy );
      }

      // Now add entry ..
      if ( !createEntry(
        itemauthorvalue, itemtitlevalue, itemlinkvalue, itemdatevalue, itemdescvalue, itemgeopointx,
        itemgeopointy ) ) {
        throw new KettleException( "Error adding item to feed" );
      }
    } else {

      // Set item tag at each row received
      if ( meta.isDisplayItem() ) {
        data.itemtag = data.channel.addElement( "item" );
      }
      for ( int i = 0; i < data.customitems.length; i++ ) {
        // get item value and name
        String itemname = environmentSubstitute( meta.getItemCustomTags()[i] );
        String itemvalue = data.inputRowMeta.getString( r, data.customitems[i] );

        if ( log.isDetailed() ) {
          logDetailed( "outputting item value <" + itemname + ">" + itemvalue + "<" + itemname + "/>" );
        }

        // add Item
        if ( meta.isDisplayItem() ) {
          Element itemtagsub = data.itemtag.addElement( itemname );
          itemtagsub.setText( itemvalue );
        } else {
          // display item at channel level
          Element temp = data.channel.addElement( itemname );
          temp.setText( itemvalue );
        }
      }
    }

    try {
      putRow( data.outputRowMeta, r ); // in case we want it to go further...
      incrementLinesOutput();

      if ( checkFeedback( getLinesOutput() ) ) {
        if ( log.isDebug() ) {
          logDebug( BaseMessages.getString( PKG, "RssOutput.Log.Linenr", "" + getLinesOutput() ) );
        }
      }

    } catch ( KettleStepException e ) {
      logError( BaseMessages.getString( PKG, "RssOutputMeta.Log.ErrorInStep" ) + e.getMessage() );
      setErrors( 1 );
      stopAll();
      setOutputDone(); // signal end to receiver(s)
      return false;
    }

    return true;
  }

  public String buildFilename() throws KettleStepException {
    return meta.buildFilename( this, getCopy() );
  }

  /**
   * @param author
   *          : The author of the event
   * @param title
   *          : The title of the event
   * @param link
   *          : The link to the element in RES
   * @param date
   *          : The event's date
   * @param desc
   *          : The event's description
   */
  @SuppressWarnings( "unchecked" )
  public boolean createEntry( String author, String title, String link, Date date, String desc,
    String geopointLat, String geopointLong ) {
    boolean retval = false;
    try {
      // Add entry to the feed
      SyndEntry entry = new SyndEntryImpl();
      SyndContent description;

      entry = new SyndEntryImpl();
      if ( title != null ) {
        entry.setTitle( title );
      }
      if ( link != null ) {
        entry.setLink( link );
      }
      if ( date != null ) {
        entry.setPublishedDate( date );
      }
      if ( author != null ) {
        entry.setAuthor( author );
      }
      if ( desc != null ) {
        description = new SyndContentImpl();
        description.setType( "text/plain" );
        description.setValue( desc );
        entry.setDescription( description );
      }
      if ( meta.AddGeoRSS() && geopointLat != null && geopointLong != null ) {
        // Add GeoRSS?
        GeoRSSModule geoRSSModule = new SimpleModuleImpl();
        if ( meta.useGeoRSSGML() ) {
          geoRSSModule = new W3CGeoModuleImpl();
        }
        geoRSSModule.setPosition( new Position( Const.toDouble( geopointLat.replace( ',', '.' ), 0 ), Const
          .toDouble( geopointLong.replace( ',', '.' ), 0 ) ) );
        entry.getModules().add( geoRSSModule );
      }

      data.entries.add( entry );

      retval = true;
    } catch ( Exception e ) {
      logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorAddingEntry", e.getMessage() ) );
      setErrors( 1 );
      retval = false;
    }
    return retval;
  }

  private boolean WriteToFile( String title, String link, String description, Date Pubdate, String copyright,
    String imageTitle, String imageDescription, String imageLink, String imageUrl, String language, String author ) {
    boolean retval = false;
    try {
      // Specify Filename
      String fileName = data.filename;

      // Set channel ...
      data.feed = new SyndFeedImpl();
      if ( Utils.isEmpty( meta.getVersion() ) ) {
        data.feed.setFeedType( "rss_2.0" );
      } else {
        data.feed.setFeedType( meta.getVersion() );
      }

      // Set encoding ...
      if ( Utils.isEmpty( meta.getEncoding() ) ) {
        data.feed.setEncoding( "iso-8859-1" );
      } else {
        data.feed.setEncoding( meta.getEncoding() );
      }

      if ( title != null ) {
        data.feed.setTitle( title );
      }
      if ( link != null ) {
        data.feed.setLink( link );
      }
      if ( description != null ) {
        data.feed.setDescription( description );
      }
      if ( Pubdate != null ) {
        data.feed.setPublishedDate( Pubdate ); // data.dateParser.parse(Pubdate.toString()));
      }
      // Set image ..
      if ( meta.AddImage() ) {
        SyndImage image = new SyndImageImpl();
        if ( imageTitle != null ) {
          image.setTitle( title );
        }
        if ( imageLink != null ) {
          image.setLink( link );
        }
        if ( imageUrl != null ) {
          image.setUrl( imageUrl );
        }
        if ( imageDescription != null ) {
          image.setDescription( imageDescription );
        }
        data.feed.setImage( image );
      }
      if ( language != null ) {
        data.feed.setLanguage( language );
      }
      if ( copyright != null ) {
        data.feed.setCopyright( copyright );
      }
      if ( author != null ) {
        data.feed.setAuthor( author );
      }

      // Add entries
      data.feed.setEntries( data.entries );

      Writer writer = new FileWriter( fileName );
      SyndFeedOutput output = new SyndFeedOutput();
      output.output( data.feed, writer );
      writer.close();

      if ( meta.AddToResult() ) {
        // Add this to the result file names...
        ResultFile resultFile =
          new ResultFile(
            ResultFile.FILE_TYPE_GENERAL, KettleVFS.getFileObject( fileName, getTransMeta() ), getTransMeta()
              .getName(), getStepname() );
        resultFile.setComment( "This file was created with a RSS Output step" );
        addResultFile( resultFile );
      }

      if ( log.isDetailed() ) {
        logDetailed( BaseMessages.getString( PKG, "RssOutput.Log.CreatingFileOK", fileName ) );
      }

      retval = true;
    } catch ( Exception e ) {
      logError( BaseMessages.getString( PKG, "RssOutput.Log.ErrorCreatingFile", e.toString() ) );
      setErrors( 1 );
      retval = false;
    }
    return retval;
  }

  public boolean init( StepMetaInterface smi, StepDataInterface sdi ) {
    meta = (RssOutputMeta) smi;
    data = (RssOutputData) sdi;

    if ( super.init( smi, sdi ) ) {

      return true;
    }
    return false;
  }

  public void dispose( StepMetaInterface smi, StepDataInterface sdi ) {
    meta = (RssOutputMeta) smi;
    data = (RssOutputData) sdi;
    if ( data.document != null ) {
      data.document = null;
    }
    if ( data.rssElement != null ) {
      data.rssElement = null;
    }
    if ( data.channel != null ) {
      data.channel = null;
    }
    setOutputDone();
    super.dispose( smi, sdi );
  }

}
