package com.fp.bpmlib;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.naming.InitialContext;

import org.jbpm.process.instance.event.listeners.TriggerRulesEventListener;
import org.jbpm.services.task.lifecycle.listeners.BAMTaskEventListener;
import org.jbpm.services.task.lifecycle.listeners.TaskLifeCycleEventListener;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.manager.RuntimeEngine;
import org.kie.api.runtime.manager.RuntimeManager;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.api.task.TaskService;
import org.kie.internal.task.api.EventService;

import com.fp.base.persistence.util.helper.MessageManager;
import com.fp.bpmlib.ejb.local.JbpmBeanLocal;
import com.fp.bpmlib.task.MaiaWorkItemHandler;
import com.fp.common.logger.APPLogger;
import com.fp.dto.Request;
import com.fp.dto.save.SaveRequest;
import com.fp.simple.flow.DataMap;

/**
 * Class encargada del inicio de un flujo de trabajo.
 * 
 * @author jvaca
 * @version 2.1
 */
public class Flujo {

    private KieSession kiesession;
    private ProcessInstance processInstance = null;
    private TaskService taskService;
    /**
     * Crea una instancia de flujo.
     */
    public Flujo() throws Exception{
        JbpmBeanLocal local = (JbpmBeanLocal) new InitialContext().lookup("java:global/maiaear-2.1/bpmlib/jbpmbean");
        RuntimeManager manager = local.getRuntimeManager();
        RuntimeEngine runtime = manager.getRuntimeEngine(null);
        taskService = runtime.getTaskService();
        kiesession = runtime.getKieSession();
        kiesession.addEventListener(new TriggerRulesEventListener(kiesession));
        kiesession.getWorkItemManager().registerWorkItemHandler("Human Task", new MaiaWorkItemHandler());
        this.addListeners(runtime);
    }

    /**
     * Crea una instancia de flujo y obtiene una instancia del proceso.
     * @param processid Id de una instancia de proceso.
     * @throws Exception
     */
    public Flujo(Long processid) throws Exception {
        this();
        processInstance = kiesession.getProcessInstance(processid);
    }

    /**
     * Adiciona listener, para el manejo del bam de tareas.
     * @param engine
     */
    @SuppressWarnings("unchecked")
    private void addListeners(RuntimeEngine engine) {
        EventService<TaskLifeCycleEventListener> eventService = (EventService<TaskLifeCycleEventListener>) engine.getTaskService();
        boolean hasBamEventListener = false;
        for (TaskLifeCycleEventListener listener : eventService.getTaskEventListeners()) {
            if (listener instanceof BAMTaskEventListener) {
                hasBamEventListener = true;
                break;
            }
        }
        if (!hasBamEventListener) {
            BAMTaskEventListener bamTaskEventListener = new BAMTaskEventListener();
            eventService.registerTaskEventListener(bamTaskEventListener);
        }
    }

    /**
     * Inicia la ejecucion de un flujo de trabajo.
     * @param flujo Id del flujo se toma del archivo.jbpm
     * @param parametros Parametros con los que inicia la ejeccion de un flujo.
     * @throws Exception
     */
    public Long iniciar(String idproceso, Request request) throws Exception {
        APPLogger.getLogger().info("Prepara Flujo");
        //Se crea un nuevo request para grabar en el bpm la minima informacion.
        SaveRequest sr = new SaveRequest();
        sr.setJsf(true);
        request.copy(sr);
        request.copyMapValuesWithOutSaveBean(sr);
        sr.mbeans.clear();
        sr.remove("MSAVE");
        sr.remove("MQUERY");
        sr.remove("lOrderPersistentBeans");
        sr.setResponse(null);


        Map<String, Object> m = new HashMap<String, Object>();
        m.put(ProcessUtil.TASKS_METADATA, new LinkedHashMap<String, Object>());
        Map<String, Object> data = new DataMap();
        // Map<String, Object> data = new HashMap<>();
        if ((sr.getSubject() == null) || (sr.getSubject().compareTo("") == 0)) {
            sr.setSubject(MessageManager.getMessage(request));
        }
        data.put(ProcessUtil.REQUEST, sr);
        m.put(ProcessUtil.DATA, data);

        processInstance = kiesession.startProcess(idproceso, m);

        APPLogger.getLogger().info("Flujo preparado");

        return processInstance.getId();
    }

    /**
     * Cierra la session de trabajo.
     */
    public void close() {
        // no cerrar la session, esta se cierra en el commit trabaja con JTA.
    }

    public KieSession getKiesession() {
        return kiesession;
    }

    public ProcessInstance getProcessInstance() {
        return processInstance;
    }




}