package com.zi.mwms.solution.workflow;

import com.cim.idm.flowpackage.core.BpelActivityListener;
import com.cim.idm.flowpackage.core.BpelExecutionContext;
import com.cim.idm.flowpackage.core.BpelExecutionContextAware;
import com.cim.idm.flowpackage.core.BpelProcessManager;
import com.cim.idm.flowpackage.core.activity.BpelProcess;
import com.cim.idm.framework.IDMFrameServiceProxy;
import com.cim.idm.framework.event.MessageEventAdaptor;
import com.cim.idm.framework.event.support.DocumentMessageUtil;
import com.cim.idm.framework.fos.idmflow.BpelExecutionEventAdaptor;
import com.cim.idm.framework.fos.idmflow.BpelExecutorService;
import com.cim.idm.framework.util.time.TimeUtils;
import com.cim.idm.framework.util.xml.JdomUtils;
import com.cim.idm.wmsextend.generic.GenericServiceProxy;
import com.cim.idm.wmsextend.generic.util.CommonUtil;
import com.cim.idm.wmsextend.generic.util.SMessageUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.xml.namespace.QName;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * BpelExecutionContextAware Interface
 */

/**
 * @author 10210477
 * @date 2022年08月17日 14:23
 */
public class BpelExecuter extends BpelExecutorService implements ApplicationContextAware, BpelExecutionContextAware {
    static Log log = LogFactory.getLog(BpelExecuter.class);

    /**
     * @uml.property name="context"
     * @uml.associationEnd
     */
    private ApplicationContext context;

    // BpelExecutionContext save ThreadLocal add
    /**
     * @uml.property name="bpelExecutionContext"
     * @uml.associationEnd multiplicity="(0 -1)" elementType="kr.co.aim.nanoflow.core.BpelExecutionContext"
     */
    private ThreadLocal<BpelExecutionContext> bpelExecutionContext = new ThreadLocal<BpelExecutionContext>();

    public void terminateImmediately() {
        log.info("***************************************************************************************");
        System.exit(0);
    }

