package com.fp.bpmlib.ejb;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;

import org.kie.api.io.ResourceType;
import org.kie.api.runtime.EnvironmentName;
import org.kie.api.runtime.manager.RuntimeEnvironment;
import org.kie.api.runtime.manager.RuntimeEnvironmentBuilder;
import org.kie.api.runtime.manager.RuntimeManager;
import org.kie.api.runtime.manager.RuntimeManagerFactory;
import org.kie.internal.io.ResourceFactory;

import com.fp.bpmlib.ejb.local.JbpmBeanLocal;
import com.fp.bpmlib.task.util.MaiaUserGroupCallback;
import com.fp.common.logger.APPLogger;
import com.fp.persistence.commondb.PersistenceHelper;
import com.fp.persistence.commondb.PersistenceManager;
import com.fp.persistence.pbpm.gene.TbpmRules;

/**
 * Clase utilitaria, utilizada para creacion de base de conocimento y RuntimeManager
 * 
 * @author Jvc
 * @version 2.1
 */
@Startup
@Singleton(name = "jbpmbean")
public class JbpmBean implements JbpmBeanLocal {
    @PersistenceUnit(unitName = "org.jbpm.domain")
    private EntityManagerFactory emf;

    private RuntimeManager runtimemanager;

    @PostConstruct
    private final void crearSingletonManager() {
        try {
            if (emf == null) {
                emf = PersistenceManager.getInstance().getEntityManagerFactoryAuxiliar("org.jbpm.domain");
            }
        } catch (Exception e) {
            APPLogger.getLogger().error(e);
        }
    }

    @PreDestroy
    private void close() {
        try {
            runtimemanager.close();
        } catch (Exception e) {
            // no hacer nada.
        }

    }

    /**
     * Crea un RuntimeManagerFactory.
     * 
     * @param emf Entiy manager factury utilizado en el manejo de flujos de trabajo.
     * @return RuntimeEnvironment
     * @throws Exception
     */
    private RuntimeEnvironment crearRuntimeManager(EntityManagerFactory emf) throws Exception {

        MaiaUserGroupCallback usergroupCallback = new MaiaUserGroupCallback();
        RuntimeEnvironmentBuilder builder = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder().entityManagerFactory(emf);
        builder.userGroupCallback(usergroupCallback);

        this.adicionarFlujos(builder);

        RuntimeEnvironment environment = builder.get();
        environment.getEnvironment().set(EnvironmentName.USE_PESSIMISTIC_LOCKING, true);

        return environment;
    }

    @Override
    public RuntimeManager getRuntimeManager() throws Exception {

        if (runtimemanager == null) {
            RuntimeEnvironment environment = this.crearRuntimeManager(emf);
            runtimemanager = RuntimeManagerFactory.Factory.get().newPerRequestRuntimeManager(environment);
        }
        return runtimemanager;
    }

    /**
     * Adiciona definiciones de flujos a un map con los cuales se crea la base de conocimiento.
     * 
     * @param resources Map que contiene definicion de flujos y reglas con los cuales se crea la base de conocimiento.
     * @throws Exception
     */
    private void adicionarFlujos(RuntimeEnvironmentBuilder builder) throws Exception {

        List<TbpmRules> ldata = TbpmRules.findRules(PersistenceHelper.getEntityManager());

        // adiciona subprocesos.
        for (TbpmRules obj : ldata) {
            if (obj.getFiletype().equals("F")) {
                builder.addAsset(ResourceFactory.newClassPathResource(obj.getPath(), "UTF-8"), ResourceType.BPMN2);
            } else {
                builder.addAsset(ResourceFactory.newClassPathResource(obj.getPath(), "UTF-8"), ResourceType.DTABLE);
            }
        }
    }

    /**
     * Entrega el entitymanagerfactory asociado al manejo de jbpm.
     * 
     * @return
     */
    @Override
    public EntityManagerFactory getEmf() {
        return emf;
    }

}