package com.alexanderlogistics;

import java.util.List;
import java.util.logging.Logger;

import javax.inject.Inject;

import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.SignalAdapter;
import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.AccessDeniedException;
import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.exceptions.ProcessingErrorException;
import org.imixs.workflow.exceptions.QueryException;

/**
 * Der ZahlungsavisAdapter verknüpft eine Rechnung mit einem Zahlungsavsis zum
 * aktuellen Kreiditor. Existiert aktuell kein offener Zahlungsavis für diesen
 * Kredito erzeugt der Adapter automatisch eine neue Prozessinstanz.
 * <p>
 * Wurde die Rechnugn bereits einem Zahlungsavis zugeordnet passiert nichts.
 * 
 * 
 * 
 * @version 1.0
 * @author rsoika
 */
public class ZahlungsavisAppendAdapter implements SignalAdapter {

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

    public static final String ERROR_MISSING_DATA = "MISSING_DATA";
    public static final String ERROR_CONFIG = "CONFIG_ERROR";

    public static final String ITEM_CDTR_NUMBER = "cdtr.number";
    public static final String ITEM_CDTR_NAME = "cdtr.name";
    public static final String ITEM_CDTR_NAME_CARGOSOFT = "cdtr.name.cargosoft";

    @Inject
    WorkflowService workflowService;

    /**
     * This method finds or create the Zahlungsavis and adds a reference
     * ($workitemref) to the current invoice.
     * 
     * @throws PluginException
     */
    @Override
    public ItemCollection execute(ItemCollection document, ItemCollection event)
            throws AdapterException, PluginException {

        appendInvoice(document);

        return document;
    }

    /**
     * Diese method hängt eine referenz der aktuellen Rechnung an den Zahlungsavis
     * 
     * @param document
     * @throws PluginException
     */
    private void appendInvoice(ItemCollection document) throws PluginException {
        String cdtrNumber = document.getItemValueString(ITEM_CDTR_NUMBER);
        String currency = document.getItemValueString("invoice.currency");

        if (cdtrNumber == null || cdtrNumber.isEmpty()) {
            throw new PluginException(PluginException.class.getName(), ERROR_MISSING_DATA,
                    "Zahlungsavis kann nicht erzeugt werden. Bitte wählen Sie zuerst einen Kreditor aus.");
        }
        
        
        logger.info("......Search Zahlungsavis or creditor '" + cdtrNumber + "'...");
        ItemCollection zahlungsAvis;
        try {
            zahlungsAvis = findZahlungsavis(cdtrNumber,currency);
            if (zahlungsAvis == null) {
                // create a new one
                zahlungsAvis = new ItemCollection().workflowGroup("Zahlungsavis").task(1000).event(100);
                // add cdtr.name
                zahlungsAvis.setItemValue(ITEM_CDTR_NAME, document.getItemValue(ITEM_CDTR_NAME));
                zahlungsAvis.setItemValue(ITEM_CDTR_NUMBER, document.getItemValue(ITEM_CDTR_NUMBER));
                zahlungsAvis.setItemValue(ITEM_CDTR_NAME_CARGOSOFT, document.getItemValue(ITEM_CDTR_NAME_CARGOSOFT));
                zahlungsAvis.setItemValue("invoice.currency", currency);
            } else {
                // zahlungsavis speichern
                zahlungsAvis.event(100);
            }
            // Invoice mit zahlungsavis verknüpften (falls noch nicht verknüpft)
            zahlungsAvis.appendItemValueUnique("$workitemref", document.getUniqueID());
            workflowService.processWorkItem(zahlungsAvis);

        } catch (QueryException | AccessDeniedException | ProcessingErrorException | ModelException e1) {
            throw new PluginException(PluginException.class.getName(), ERROR_MISSING_DATA,
                    "Es konnte kein Zahlungsavis zugewiesen werden: " + e1.getMessage());

        }
    }

    /**
     * Prüft alle offenen Zahlugnsaviss und gibt den neuesten zur angegebenen
     * cdrNumber zurück, oder null falls es keinen Offenen Zahlungsavis gibt.
     * 
     * @param cdrNumber
     * @return
     * @throws QueryException
     */
    private ItemCollection findZahlungsavis(String cdtrNumber,String currency) throws QueryException {
        String query = "(type:workitem) AND ($modelversion:zahlungsavis*) ";
        List<ItemCollection> resultList = workflowService.getDocumentService().find(query, 999, 0, "$modified", true);

        for (ItemCollection zahlungsavis : resultList) {
            if (cdtrNumber.equals(zahlungsavis.getItemValueString(ITEM_CDTR_NUMBER))
             && currency.equals(zahlungsavis.getItemValueString("invoice.currency")) 		
            		) {
                return zahlungsavis;
            }
        }

        // no zahlungsavis found
        return null;
    }

}