/*******************************************************************************
 *  Imixs Workflow Technology
 *  Copyright (C) 2001, 2008 Imixs Software Solutions GmbH,  
 *  http://www.imixs.com
 *  
 *  This program is free software; you can redistribute it and/or 
 *  modify it under the terms of the GNU General Public License 
 *  as published by the Free Software Foundation; either version 2 
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 *  General Public License for more details.
 *  
 *  You can receive a copy of the GNU General Public
 *  License at http://www.gnu.org/licenses/gpl.html
 *  
 *  Contributors:  
 *  	Imixs Software Solutions GmbH - initial API and implementation
 *  	Ralph Soika
 *******************************************************************************/
package com.alexanderlogistics.datev;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.ejb.EJB;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPSClient;
import org.imixs.workflow.FileData;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.ModelService;
import org.imixs.workflow.engine.ReportService;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.engine.scheduler.Scheduler;
import org.imixs.workflow.engine.scheduler.SchedulerException;
import org.imixs.workflow.engine.scheduler.SchedulerService;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.QueryException;

/**
 * The CargosoftExportScheduler exportiert eine csv Datei auf eine FTP Laufwerk
 * mit allen noch offenen Rechnungen. Diese Datei wird von Cargosoft dann
 * verwendet um den Kreditramen für einen kunden zu ermitteln. Es werden
 * praktisch von Cargosoft nur die offenen Salen aus unserer CSV Datei pro
 * Kreditor ermittelt. (Wir könnten sozusagen auch direkt das ergeniss liefern,
 * aber so ist die aktuelel Carhosoft Schnittstelle implementiert).
 * <p>
 * The class implements the interface
 * _org.imixs.workflow.engine.scheduler.Scheduler_ and can be used in
 * combination with the Imxis-Workflow Scheduler Service.
 * 
 * @see SchedulerService
 * @author rsoika
 * 
 */
public class CargosoftExportScheduler implements Scheduler {

    public static final int MAX_COUNT = 999;
    public static final String FTP_ERROR = "FTP_ERROR";

    public static DateFormat dateFormat = new SimpleDateFormat("ddMMyyyy");
    public static DecimalFormat decimalFormat = new DecimalFormat("0.00",
            new DecimalFormatSymbols(java.util.Locale.GERMANY));
    public static DecimalFormat rateFormat = new DecimalFormat("0.000000",
            new DecimalFormatSymbols(java.util.Locale.GERMANY));

    @EJB
    DocumentService documentService;

    @EJB
    WorkflowService workflowService;

    @EJB
    ModelService modelService;

    @EJB
    ReportService reportService;

    private static Logger logger = Logger.getLogger(CargosoftExportScheduler.class.getName());

    /**
     * This is the method which processes the timeout event depending on the running
     * timer settings.
     * 
     * 
     * 
     * @param timer
     * @throws QueryException
     */
    public ItemCollection run(ItemCollection configuration) throws SchedulerException {
        List<ItemCollection> invoices = null;
        StringBuffer buffer = new StringBuffer();
        int lines = 0;

        configuration.removeItem("_scheduler_logmessage");
        logMessage(configuration, "....export to Cargosoft...");
        // $taskID<5900
        String sQuery = "(type:workitem AND $modelversion:rechnungsausgang* AND $taskid:[5000 TO 5899])";

        try {
            // find the textblock...
            invoices = documentService.find(sQuery, 9999, 0);
        } catch (QueryException e) {
            logMessage(configuration, "failed to search invoices by query: " + e.getMessage());
        }

        if (invoices != null && invoices.size() > 0) {
            // File csvOutputFile = new File(CSV_FILE_NAME);
            for (ItemCollection doc : invoices) {
                String line = "";
                line = line + doc.getItemValueString("dbtr.number") + ";";
                line = line + "\"" + doc.getItemValueString("dbtr.name") + "\";";
                line = line + "\"" + doc.getItemValueString("invoice.number") + "\";";
                line = line + dateFormat.format(doc.getItemValueDate("invoice.date")) + ";";
                line = line + dateFormat.format(doc.getItemValueDate("invoice.duedate")) + ";";

                // Betrag soll; Betrag Haben;
                double betrag = doc.getItemValueDouble("invoice.total");
                if (betrag >= 0) {
                    // Soll
                    line = line + decimalFormat.format(betrag) + ";0,00;";
                } else {
                    // Haben
                    line = line + "0,00;" + decimalFormat.format(Math.abs(betrag)) + ";";

                }
                // Saldo; S/H Saldo
                betrag = doc.getItemValueDouble("invoice.saldo");

                // convert to hauswahrung
                double rate = doc.getItemValueDouble("invoice.rate");
                double hausWaehrung = betrag;
                if (rate != 0.0) {
                    hausWaehrung = betrag / rate;
                }

                if (hausWaehrung >= 0) {
                    // Soll
                    line = line + decimalFormat.format(hausWaehrung) + ";S;";
                } else {
                    // Haben
                    line = line + decimalFormat.format(Math.abs(hausWaehrung)) + ";H;";
                }

                // WKZ
                String wkz = doc.getItemValueString("invoice.currency");
                if (!"EUR".equals(wkz)) {
                    line = line + //
                            wkz + ";" + //
                            decimalFormat.format(doc.getItemValueDouble("invoice.base.amount")) + ";" + //
                            rateFormat.format(doc.getItemValueDouble("invoice.rate")) + ";";
                } else {
                    line = line + ";0,00;0,000000;";
                }
                line = line + ";;;;;;" + doc.getItemValueString("invoice.text");
                // auffüllen mit 77 mal ';'
                int i = 69;
                while (i > 0) {
                    line = line + ";";
                    i--;
                }
                buffer.append(line + "\n");
                lines++;
            }

        }

        // transfer file via FTP...
        DateFormat formatter = new SimpleDateFormat("yyyyMMddHHmm");
        // MMM d, yyyy HH:mm a
        FileData fileData = new FileData("OPD_" + formatter.format(new Date()) + ".txt",
                String.valueOf(buffer).getBytes(), null, null);

        put(configuration, fileData);

        logMessage(configuration, "...Export completed: " + lines + " lines");
        return configuration;
    }