    public void terminateAfterManagement(String serverName) {

        String selfServerName = System.getProperty("Seq");
        log.info("***************************************************************************************");
        log.info("Receive ServerName = " + serverName);
        log.info("My ServerName = " + selfServerName);

        if (serverName.equals(selfServerName)) {

            log.info("[1/2] Closeing Transport .....");
            MessageEventAdaptor bundleMessageEventAdaptor = (MessageEventAdaptor) IDMFrameServiceProxy
                    .getApplicationContext().getBean(MessageEventAdaptor.class);
            bundleMessageEventAdaptor.terminate();
            log.info("[2/2] Closeing Transport .....");

            log.info("[1/2] Checking alive bpel or running bpel .....");
            BpelProcessManager bpelProcessManager = (BpelProcessManager) IDMFrameServiceProxy
                    .getApplicationContext().getBean(BpelProcessManager.class);
            boolean isrunningBpel = false;
            int bpelCheckCount = 2;

            String nameCheck = serverName.substring(0, 6);
            String msgSvrStr = "MSGSVR";
            if (msgSvrStr.equals(nameCheck.toUpperCase())) {
                bpelCheckCount = 3;
            }
            int max = 3;
            for (int i = 0; i < max; i++) {
                log.info("Bpel Size = " + bpelProcessManager.getRunningBpelProcessSize());
                while (bpelProcessManager.getRunningBpelProcessSize() > bpelCheckCount) {
                    if (!isrunningBpel) {
                        log.info("Waiting for completing running bpel .....");
                        isrunningBpel = true;
                    }
                    try {
                        Thread.sleep(500);
                    } catch (Exception e) {
                    }
                }

                try {
                    Thread.sleep(330);
                } catch (Exception e) {
                }
            }

            if (isrunningBpel) {
                log.info("All running bpel are completed .....");
            }

            log.info("[2/2] Checking alive bpel or running bpel .....");
            log.info("***************************************************************************************");
            log.info("********************           Terminated Good bye           **************************");
            log.info("***************************************************************************************");
            System.exit(0);
        } else {
            log.warn("Receive ServerName is not same my Name");
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        context = ctx;
    }

    @Override
    public void setBpelExecutionContext(BpelExecutionContext bpelExecutionContext) {
        this.bpelExecutionContext.set(bpelExecutionContext);
    }

    public BpelExecutionContext getBpelExecutionContext() {
        return bpelExecutionContext.get();
    }

    public void executeWFListener(Document document) {
        Object[] arguments = new Object[]{document};
        this.executeWF(arguments, false, DocumentMessageUtil.getListenerBpelName(document));
    }

    public void executeWF(Document document) {
        Object[] arguments = new Object[]{document};
        this.executeWF(arguments, false, DocumentMessageUtil.getBpelName(document));
    }

    @Override
    public void executeWF(Document document, String bpelName) {
        Object[] arguments = new Object[]{document};
        this.executeWF(arguments, false, bpelName);
    }

    public void SyncExcuteWF(Document document, String bpelName) {
        Object[] arguments = new Object[]{document};
        this.executeWF(arguments, false, bpelName);
    }

    public void executeProcess(Object[] arguments, boolean parallel, String bpelName) {
        BpelProcess process = null;
        try {
            if (bpelName == null) {
                for (int i = 0; i < arguments.length; i++) {
                    if (arguments[i] instanceof Document) {
                        String bpel = DocumentMessageUtil.getBpelName((Document) arguments[i]);
                        if (bpel != null && bpel.length() > 0) {
                            if (!bpel.toLowerCase().endsWith(".bpel")) {
                                bpelName = bpel + ".bpel";
                            } else {
                                bpelName = bpel;
                            }
                            break;
                        }
                    }
                }
                if (bpelName == null) {
                    bpelName = getBpelRepository().getRootBpelName();
                }
            }


            QName name = new QName(DEFAULT_TARGETNAMESPACE, bpelName);
            process = newBpelProcess(name);
            try {
                BpelActivityListener listener = (BpelActivityListener) context.getBean("Modeler");
                process.addBpelActivityListener(listener);
            } catch (Exception ex) {

                process.addBpelActivityListener((BpelExecutionEventAdaptor) context.getBean("BpelExecutionEventAdaptor"));
            }


            process.execute(arguments, parallel);

        } catch (Exception ex) {
            log.error("Could not execute " + bpelName, ex);
            ((BpelExecutionEventAdaptor) context.getBean("BpelExecutionEventAdaptor")).onException(process, ex);
        }
    }

    public void executeWF(Object[] arguments, boolean parallelMode, String bpelName) {
        BpelProcess process = null;
        String bpelStr = ".bpel";
        try {
            if (bpelName == null) {
                for (int i = 0; i < arguments.length; i++) {
                    if (arguments[i] instanceof Document) {
                        String bpel = DocumentMessageUtil.getBpelName((Document) arguments[i]);
                        if (bpel != null && bpel.length() > 0) {
                            if (!bpel.toLowerCase().endsWith(".bpel")) {
                                bpelName = bpel + ".bpel";
                            } else {
                                bpelName = bpel;
                            }
                            break;
                        }
                    }
                }
                if (bpelName == null) {
                    bpelName = getBpelRepository().getRootBpelName();
                }
            } else if (bpelName.length() > 0 && !bpelName.toLowerCase().endsWith(bpelStr)) {
                bpelName = bpelName + ".bpel";
            }
            QName name = new QName(DEFAULT_TARGETNAMESPACE, bpelName);
            process = newBpelProcess(name);
            process.setParent(getBpelExecutionContext().getRunningActivity());
            process.setSuperProcess(getBpelExecutionContext().getBpelProcess());
            process.addBpelActivityListener(getBpelExecutionContext().getRunningActivity());
            Document doc = (Document) arguments[0];
            Element root = doc.getDocument().getRootElement();
            Element header = root.getChild(SMessageUtil.Header_Tag);
            try {
                String sql = " SELECT DEFAULTFLAG FROM ENUMDEFVALUE WHERE ENUMNAME = "
                        + "? AND ENUMVALUE = ? AND DEFAULTFLAG = ? ";
                Object[] bind = new Object[]{"ServerMessageLogSave", "MessageSaveFlag", "Y"};
                String[][] sqlResult = IDMFrameServiceProxy.getSqlTemplate().queryForStringArray(sql, bind);
                String yStr = "Y";
                if (sqlResult != null && sqlResult.length > 0 && sqlResult[0][0].length() > 0
                        && yStr.equals(sqlResult[0][0])) {
                    String sOicFormName = "";
                    String sServerName = System.getProperty("svr");
                    String sMessageName = "";
                    String sMenuName = "";
                    try {
                        sOicFormName = header.getChild("OICFORMNAME").getText();
                    } catch (Exception ex) {
                        sOicFormName = "NULL";
                    }
                    try {
                        sMenuName = header.getChild("OICMENUNAME").getText();
                    } catch (Exception ex) {
                        sMenuName = "";
                    }
                    try {
                        sMessageName = header.getChild("MESSAGENAME").getText();
                    } catch (Exception ex) {
                        sMessageName = "NULL";
                    }
                    if (sServerName == null || "".equals(sServerName)) {
                        sServerName = "NULL";
                    }
                    if (sMenuName != null && sMenuName.length() > 0) {
                        sql = " SELECT NVL(ENGLISH, ?) FROM BSNLSDATA WHERE 1 = 1 AND NLSTYPE IN ('Menu', 'Label' ) "
                                + "AND NLSNAME = ? ORDER BY DECODE(NLSTYPE, 'Menu', 1, 'Label', 0, 999) ";
                        bind = new Object[]{sMenuName, sMenuName};
                        sqlResult = IDMFrameServiceProxy.getSqlTemplate().queryForStringArray(sql, bind);
                        if (sqlResult != null && sqlResult.length > 0) {
                            sMenuName = sqlResult[0][0];
                        }
                    }
                    sql = " DELETE FROM BSMESSAGEUSEINFO WHERE SERVERNAME = ? AND FORMNAME = ? AND MESSAGENAME = ? ";
                    bind = new Object[]{sServerName, sOicFormName, sMessageName};
                    IDMFrameServiceProxy.getSqlTemplate().update(sql, bind);
                    sql = " INSERT INTO BSMESSAGEUSEINFO (SERVERNAME, FORMNAME, MESSAGENAME, TIMEKEY, "
                            + "MENUCAPTION, MESSAGEFORMAT) VALUES (?, ?, ?, ?, ?, ?) ";
                    bind = new Object[]{sServerName, sOicFormName, sMessageName, new TimeUtils().getCurrentEventTimeKey(),
                            sMenuName, JdomUtils.toString(doc)};
                    IDMFrameServiceProxy.getSqlTemplate().update(sql, bind);
                }
            } catch (Exception ex) {
            }
            String username = header.getChild("EVENTUSER") != null ? header.getChild("EVENTUSER").getText() : null;
            String source = header.getChild("SOURCE") != null ? header.getChild("SOURCE").getText() : null;
            String token = header.getChild("TOKEN") != null ? header.getChild("TOKEN").getText() : null;
            String messageName = header.getChild("MESSAGENAME") != null ? header.getChild("MESSAGENAME")
                    .getText() : null;
//            boolean checkResult = UserServiceProxy.getUserInfoService().checkLoginTokenForBpel(username,
//                    source, token, messageName);
            boolean checkResult=true;
            if (!checkResult) {
                Element returnElement = new Element("Return");
                Element returnCode = new Element("RETURNCODE");
                returnCode.setText("9999");
                returnElement.addContent(returnCode);
                Element returnMessage = new Element("RETURNMESSAGE");
                returnMessage.setText("Login authorization failed");
                returnElement.addContent(returnMessage);
                root.addContent(returnElement);
                return;
            }

/*            String checkInterface = "SELECT count(1) FROM PLATFORMINTERFACEMANAGER WHERE PLATFORMNAME = ? and INTERFACETYPE = ? and INTERFACENAME = ? and status = 'On' ";

            String[] checkInterfaceArgs = new String[]{source, "Event",messageName};

            List<Map<String, Object>> checkInterfaceList = IDMFrameServiceProxy.getSqlTemplate().queryForList(checkInterface, checkInterfaceArgs);

            if(checkInterfaceList.size() == 0){
                Element returnElement = new Element("Return");
                Element returnCode = new Element("RETURNCODE");
                returnCode.setText("9998");
                returnElement.addContent(returnCode);
                Element returnMessage = new Element("RETURNMESSAGE");
                returnMessage.setText("Interface not authorized");
                returnElement.addContent(returnMessage);
                root.addContent(returnElement);
                return;
            }*/

            process.execute(arguments, parallelMode, false, getBpelExecutionContext()
                    .getBpelProcess().getOriginatorBpelProcess());
            Long lElapsedTime = process.getEndTime().getTime() - process.getStartTime().getTime();
            log.info("Message[" + header.getChild("MESSAGENAME").getText() + "]" + "TRANSACTIONID["
                    + header.getChildText("TRANSACTIONID") + "]-elapsedTime=" + lElapsedTime);
        } catch (Exception ex) {
            log.error("Could not execute " + bpelName, ex);
            ((BpelExecutionEventAdaptor) context.getBean("BpelExecutionEventAdaptor")).onException(process, ex);
        } finally {
            bpelExecutionContext.remove();
        }
    }

    public Document makeEviorMessageFormat(Document xml, String value) throws Exception {
        Element root = xml.getDocument().getRootElement();

        Document returnMsg = (Document) xml.clone();

        Element headerElement = JdomUtils.getNode(returnMsg, "//Message/Header");

        headerElement.getChild("KIND").setText("UnixProcessReport");
        headerElement.getChild("MESSAGENAME").setText("UnixProcessReport");

        Element bodyElement = JdomUtils.getNode(returnMsg, "//Message/Body");

        if (bodyElement == null) {
            Element messageElement = JdomUtils.getNode(returnMsg, "//Message");
            bodyElement = new Element("Body");

            messageElement.addContent(bodyElement);
        } else {
            bodyElement.removeContent();
        }

        String selfServerName = System.getProperty("Seq");

        Element unixProcessReportElement = new Element("UNIXPROCESS_REPORT");
        unixProcessReportElement.setAttribute("ID", selfServerName);

        Element reportKeyElement = new Element("REPORT_KEY");
        reportKeyElement.setText(value);

        unixProcessReportElement.addContent(reportKeyElement);

        bodyElement.addContent(unixProcessReportElement);

        return returnMsg;
    }

    /**
     * Name : insertMessageLog
     * Desc : This function is insertMessageLog
     * Author :ZXY Systems, Inc
     * Date : 2013.04.20
     */
    /**
     * @param doc
     * @param serverName
     */
    public static void insertMessageLog(Document doc, String serverName) {
        CommonUtil.insertMessageLog(doc, serverName);
    }

    /**
     * Name : insertErrorMessageLog
     * Desc : This function is insertMessageLog
     * Author : ZXY Systems, Inc
     * Date : 2013.04.20
     */
    /**
     * @param doc
     */
    public static void insertErrorMessageLog(Document doc) {
        CommonUtil.insertErrorMessageLog(doc);
    }

    /** 2013.04.15
     *
     * @param target
     * @return
     */
    /**
     * @param target
     * @return String
     */
    public String pdcDataInsertFlag(String target) {
        String flag = GenericServiceProxy.getConstantMap().FLAG_N;
        if (CommonUtil.getEnumDefValueByEnumName(target).size() > 0) {
            flag = CommonUtil.getEnumDefValueByEnumName(target).get(0).get("ENUMVALUE").toString();
        }

        return flag;
    }

    public static void reportSvrCount(String serverName, String messageName) {
        try {
            List<Map<String, Object>> yn = CommonUtil.getEnumDefValueByEnumName(GenericServiceProxy
                    .getConstantMap().MESSAGECOUNT);
            String yStr = "Y";
            String enumValueStr = "ENUMVALUE";
            if (yn.size() > 0 && yStr.equals(yn.get(0).get(enumValueStr).toString())) {
                String wipDate = CommonUtil.getWipDate();
                String selectSql = "SELECT MESSAGENAME,MESSAGECOUNT FROM BSMESSAGECOUNT "
                        + "WHERE WIPDATA = :wipData AND TYPENAME = 'Report' AND SERVERNAME = :serverName "
                        + "AND MESSAGENAME = :messageName";

                Map<String, String> bindMap = new HashMap<String, String>(5);
                bindMap.put("wipData", wipDate);
                bindMap.put("serverName", serverName);
                bindMap.put("messageName", messageName);

                List<Map<String, Object>> selectResult =
                        IDMFrameServiceProxy.getSqlTemplate().queryForList(selectSql, bindMap);

                if (selectResult.size() > 0) {
                    String updateSql = "UPDATE BSMESSAGECOUNT SET MESSAGECOUNT = :maxCount "
                            + "WHERE WIPDATA = :wipData AND TYPENAME = 'Report' AND SERVERNAME = :serverName "
                            + "AND MESSAGENAME = :messageName";

                    bindMap.put("maxCount", String.valueOf(Integer.valueOf(selectResult.get(0)
                            .get("MESSAGECOUNT").toString()) + 1));

                    IDMFrameServiceProxy.getSqlTemplate().update(updateSql, bindMap);
                } else {
                    String insertSql = "INSERT INTO BSMESSAGECOUNT (WIPDATA, TYPENAME, SERVERNAME, "
                            + "MESSAGENAME, MESSAGECOUNT) "
                            + "VALUES (:wipData,'Report',:serverName,:messageName,1)";

                    IDMFrameServiceProxy.getSqlTemplate().update(insertSql, bindMap);
                }
            }

        } catch (Exception e) {
            log.error("Report Type Error BSMESSAGECOUNT");
        }
    }

    public Document executeDispatching(Document doc, String bpelName) {
        BpelProcess process = null;
        try {
            bpelName = bpelName + ".bpel";
            QName name = new QName(DEFAULT_TARGETNAMESPACE, bpelName);
            process = newBpelProcess(name);
            process.execute(new Object[]{doc}, false, false, null);
            return doc;
        } catch (Exception ex) {
            log.error("Could not execute " + bpelName, ex);
            ((BpelExecutionEventAdaptor) context.getBean("BpelExecutionEventAdaptor")).onException(process, ex);
        }
        return null;
    }
}