package com.fp.frontend.controller.bpm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

import org.primefaces.event.SelectEvent;

import com.fp.dto.Request;
import com.fp.dto.Response;
import com.fp.dto.json.Serializer;
import com.fp.dto.query.DtoQuery;
import com.fp.frontend.controller.AbstractController;
import com.fp.frontend.controller.pgeneral.lov.TransactionLovController;
import com.fp.frontend.helper.MessageHelper;
import com.fp.persistence.pgeneral.log.TgeneTransactionLog;
import com.fp.persistence.pgeneral.trans.TgeneTransaction;
import com.fp.simple.dto.TaskInfo;
import com.fp.simple.dto.metadata.ProcessInstanceMeta;

/**
 * Clase que muestra
 *
 * @author amerchan
 * @version 2.1
 */
@ManagedBean
@ViewScoped
public class TransactionLogController extends AbstractController<TgeneTransactionLog> {

    private static final long serialVersionUID = 1L;

    private List<Map<String, Object>> lTransactionLogResult;

    private Map<String, Object> tLogResult;

    // monitor
    private List<Map<String, Object>> lorigin;

    private List<ProcessInstanceMeta> lstatus;

    private List<ProcessInstanceMeta> lpim;

    private Map<String, Object> first;

    private List<List<ProcessInstanceMeta>> lLast;

    private List<String> lLastA;

    private List<TaskInfo> lActualTaskInfo;

    private List<Map<String, Object>> ltaskDetailData;

    private List<Map<String, Object>> ltaskDetailComments;

    private TaskInfo taskInfoSelected;

    private String actualTaskName;

    private boolean enableFlowButton;

    private String flowJson;

    private String lFlowsResponseJson;

    private Long processId;

    private String trn;

    private String aname;

    private String comment;

    private String imageFlowName = "/resources/images/bpm/stackTraceOff.png";

    public TransactionLogController() throws Exception {
        super(TgeneTransactionLog.class);
    }

    @PostConstruct
    private void postconstruct() {
        this.init();
        // Inicializa autoconsulta
        super.startQuery();
    }

    /**
     * Incializa el controlador, cuando se esta utilizando una pagina que utliza
     * el controlador.
     */
    private void init() {
        try {
            this.lrecord = new ArrayList<>();
            this.beanalias = "TRANSACTIONLOG";
            this.enableFlowButton = false;
        } catch (Exception e) {
            MessageHelper.setMessageError(e);
        }
    }