    private void logMessage(ItemCollection configuration, String message) {
        configuration.appendItemValue("_scheduler_logmessage", message);
        logger.info(message);
    }

    /**
     * Diese Hilfsmehtode überträgt eine Datei an einen FTP Server. Die
     * Verbindugnsdaten stehen im Configuraiton Workitem.
     * 
     * @param fileData object
     * @throws PluginException
     */
    public void put(ItemCollection configuration, FileData fileData) {

        String ftpServer = configuration.getItemValueString("_datev_ftp_host");
        String ftpUser = configuration.getItemValueString("_datev_ftp_userid");
        String ftpPassword = configuration.getItemValueString("_datev_ftp_password");
        String ftpWorkingPath = configuration.getItemValueString("_datev_ftp_path_buchungsstapel");
        int ftpPort = configuration.getItemValueInteger("_datev_ftp_port");
        if (ftpPort <= 0) {
            // set default port
            ftpPort = 21;
        }

        String fileName = fileData.getName();

        // Compute file path
        if (!ftpWorkingPath.startsWith("/")) {
            ftpWorkingPath = "/" + ftpWorkingPath;
        }
        if (!ftpWorkingPath.endsWith("/")) {
            ftpWorkingPath = ftpWorkingPath + "/";
        }
        InputStream writer = null;

        FTPClient ftpClient = null;
        try {
            logMessage(configuration, "......put " + fileName + " to FTP server: " + ftpServer + "...");
            ftpClient = new FTPSClient("TLS", false);
            ftpClient.setBufferSize(8192);
            ftpClient.connect(ftpServer, ftpPort);
            if (ftpClient.login(ftpUser, ftpPassword) == false) {
                logMessage(configuration, "FTP file transfer failed: login failed!");
            }
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
            ftpClient.setControlEncoding("UTF-8");

            // verify directories
            if (!ftpClient.changeWorkingDirectory(ftpWorkingPath)) {
                logMessage(configuration, "FTP file transfer failed: missing working directory '" + ftpWorkingPath
                        + "' : " + ftpClient.getReplyString());
            }

            // upload file to FTP server.
            writer = new ByteArrayInputStream(fileData.getContent());

            if (!ftpClient.storeFile(fileName, writer)) {
                logMessage(configuration, "FTP file transfer failed: unable to write '" + ftpWorkingPath + fileName
                        + "' : " + ftpClient.getReplyString());
            }

            logMessage(configuration, "...." + ftpWorkingPath + fileName + " transfered successfull to " + ftpServer);

        } catch (IOException e) {
            logMessage(configuration, "FTP file transfer failed: " + e.getMessage());
        } finally {
            // do logout....
            try {
                if (writer != null) {
                    writer.close();
                }
                ftpClient.logout();
                ftpClient.disconnect();
            } catch (IOException e) {
                logMessage(configuration, "FTP file transfer failed: " + e.getMessage());
            }
        }
    }

}
