package com.fp.general.scheduler;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import com.fp.common.exception.CommonException;
import com.fp.common.exception.ExceptionHandler;
import com.fp.common.logger.APPLogger;
import com.fp.dto.rules.ScheduleRule;
import com.fp.dto.save.SaveRequest;
import com.fp.persistence.commondb.NestedSave;
import com.fp.persistence.commondb.PersistenceHelper;
import com.fp.persistence.commondb.PersistenceManager;
import com.fp.persistence.commondb.data.SessionData;
import com.fp.persistence.commondb.data.ThreadFacade;
import com.fp.persistence.commondb.helper.FormatDates;
import com.fp.persistence.pgeneral.date.TgeneAccountingDateBranch;
import com.fp.persistence.pgeneral.schedule.TgeneScheduleLog;
import com.fp.persistence.pgeneral.schedule.TgeneScheduleLogKey;
import com.fp.persistence.pgeneral.schedule.TgeneScheduleProcess;

/**
 * Clase que se encarga de ejecutar tareas calendarizadas, que se parametrizan en TgeneSchdeleEven.
 * 
 * @author Jorge Vaca
 * @version 2.1
 */
public class SchedulerJob implements Job {

    /*
     * (non-Javadoc)
     * 
     * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
     */
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        TgeneScheduleLog log = null;
        Integer cia = null;
        try {
            JobDataMap jdm = context.getJobDetail().getJobDataMap();
            String event = jdm.getString("evento");
            APPLogger.getLogger().error("INICIA EJECUCION DE TAREA " + event);
            // compania para obtener el entity manager
            SessionData s = new SessionData();
            cia = jdm.getInt("cia");
            s.setCompany(cia);

            ThreadFacade.setSaveRequest(s);
            PersistenceHelper.setEntityManager(PersistenceManager.getInstance().createEntityManagerLocal());
            PersistenceHelper.beginNewTransaction();
            // ejecuta la tarea calendarizada.
            TgeneScheduleProcess process = TgeneScheduleProcess.find(PersistenceHelper.getEntityManager(), event);
            SaveRequest saveRequest = this.fillSaveRequest(jdm, process);
            // Fija resultado de ejecucion de la tarea
            log = this.createTgeneScheduleLog(event, saveRequest);
            this.processByRule(process, jdm, saveRequest);
            PersistenceHelper.save(log);
            PersistenceHelper.commitNewTransaction();
        } catch (Exception e) {
            PersistenceHelper.rollbackNewTransaction();
            this.saveError(cia, e, log);
        } finally {
            PersistenceHelper.closeSession();
        }
    }

    /**
     * Metodo que se encarga de grabar el error que se genera en la ejecucion de la tarea calendarizada.
     * 
     * @param exception Excepcion que contiene el error presentado.
     * @throws Exception
     */
    private void saveError(Integer cia, Exception exeption, TgeneScheduleLog log) {
        try {
            ExceptionHandler eh = new ExceptionHandler(exeption, "es");
            if (eh.getCode().length() > 20) {
                log.setResultcode(eh.getCode().substring(0, 19));
            } else {
                log.setResultcode(eh.getCode());
            }
            if (eh.getUserMessage().length() > 399) {
                log.setResultmessage(eh.getUserMessage().substring(0, 399));
            } else {
                log.setResultmessage(eh.getUserMessage());
            }
            new NestedSave(cia, log);
        } catch (Exception e) {
            APPLogger.getLogger().error(e, e);
        }

    }

    /**
     * Crea una instancia de TgeneScheduleLog, que almacena el resultado de la tarea calendarizada.
     * 
     * @param pEvent codigo de evento de la tarea calendarizada.
     * @param saveRequest Objeto que contiene el request de entrada de ejecucion de la tarea.
     * @return TgeneScheduleLog
     * @throws Exception
     */
    private TgeneScheduleLog createTgeneScheduleLog(String pEvent, SaveRequest saveRequest) throws Exception {
        TgeneScheduleLogKey key = new TgeneScheduleLogKey();
        key.setEventcode(pEvent);
        key.setRealdate(FormatDates.getInstance().getDataBaseTimestamp());
        TgeneScheduleLog log = new TgeneScheduleLog(key);
        TgeneAccountingDateBranch date = com.fp.persistence.commondb.db.DataHelper.getInstance().getTgeneAccountingDateBranch(
                saveRequest.getCompany(), 0);
        log.setProcessdate(date.getAccountingdate());
        log.setUsercode(saveRequest.getUser());
        log.setResultcode("0");
        log.setResultmessage("TRANSACCION REALIZADA CORRECTAMENTE");
        return log;
    }

    /**
     * Metodo encargado de ejecutar reglas de procesos calendarizados.
     * 
     * @param pProcess Objeto que contiene la regla a ejecutar.
     * @throws Exception
     */
    private void processByRule(TgeneScheduleProcess pProcess, JobDataMap jdm, SaveRequest saveRequest) throws Exception {
        ScheduleRule rule = null;
        try {
            rule = (ScheduleRule) Class.forName(pProcess.getProcesscode()).newInstance();
        } catch (ClassNotFoundException e) {
            throw new CommonException("COMMON-0006", "REGLA {0} A EJECUTAR NO DEFINIDO MODULE: {1} TRANS: {2} VERSION {3}",
                    pProcess.getProcesscode(), e, saveRequest.getTransactionModule(), saveRequest.getTransactionCode(),
                    saveRequest.getTransactionVersion());
        } catch (ClassCastException e) {
            throw new CommonException("COMMON-0007", "REGLA {0} A EJECUTAR MODULE: {1} TRANS: {2} VERSION {3} NO IMPLEMENTA {4}", e,
                    pProcess.getProcesscode(), saveRequest.getTransactionModule(), saveRequest.getTransactionCode(),
                    saveRequest.getTransactionVersion(), ScheduleRule.class.getName());
        }
        rule.execute(saveRequest);
    }

    /**
     * Arma y entrega un objeto SaveRequest, utilizado en la ejecucion de transacciones.
     * 
     * @param jdm Map con parametros necesarios para ejecutar una tarea calendarizada.
     * @param process
     * @return SaveRequest
     * @throws Exception
     */
    private SaveRequest fillSaveRequest(JobDataMap jdm, TgeneScheduleProcess process) throws Exception {
        SaveRequest sq = new SaveRequest();
        sq.setCompany(jdm.getInt("cia"));
        sq.setBranchCode(jdm.getInt("suc"));
        sq.setOfficeCode(jdm.getInt("ofi"));
        sq.setTerminalCode(jdm.getString("ter"));
        sq.setChannelCode(jdm.getString("can"));
        sq.setUser(jdm.getString("usu"));
        sq.setTransactionModule(process.getTransactionmodule());
        sq.setTransactionCode(process.getTransactioncode());
        sq.setTransactionVersion(process.getTransactionversion());
        return sq;
    }

}
