package sos.scheduler.ftp;

import java.io.File;
import java.util.Iterator;
import java.util.Vector;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import sos.net.SOSFTP;
import sos.net.SOSFTPS;
import sos.net.SOSFileTransfer;
import sos.net.SOSMail;
import sos.net.SOSSFTP;
import sos.scheduler.job.JobSchedulerJob;
import sos.spooler.Order;
import sos.spooler.Variable_set;
import sos.util.SOSFile;
import sos.util.SOSFileOperations;
import sos.util.SOSGZip;
import sos.util.SOSSchedulerLogger;
import sos.util.SOSString;

/**
 * FTP File Transfer
 *
 @author Andreas P�schel
 @author M�r�vet �ks�z
 */

public class JobSchedulerFTPSend extends JobSchedulerJob {

    /** The FTP server will always reply the ftp error codes,
     * see http://www.the-eggman.com/seminars/ftp_error_codes.html */
  public  static final int ERROR_CODE = 300;

  private SOSFileTransfer ftpClient        = null;

  private String          lastHost         = "";

  private int             lastPort         = 0;

  private String          lastUser         = "";

  private String          lastAccount      = "";

  private SOSString       sosString        = new SOSString();


  public boolean spooler_process() {

    String      protocol                        = "ftp";
    boolean     sshBasedProtocol                = false;

        boolean     rc                              = false;

    String      host                            = "";
    int         port                            = 21;

    String      user                            = "anonymous";
    String      password                        = "";
    String      account                         = "";

    String      transferMode                    = "binary";
    boolean     passiveMode                     = false;

    String      remoteDir                       = "./";
    String      localDir                        = ".";
    String      fileSpec                        = ".*";

        String       atomicSuffix                   = "";
        boolean      checkSize                      = true;
        boolean      overwriteFiles                 = true;
        boolean      appendFiles                    = false;
        boolean      removeFiles                    = false;
        boolean      makeDirs                       = false;
        boolean      forceFiles                     = true;
        boolean      compressFiles                  = false;
        String       compressedFileExtension        = "";

        boolean      zeroByteFiles                  = true;
        boolean      zeroByteFilesStrict            = false;
        boolean      zeroByteFilesRelaxed           = false;

        String       fileNotificationTo             = "";
        String       fileNotificationCC             = "";
        String       fileNotificationBCC            = "";
        String       fileNotificationSubject        = "";
        String       fileNotificationBody           = "";

        String       fileZeroByteNotificationTo     = "";
        String       fileZeroByteNotificationCC     = "";
        String       fileZeroByteNotificationBCC    = "";
        String       fileZeroByteNotificationSubject= "";
        String       fileZeroByteNotificationBody   = "";

    boolean      isLoggedIn                     = false;
    Variable_set params                         = null;

    boolean      keepConnection                 = false;
    boolean      sameConnection                 = false;

        int          count                          = 0;
        int          zeroByteCount                  = 0;

        String       replacing                      = null;
    String       replacement                    = null;

    boolean      recursive                      = false;
    String       filePath                       = "";
    boolean      isFilePath                     = false;

    // alternative Parameter
    String      alternativeHost                 = "";
    int         alternativePort                 = 0;
    String      alternativeUser                 = "";
    String      alternativePassword             = "";
    String      alternativeAccount              = "";
    String      alternativeRemoteDir            = "";
    boolean     alternativePassiveMode          = false;
    String      alternativeTransferMode         = "";

    // Parallel File Transfer
    boolean      parallelTransfer                = false;
        String       parallelTransferCheckSetback    = "00:00:60";
        int          parallelTransferCheckRetry      = 60;

    // Hilfsvariable: wenn gesetzt, dann handelt es sich um einen Wiederholungsauftrag. Also keine Dateien abfrufen
    boolean      checkParallel              = false;
    boolean      orderSelfDestruct          = false;

    // Variablen f�r ssh-basierte Transferprotokolle
      /** optional proxy configuration */
      String proxyHost                  = "";
      int proxyPort                     = 0;
      String proxyUser                  = "";
      String proxyPassword              = "";
      /** authentication method: publickey, password */
      String authenticationMethod       = "publickey";
      /** key file: ~/.ssh/id_rsa or ~/.ssh/id_dsa */
      String authenticationFilename     = "";


    try {
      this.setLogger(new SOSSchedulerLogger(spooler_log));

      try // to get the job parameters and order parameters
        params = spooler.create_variable_set();
        if (spooler_task.params() != nullparams.merge(spooler_task.params());
        if (spooler_job.order_queue() != null && spooler_task.order().params() != nullparams.merge(spooler_task.order().params());

        if (params.var("ftp_keep_connection"!= null && params.var("ftp_keep_connection").length() 0) {
          String keep = params.var("ftp_keep_connection");
          if (keep.equalsIgnoreCase("true"|| keep.equalsIgnoreCase("1")) {
            keepConnection=true;
          else {
            keepConnection= false;
          }
        else {
          keepConnection=false;
        }

        if (params.var("ftp_protocol"!= null && params.var("ftp_protocol").length() 0)
          protocol = params.var("ftp_protocol");
        if (protocol.equalsIgnoreCase("sftp")){
          sshBasedProtocol = true;
          //use other defaults
          port = 22;
        }

        if (params.var("ftp_host"!= null && params.var("ftp_host").length() 0)
          host = params.var("ftp_host");

        if (params.var("ftp_port"!= null && params.var("ftp_port").length() 0)
          port = Integer.parseInt(params.var("ftp_port"));

        if (params.var("ftp_user"!= null && params.var("ftp_user").length() 0)
          user = params.var("ftp_user");

        if (params.var("ftp_password"!= null && params.var("ftp_password").length() 0)
          password = params.var("ftp_password");

        if (params.var("ftp_account"!= null && params.var("ftp_account").length() 0)
          account = params.var("ftp_account");

        if (keepConnection){
          sameConnection = ftpClient!=null && ftpClient.isConnected() && lastHost.equalsIgnoreCase(host)
          && lastPort==port && lastUser.equalsIgnoreCase(user&& lastAccount.equalsIgnoreCase(account);
        }
        if (ftpClient!=null && ftpClient.isConnected() && !sameConnection) {
          try{
            if (isLoggedInftpClient.logout();
            ftpClient.disconnect();
          catch (Exception e){}
        }

        lastHost = host;
        lastPort = port;
        lastUser = user;
        lastAccount = account;


        if (params.var("ftp_transfer_mode"!= null && params.var("ftp_transfer_mode").length() 0)
          transferMode = params.var("ftp_transfer_mode");

        if (params.var("ftp_passive_mode"!= null && params.var("ftp_passive_mode").length() 0)
          passiveMode = (params.var("ftp_passive_mode").equals("1"true false);

        if (params.var("ftp_remote_dir"!= null && params.var("ftp_remote_dir").length() 0)
          remoteDir = params.var("ftp_remote_dir");

        if (params.var("ftp_local_dir"!= null && params.var("ftp_local_dir").length() 0)
          localDir = params.var("ftp_local_dir");

        if (params.var("ftp_file_spec"!= null && params.var("ftp_file_spec").length() 0)
          fileSpec = params.var("ftp_file_spec");

        if (params.var("ftp_atomic_suffix"!= null && params.var("ftp_atomic_suffix").length() 0)
          atomicSuffix = params.var("ftp_atomic_suffix");

        if (params.var("ftp_check_size"!= null && params.var("ftp_check_size").length() 0)
          checkSize = (!params.var("ftp_check_size").equals("1")
              && !params.var("ftp_check_size").equalsIgnoreCase("true")
              && !params.var("ftp_check_size").equalsIgnoreCase("yes"false true);

        if (params.var("ftp_overwrite_files"!= null && params.var("ftp_overwrite_files").length() 0)
          overwriteFiles = (!params.var("ftp_overwrite_files").equals("1")
              && !params.var("ftp_overwrite_files").equalsIgnoreCase("true")
              && !params.var("ftp_overwrite_files").equalsIgnoreCase("yes"false true);

        if (params.var("ftp_append_files"!= null && params.var("ftp_append_files").length() 0)
          appendFiles = (params.var("ftp_append_files").equals("1")
              || params.var("ftp_append_files").equalsIgnoreCase("true")
              || params.var("ftp_append_files").equalsIgnoreCase("yes"true false);

        if (params.var("ftp_remove_files"!= null && params.var("ftp_remove_files").length() 0)
          removeFiles = (params.var("ftp_remove_files").equals("1")
              || params.var("ftp_remove_files").equalsIgnoreCase("true")
              || params.var("ftp_remove_files").equalsIgnoreCase("yes"true false);

        if (params.var("ftp_make_dirs"!= null && params.var("ftp_make_dirs").length() 0)
          makeDirs = (params.var("ftp_make_dirs").equals("1")
              || params.var("ftp_make_dirs").equalsIgnoreCase("true")
              || params.var("ftp_make_dirs").equalsIgnoreCase("yes"true false);

        if (params.var("ftp_force_files"!= null && params.var("ftp_force_files").length() 0)
          forceFiles = (!params.var("ftp_force_files").equals("1")
              && !params.var("ftp_force_files").equalsIgnoreCase("true")
              && !params.var("ftp_force_files").equalsIgnoreCase("yes"false true);

        if (params.var("ftp_compress_files"!= null && params.var("ftp_compress_files").length() 0)
          compressFiles = (params.var("ftp_compress_files").equals("1")
              || params.var("ftp_compress_files").equalsIgnoreCase("true")
              || params.var("ftp_compress_files").equalsIgnoreCase("yes"true false);

        if (params.var("ftp_compressed_file_extension"!= null && params.var("ftp_compressed_file_extension").length() 0) {
          compressedFileExtension = params.var("ftp_compressed_file_extension");
        else {
          compressedFileExtension = ".gz";
        }


        if (params.var("ftp_file_zero_byte_transfer"!= null && params.var("ftp_file_zero_byte_transfer").length() 0) {
          if (params.var("ftp_file_zero_byte_transfer").equals("1")
              || params.var("ftp_file_zero_byte_transfer").equalsIgnoreCase("true")
              || params.var("ftp_file_zero_byte_transfer").equalsIgnoreCase("yes")) {
            zeroByteFiles = true;
            zeroByteFilesStrict = false;
          else if (params.var("ftp_file_zero_byte_transfer").equalsIgnoreCase("strict")) {
            zeroByteFiles = false;
            zeroByteFilesStrict = true;
          else if (params.var("ftp_file_zero_byte_transfer").equalsIgnoreCase("relaxed")) {
            zeroByteFiles = false;
            zeroByteFilesStrict = false;
            zeroByteFilesRelaxed = true;
          else {
            zeroByteFiles = false;
            zeroByteFilesStrict = false;
          }
        }

        if (params.var("ftp_file_notification_to"!= null && params.var("ftp_file_notification_to").length() 0) {
          fileNotificationTo = params.var("ftp_file_notification_to");
        }

        if (params.var("ftp_file_notification_cc"!= null && params.var("ftp_file_notification_cc").length() 0) {
          fileNotificationCC = params.var("ftp_file_notification_cc");
        }

        if (params.var("ftp_file_notification_bcc"!= null && params.var("ftp_file_notification_bcc").length() 0) {
          fileNotificationBCC = params.var("ftp_file_notification_bcc");
        }

        if (params.var("ftp_file_notification_subject"!= null && params.var("ftp_file_notification_subject").length() 0) {
          fileNotificationSubject = params.var("ftp_file_notification_subject");
        }

        if (params.var("ftp_file_notification_body"!= null && params.var("ftp_file_notification_body").length() 0) {
          fileNotificationBody = params.var("ftp_file_notification_body");
        }


        if (params.var("ftp_file_zero_byte_notification_to"!= null && params.var("ftp_file_zero_byte_notification_to").length() 0) {
          fileZeroByteNotificationTo = params.var("ftp_file_zero_byte_notification_to");
        }

        if (params.var("ftp_file_zero_byte_notification_cc"!= null && params.var("ftp_file_zero_byte_notification_cc").length() 0) {
          fileZeroByteNotificationCC = params.var("ftp_file_zero_byte_notification_cc");
        }

        if (params.var("ftp_file_zero_byte_notification_bcc"!= null && params.var("ftp_file_zero_byte_notification_bcc").length() 0) {
          fileZeroByteNotificationBCC = params.var("ftp_file_zero_byte_notification_bcc");
        }

        if (params.var("ftp_file_zero_byte_notification_subject"!= null && params.var("ftp_file_zero_byte_notification_subject").length() 0) {
          fileZeroByteNotificationSubject = params.var("ftp_file_zero_byte_notification_subject");
        }

        if (params.var("ftp_file_zero_byte_notification_body"!= null && params.var("ftp_file_zero_byte_notification_body").length() 0) {
          fileZeroByteNotificationBody = params.var("ftp_file_zero_byte_notification_body");
        }

        if params.value("replacing")!=null && params.value("replacing").length()>) {
          replacing = params.value("replacing");
        }

        if params.value("replacement")!=null && params.value("replacement").length()>) {
          replacement = params.value("replacement");
        }


        if params.value("ftp_recursive")!=null && params.value("ftp_recursive").length()>) {
          String sRecursive = "";
          sRecursive = params.value("ftp_recursive");
          recursive = sosString.parseToBoolean(sRecursive);
        }

        if replacing != null && replacement == null ) {
          throw new Exception("job parameter is missing for specified parameter [replacing]: [replacement]");
        }

        if replacing == null && replacement != null ) {
          throw new Exception("job parameter is missing for specified parameter [replacement]: [replacing]");
        }


        if (appendFiles && compressFiles) {
          throw new Exception("unsupported parameter settings [ftp_append_files, ftp_compress_files]: cannot append to compressed files");
        }

        if (params.var("ftp_file_path"!= null && params.var("ftp_file_path").length() 0) {
          filePath = params.var("ftp_file_path");
          isFilePath = true;
        }

        // alternative parameters
        if (params.var("ftp_alternative_host"!= null && params.var("ftp_alternative_host").length() 0)
          alternativeHost = params.var("ftp_alternative_host");

        if (params.var("ftp_alternative_port"!= null && params.var("ftp_alternative_port").length() 0)
          alternativePort = Integer.parseInt(params.var("ftp_alternative_port"));

        if (params.var("ftp_alternative_password"!= null && params.var("ftp_alternative_password").length() 0)
          alternativePassword = params.var("ftp_alternative_password");

        if (params.var("ftp_alternative_user"!= null && params.var("ftp_alternative_user").length() 0)
          alternativeUser = params.var("ftp_alternative_user");

        if (params.var("ftp_alternative_account"!= null && params.var("ftp_alternative_account").length() 0)
          alternativeAccount = params.var("ftp_alternative_account");

        if (params.var("ftp_alternative_remote_dir"!= null && params.var("ftp_alternative_remote_dir").length() 0)
          alternativeRemoteDir = params.var("ftp_alternative_remote_dir");

        if (params.var("ftp_alternative_passive_mode"!= null && params.var("ftp_alternative_passive_mode").length() 0)
          alternativePassiveMode = (params.var("ftp_alternative_passive_mode").equals("1"true false);

        if (params.var("ftp_alternative_transfer_mode"!= null && params.var("ftp_alternative_transfer_mode").length() 0)
          alternativeTransferMode = params.var("ftp_alternative_transfer_mode");

        if (params.var("ftp_parallel"!= null && params.var("ftp_parallel").length() 0)
          parallelTransfer = sosString.parseToBoolean(sosString.parseToString(params.var("ftp_parallel")));

                if (params.var("ftp_parallel_check_setback"!= null && params.var("ftp_parallel_check_setback").length() 0)
                    parallelTransferCheckSetback = params.var("ftp_parallel_check_setback");

                if (params.var("ftp_parallel_check_retry"!= null && params.var("ftp_parallel_check_retry").length() 0) {
                    try {
                        parallelTransferCheckRetry = Integer.parseInt(params.var("ftp_parallel_check_retry"));
                    catch (Exception e) {
                        throw new Exception("illegal value for parameter [ftp_parallel_check_retry]: " + params.var("ftp_parallel_check_retry"));
                    }
                }

                // implicit parameters
                if(params.var("ftp_check_parallel"!= null && params.var("ftp_check_parallel").length() 0)
          checkParallel = sosString.parseToBoolean(sosString.parseToString(params.var("ftp_check_parallel")));

        if(params.var("ftp_order_self_destruct"!= null && params.var("ftp_order_self_destruct").length() 0)
          orderSelfDestruct = sosString.parseToBoolean(sosString.parseToString(params.var("ftp_order_self_destruct")));

        if (sshBasedProtocol){
          // parameters for ssh-based protocols
          if (params.value("ssh_proxy_host"!= null && params.value("ssh_proxy_host").toString().length() 0) {
            proxyHost=params.value("ssh_proxy_host");
          }

          if (params.value("ssh_proxy_port"!= null && params.value("ssh_proxy_port").length() 0) {
            try {
              proxyPort=(Integer.parseInt(params.value("ssh_proxy_port")));
            catch (Exception ex) {
              throw new Exception("illegal non-numeric value for parameter [ssh_proxy_port]: " + params.value("ssh_proxy_port"));
            }
          else {
            proxyPort=3128;
          }

          if (params.value("ssh_proxy_user"!= null && params.value("ssh_proxy_user").length() 0) {
            proxyUser=(params.value("ssh_proxy_user"));
          }

          if (params.value("ssh_proxy_password"!= null && params.value("ssh_proxy_password").length() 0) {
            proxyPassword=(params.value("ssh_proxy_password"));
          }

          if (params.value("ssh_auth_method"!= null && params.value("ssh_auth_method").length() 0) {
            if (params.value("ssh_auth_method").equalsIgnoreCase("publickey"|| params.value("ssh_auth_method").equalsIgnoreCase("password")) {
              authenticationMethod=(params.value("ssh_auth_method"));
            else {
              throw new Exception("invalid authentication method [publickey, password] specified: " + params.value("ssh_auth_method"));
            }
          else {
            authenticationMethod=("publickey");
          }

          if (params.value("ssh_auth_file"!= null && params.value("ssh_auth_file").length() 0) {
            authenticationFilename=(params.value("ssh_auth_file"));
          else {
            if (authenticationMethod.equalsIgnoreCase("publickey"))
              throw new Exception("no authentication filename was specified as parameter [ssh_auth_file]");