    private void initFlowInfo() {
        this.lorigin = new ArrayList<Map<String, Object>>();
        this.lstatus = new ArrayList<ProcessInstanceMeta>();
        this.lpim = new ArrayList<ProcessInstanceMeta>();
        this.lActualTaskInfo = new ArrayList<TaskInfo>();
        this.lLast = new ArrayList<List<ProcessInstanceMeta>>();
        this.lLastA = new ArrayList<String>();
        this.first = new HashMap<String, Object>();
        this.ltaskDetailData = new ArrayList<Map<String, Object>>();
        this.ltaskDetailComments = new ArrayList<Map<String, Object>>();
        this.taskInfoSelected = new TaskInfo();
        this.enableFlowButton = false;
        this.trn = "";
        this.aname = "";
        this.imageFlowName = "";
        this.actualTaskName = "";
        this.flowJson = "";
        this.lFlowsResponseJson = "";
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void querydatabase() {
        try {
            if (!this.existAtLeastOneFilterValue()) {
                MessageHelper.setMessageError("msg_filterrequird");
                return;
            }
            Request request = this.callerhelper.getRequest();
            DtoQuery dto = super.getDtoQuery(true);
            HashMap<String, DtoQuery> mtables = new HashMap<String, DtoQuery>();
            mtables.put(this.beanalias, dto);
            request.setQueryTables(mtables);
            request.put("querytype", "P");
            request.put("queryalias", "TRANSACTIONLOGRESULT");

            Response resp = this.callerhelper.executeQuery(request);
            if (resp.getResponseCode().compareTo(Response.RESPONSE_OK) != 0) {
                this.lTransactionLogResult = new ArrayList<Map<String, Object>>();
                MessageHelper.setMessageError(resp);
            } else {
                this.lTransactionLogResult = (List<Map<String, Object>>) resp.get(this.beanalias);
                this.lrecord.add(null); // dummy para que funcione la paginacion en el metodo next()
            }
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
    }

    @SuppressWarnings("unchecked")
    public void queryMonitor() {
        try {
            this.initFlowInfo();
            Request request = this.callerhelper.getRequest();
            request.put("querytype", "T");
            request.put("queryalias", "TRANSACTIONLOGRESULT");
            request.put("PID", this.processId);

            Response resp = this.callerhelper.executeQuery(request);
            if (resp.getResponseCode().compareTo(Response.RESPONSE_OK) != 0) {
                this.lorigin = new ArrayList<Map<String, Object>>();
                this.lstatus = new ArrayList<ProcessInstanceMeta>();
                this.lpim = new ArrayList<ProcessInstanceMeta>();
                MessageHelper.setMessageError(resp);
            } else {
                this.lorigin = (List<Map<String, Object>>) resp.get("origin");
                this.lstatus = (ArrayList<ProcessInstanceMeta>) resp.get("status");
                this.lpim = this.lstatus;
                this.trn = (String) resp.get("TRN");
                // System.out.println(this.lorigin);
            }
            this.showFlow();
            this.first = (Map<String, Object>) resp.get("FIRST");
            this.showDefaultTask();
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
    }

    @SuppressWarnings("unchecked")
    public void queryTaskDetail() {
        try {
            Request request = this.callerhelper.getRequest();
            request.put("querytype", "P");
            request.put("queryalias", "TASKDETAIL");
            request.put("PID", this.processId);
            request.put("TID", this.taskInfoSelected.getTaskId());
            request.put("JID", this.taskInfoSelected.getJournalId());

            Response resp = this.callerhelper.executeQuery(request);
            if (resp.getResponseCode().compareTo(Response.RESPONSE_OK) != 0) {
                this.ltaskDetailData = new ArrayList<Map<String, Object>>();
                this.ltaskDetailComments = new ArrayList<Map<String, Object>>();
                MessageHelper.setMessageError(resp);
            } else {
                this.ltaskDetailData = (List<Map<String, Object>>) resp.get("data");
                this.ltaskDetailComments = (List<Map<String, Object>>) resp.get("comments");
                // super.cloneOriginalBean((List<AbstractDataTransport>) resp.get(this.beanalias));
            }
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
    }

    @SuppressWarnings("unchecked")
    public void showTask() {
        try {
            String taskName = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("taskName");
            // System.out.println("taskName::"+taskName);
            Request request = this.callerhelper.getRequest();
            request.put("querytype", "P");
            request.put("queryalias", "TASKHISTORY");
            request.put("PID", this.processId);
            request.put("SPID", this.processId);
            request.put("NAME", taskName);

            Response resp = this.callerhelper.executeQuery(request);
            if (resp.getResponseCode().compareTo(Response.RESPONSE_OK) != 0) {
                this.lActualTaskInfo = new ArrayList<TaskInfo>();
                MessageHelper.setMessageError(resp);
            } else {
                this.showActualInfo(taskName, (List<TaskInfo>) ((Map<String, Object>) resp.get("DATA")).values().toArray()[0]);
            }

        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
    }

    public void saveComment() {
        try {
            Request request = this.callerhelper.getNewRequest(this.callerhelper.getRequest().getTransactionModule(), 2002, 1);
            request.modifiedData().put("TID", this.taskInfoSelected.getTaskId());
            request.modifiedData().put("BPMObs", this.comment);
            Response resp = this.callerhelper.executeSave(request);
            if (resp.getResponseCode().compareTo(Response.RESPONSE_OK) == 0) {
                this.postCommit(resp);
                MessageHelper.setMessageInfo(resp);
                this.comment = "";
            } else {
                MessageHelper.setMessageError(resp);
            }
        } catch (Throwable e) {
            MessageHelper.setMessageError(e);
        }
    }

    @SuppressWarnings("unchecked")
    private void showDefaultTask() {
        try {
            Map<String, Object> mapTasks = null;
            if (this.first != null) {
                mapTasks = (Map<String, Object>) this.first.values().toArray()[0];
            }
            String key = null;
            List<TaskInfo> lTaskValues = null;
            if (mapTasks != null) {
                key = (String) mapTasks.keySet().toArray()[0];
                lTaskValues = (List<TaskInfo>) mapTasks.values().toArray()[0];
            }

            this.showActualInfo(key, lTaskValues);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void showFlow() throws Exception {
        String pMetaId = super.getRequestParameter("pMetaId");
        // System.out.println("pMetaId:"+pMetaId);
        if (pMetaId != null && !pMetaId.isEmpty()) {
            this.enableFlowButton = true;
            this.lLast.add(this.lLast.size(), this.lpim);
            this.lLastA.add(this.lLastA.size(), this.aname);
            this.lpim = this.getSubFlow(pMetaId);
        }
        this.showImage(!this.lpim.isEmpty() ? this.lpim.get(0) : null);
    }

    public void showLastFlow() throws Exception {
        this.lpim = this.lLast.get(this.lLast.size() - 1);
        this.lLast.remove(this.lLast.size() - 1);

        if (this.lLast.size() < 1) {
            this.enableFlowButton = false;
            this.showDefaultTask();
        }
        this.showImage(this.lpim.get(0));
    }

    private List<ProcessInstanceMeta> getSubFlow(String pMetaid) {
        Long metaId = Long.parseLong(pMetaid);
        for (ProcessInstanceMeta processInstanceMeta : this.lpim) {
            if (processInstanceMeta.getPmetaid().compareTo(metaId) == 0) {
                return processInstanceMeta.getSub();
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    private void showImage(ProcessInstanceMeta pFlow) throws Exception {
        if (pFlow == null) {
            return;
        }
        this.processId = pFlow.getPid();
        if (pFlow != null) {
            this.showActualInfo("", pFlow.getVariables() == null || pFlow.getVariables().get("actualTask") == null ? null : (List<TaskInfo>) pFlow
                    .getVariables().get("actualTask"));
        }
        this.imageFlowName = "/resources/images/bpm/flows/" + pFlow.getName() + "-" + pFlow.getVersion() + ".png";
    }

    private void showActualInfo(String name, List<TaskInfo> lActualTaskInfo) throws Exception {
        this.actualTaskName = name;
        this.aname = name;
        this.lActualTaskInfo = lActualTaskInfo;
        Response r = new Response("", "");
        r.put("flows", this.lpim);
        Serializer ser = new Serializer(r);

        // System.out.println(ser.toJSON());
        this.lFlowsResponseJson = ser.toJSON();
    }

    public void openTransactionLov() {
        Map<String, List<String>> params = new HashMap<>();
        List<String> l = new ArrayList<>();
        l.add("TRANSACTION"); // valor del parametro
        params.put("processtype", l);

        TransactionLovController.openLov(params);
    }

    public void onReturnTransactionLov(SelectEvent event) throws Exception {
        TgeneTransaction t = (TgeneTransaction) event.getObject();
        super.addFilter("transactionmodule", t.getPk().getTransactionmodule());
        super.addFilter("transactioncode", t.getPk().getTransactioncode().toString());
        super.addFilter("transactionversion", t.getPk().getTransactionversion().toString());
        super.addField("transactionname", t.getName());
        this.query();
    }

    /**
     * Entrega el valor de: lTransactionLogResult
     *
     * @return List<Map<String,Object>>
     */
    public List<Map<String, Object>> getlTransactionLogResult() {
        return this.lTransactionLogResult;
    }

    /**
     * Fija el valor de: lTransactionLogResult
     *
     * @param lTransactionLogResult Valor a fijar en el atributo
     */
    public void setlTransactionLogResult(List<Map<String, Object>> lTransactionLogResult) {
        this.lTransactionLogResult = lTransactionLogResult;
    }

    /**
     * Entrega el valor de: tLogResult
     *
     * @return Map<String,Object>
     */
    public Map<String, Object> gettLogResult() {
        return this.tLogResult;
    }

    /**
     * Fija el valor de: tLogResult
     *
     * @param tLogResult Valor a fijar en el atributo
     */
    public void settLogResult(Map<String, Object> tLogResult) {
        this.tLogResult = tLogResult;
    }

    /**
     * Entrega el valor de: lorigin
     *
     * @return List<Map<String,Object>>
     */
    public List<Map<String, Object>> getLorigin() {
        return this.lorigin;
    }

    /**
     * Fija el valor de: lorigin
     *
     * @param lorigin Valor a fijar en el atributo
     */
    public void setLorigin(List<Map<String, Object>> lorigin) {
        this.lorigin = lorigin;
    }

    /**
     * Entrega el valor de: lstatus
     *
     * @return List<ProcessInstanceMeta>
     */
    public List<ProcessInstanceMeta> getLstatus() {
        return this.lstatus;
    }

    /**
     * Fija el valor de: lstatus
     *
     * @param lstatus Valor a fijar en el atributo
     */
    public void setLstatus(List<ProcessInstanceMeta> lstatus) {
        this.lstatus = lstatus;
    }

    /**
     * Entrega el valor de: lpim
     *
     * @return List<ProcessInstanceMeta>
     */
    public List<ProcessInstanceMeta> getLpim() {
        return this.lpim;
    }

    /**
     * Fija el valor de: lpim
     *
     * @param lpim Valor a fijar en el atributo
     */
    public void setLpim(List<ProcessInstanceMeta> lpim) {
        this.lpim = lpim;
    }

    /**
     * Entrega el valor de: lLast
     *
     * @return List<ProcessInstanceMeta>
     */
    public List<List<ProcessInstanceMeta>> getlLast() {
        return this.lLast;
    }

    /**
     * Fija el valor de: lLast
     *
     * @param lLast Valor a fijar en el atributo
     */
    public void setlLast(List<List<ProcessInstanceMeta>> lLast) {
        this.lLast = lLast;
    }

    /**
     * Entrega el valor de: lLastA
     *
     * @return List<ProcessInstanceMeta>
     */
    public List<String> getlLastA() {
        return this.lLastA;
    }

    /**
     * Fija el valor de: lLastA
     *
     * @param lLastA Valor a fijar en el atributo
     */
    public void setlLastA(List<String> lLastA) {
        this.lLastA = lLastA;
    }

    /**
     * Entrega el valor de: lActualTaskInfo
     *
     * @return List<TaskInfo>
     */
    public List<TaskInfo> getlActualTaskInfo() {
        return this.lActualTaskInfo;
    }

    /**
     * Fija el valor de: lActualTaskInfo
     *
     * @param lActualTaskInfo Valor a fijar en el atributo
     */
    public void setlActualTaskInfo(List<TaskInfo> lActualTaskInfo) {
        this.lActualTaskInfo = lActualTaskInfo;
    }

    /**
     * Entrega el valor de: ltaskDetailData
     *
     * @return List<Map<String,Object>>
     */
    public List<Map<String, Object>> getLtaskDetailData() {
        return this.ltaskDetailData;
    }

    /**
     * Fija el valor de: ltaskDetailData
     *
     * @param ltaskDetailData Valor a fijar en el atributo
     */
    public void setLtaskDetailData(List<Map<String, Object>> ltaskDetailData) {
        this.ltaskDetailData = ltaskDetailData;
    }

    /**
     * Entrega el valor de: ltaskDetailComments
     *
     * @return List<Map<String,Object>>
     */
    public List<Map<String, Object>> getLtaskDetailComments() {
        return this.ltaskDetailComments;
    }

    /**
     * Fija el valor de: ltaskDetailComments
     *
     * @param ltaskDetailComments Valor a fijar en el atributo
     */
    public void setLtaskDetailComments(List<Map<String, Object>> ltaskDetailComments) {
        this.ltaskDetailComments = ltaskDetailComments;
    }

    /**
     * Entrega el valor de: taskInfoSelected
     *
     * @return TaskInfo
     */
    public TaskInfo getTaskInfoSelected() {
        return this.taskInfoSelected;
    }

    /**
     * Fija el valor de: taskInfoSelected
     *
     * @param taskInfoSelected Valor a fijar en el atributo
     */
    public void setTaskInfoSelected(TaskInfo taskInfoSelected) {
        this.taskInfoSelected = taskInfoSelected;
    }

    /**
     * Entrega el valor de: lFlowsResponseJson
     *
     * @return String
     */
    public String getlFlowsResponseJson() {
        return this.lFlowsResponseJson;
    }

    /**
     * Fija el valor de: lFlowsResponseJson
     *
     * @param lFlowsResponseJson Valor a fijar en el atributo
     */
    public void setlFlowsResponseJson(String lFlowsResponseJson) {
        this.lFlowsResponseJson = lFlowsResponseJson;
    }

    /**
     * Entrega el valor de: flowJson
     *
     * @return String
     */
    public String getFlowJson() {
        return this.flowJson;
    }

    /**
     * Fija el valor de: flowJson
     *
     * @param flowJson Valor a fijar en el atributo
     */
    public void setFlowJson(String flowJson) {
        this.flowJson = flowJson;
    }

    /**
     * Entrega el valor de: processId
     *
     * @return String
     */
    public Long getProcessId() {
        return this.processId;
    }

    /**
     * Fija el valor de: processId
     *
     * @param processId Valor a fijar en el atributo
     */
    public void setProcessId(Long processId) {
        this.processId = processId;
    }

    /**
     * Entrega el valor de: trn
     *
     * @return String
     */
    public String getTrn() {
        return this.trn;
    }

    /**
     * Fija el valor de: trn
     *
     * @param trn Valor a fijar en el atributo
     */
    public void setTrn(String trn) {
        this.trn = trn;
    }

    /**
     * Entrega el valor de: aname
     *
     * @return String
     */
    public String getAname() {
        return this.aname;
    }

    /**
     * Fija el valor de: aname
     *
     * @param aname Valor a fijar en el atributo
     */
    public void setAname(String aname) {
        this.aname = aname;
    }

    /**
     * Entrega el valor de: comment
     *
     * @return String
     */
    public String getComment() {
        return this.comment;
    }

    /**
     * Fija el valor de: comment
     *
     * @param comment Valor a fijar en el atributo
     */
    public void setComment(String comment) {
        this.comment = comment;
    }

    /**
     * Entrega el valor de: actualTaskName
     *
     * @return String
     */
    public String getActualTaskName() {
        return this.actualTaskName;
    }

    /**
     * Fija el valor de: actualTaskName
     *
     * @param actualTaskName Valor a fijar en el atributo
     */
    public void setActualTaskName(String actualTaskName) {
        this.actualTaskName = actualTaskName;
    }

    /**
     * Entrega el valor de: enableFlowButton
     *
     * @return boolean
     */
    public boolean isEnableFlowButton() {
        return this.enableFlowButton;
    }

    /**
     * Fija el valor de: enableFlowButton
     *
     * @param enableFlowButton Valor a fijar en el atributo
     */
    public void setEnableFlowButton(boolean enableFlowButton) {
        this.enableFlowButton = enableFlowButton;
    }

    /**
     * Entrega el valor de: imageFlowName
     *
     * @return String
     */
    public String getImageFlowName() {
        return this.imageFlowName;
    }

    /**
     * Fija el valor de: imageFlowName
     *
     * @param imageFlowName Valor a fijar en el atributo
     */
    public void setImageFlowName(String imageFlowName) {
        this.imageFlowName = imageFlowName;
    }

}
