package com.horizon.wf.action;

import com.horizon.wf.action.base.BaseForTask;
import com.horizon.wf.action.base.IActionForStartSubFlow;
import com.horizon.wf.action.base.SubflowEnd;
import com.horizon.wf.config.HZResourceBundle;
import com.horizon.wf.core.node.INextNode;
import com.horizon.wf.core.node.ITaskNode;
import com.horizon.wf.core.runtime.RunningData;
import com.horizon.wf.core.track.json.impl.ITrackJson;
import com.horizon.wf.core.work.ICustomAction;
import com.horizon.wf.definition.pub.IFlowInfo;
import com.horizon.wf.definition.pub.IFlowNode;
import com.horizon.wf.definition.pub.node.INodeControl;
import com.horizon.wf.definition.pub.node.INodeForm;
import com.horizon.wf.definition.pub.node.INodeRouter;
import com.horizon.wf.definition.tools.NodeTypeEnum;
import com.horizon.wf.entity.db.*;
import com.horizon.wf.entity.user.INodeUser;
import com.horizon.wf.expand.impl.IOrganizationInterface;
import com.horizon.wf.global.*;
import com.horizon.wf.plugins.PluginsUtil;
import com.horizon.wf.rule.jsr94.IRuleEngine;

import java.util.*;

/**
 * 提交操作实现类
 *
 * @author liys
 * @version 1.0
 * @since v7.0
 */
public class ActionSubmit extends BaseForTask implements ICustomAction,
        IActionForStartSubFlow {
    private List<INextNode> nextNodes = new ArrayList<INextNode>();
    private boolean isSendTodo = true;// 是否发送待办
    private boolean isMakeTaskData = true;// 是否生成task数据
    private SubflowEnd subflowEnd = null;// 子流程实例结束时,主流程是否可以往下流转处理类

    /**
     * 本操作需要执行的内容
     */
    public boolean execute(ITaskNode curTaskNode) {
        setFunnameToRunningdata();

        // 提交到退回节点时,如果需要重新选择办理人,则把下面的赋值语句打开即可,不打开则获取退回节点的原来办理人(包含没有办理的人)
        if (runningdata.getCurTrack().getFlowstatus() == StaticVarExtend.FlowStatus_Reject) {
            runningdata.getCurTrack().setFlowstatus(
                    StaticVarExtend.FlowStatus_Normal);
        }
        normalSubmit(curTaskNode);
        // 执行操作完成事件
        if (StaticVarExtend.F_STATUS_Success == result && executeEventSave()) {
            handleFirstStart();// 处理第一次操作的 权限
            if (actionSuccess(resultBean.getNextNodes())) {
                runningdata.setUpdateTask(true);
                if("Start".equals(curTaskNode.getNodeid()) && !HZResourceBundle.getInstance().isSaveToDBWhenStartInstance()){
                    // 开始节点只有没有业务表单
                    String[] formids={"FlowTrack"};
                    runningdata.getInitData().setFormids(formids);
                }else{
                    // 获取当前人有权限的表单
                    runningdata.getInitData().setFormids(
                            ac.setFormIdsByRunningdata(getCurFlowNode(),
                                    getCurUser()));
                }

            } else {
                result = StaticVarExtend.F_STATUS_OtherError;
            }
        }

        runningdata.setBackMsg(msg);
        runningdata.setResultCode(result);
        return true;
    }

    protected void setFunnameToRunningdata() {
        runningdata.setFunname(StaticVarExtend.OPERATOR_FUNNAME_SUBMIT);
        setActionname("Submit_Msg0001", "提交");
    }

    /**
     * 处理第一次操作
     */
    private void handleFirstStart() {
        List<DBWorkAuth> auths = new ArrayList<DBWorkAuth>();
        DBTrack track = runningdata.getCurTrack();
        IFlowNode curNode = runningdata.getCurFlowNode();
        // 是否第一次操作
        if (isnewdoc < 2) {
            isNewDoc("2");
            // 全局读者
            String flowreaders = changeReaderList(runningdata);
            if (StringUtilExtend.isNotNull(flowreaders)) {
                auths.add(makeAuthByAuthId(flowreaders,
                        StaticVarExtend.AUTH_READER, ""));

                // 增加发送消息
                DBTodo frTodo = makeDefaultDBTodo();
                frTodo.setAuthId(flowreaders);
                frTodo.setTrackactive(String.valueOf(track.getActive()));
                frTodo.setTrackid(track.getId());
                frTodo.setTrackstatus(String.valueOf(track.getFlowstatus()));
                frTodo.setNodeid(getCurNodeid());
                frTodo.setNodename(track.getNodename());
                frTodo.setWorkver((track.getVersion() + 1));

                IFlowInfo flowInfo = runningdata.getInstanceDefinition()
                        .getFlowinfo();
                String msgType = flowInfo.getReaderMsg();

                String dMsg = StaticVarExtend.Send_Read;
                // 20150727 liys 修改为默认发送待阅消息,不管定义是否勾选
                DBTodo nTodo = frTodo.copy();
                nTodo.setTitle(ac.getTodoTitle(track.getId(), curNode,
                        runningdata, dMsg, StaticVarExtend.AUTH_READER));
                nTodo.setStatus(StaticVarExtend.AUTH_READER);
                todoLst.add(nTodo);

                String[] msgSendTypes = msgType
                        .split(StaticVarExtend.StrSplitChar);
                for (String str : msgSendTypes) {
                    if (null == str || "".equals(str)
                            || str.equalsIgnoreCase(dMsg)) {
                        continue;
                    }
                    DBTodo oTodo = frTodo.copy();
                    oTodo.setTitle(ac.getTodoTitle(track.getId(), curNode,
                            runningdata, str, StaticVarExtend.AUTH_READER));
                    oTodo.setStatus("");
                    oTodo._setOtherstatus(str);
                    todoLst.add(oTodo);
                }

            }

            if (isnewdoc == 0) {
                String doneId = getCurUser().getFullName();
                // 增加创建者权限
                DBWorkAuth creator = makeAuthByAuthId(doneId,
                        StaticVarExtend.AUTH_CREATOR, "");
                creator.setAuthType(StaticVarExtend.UserFix);
                auths.add(creator);
            }

        }
        if (!auths.isEmpty()) {
            runningdata.setCurAuthToMap(auths);
        }
    }

    /**
     * 将全局读者的list转换成string
     * @return 转换后的字符串
     */
    private String changeReaderList(RunningData rd) {
        StringBuilder readers = new StringBuilder("");
        String dataIdentifier = rd.getInitData().getDataIdentifier();
        List<String> readersList = rd.getInstanceDefinition().getFlowinfo()
                .getReader();
        IOrganizationInterface organization = PluginsUtil.getMultiInstance().getOrganization(rd.getInitData().getTenantid());
        if (CollectionUtil.isListNotEmpty(readersList)) {
            // 个人,无前缀
            if (StringUtilExtend.isNotNull(readersList.get(0))) {
                String[] persons = readersList.get(0).split(
                        StaticVarExtend.UserSplitChar);
                for (String s : persons) {
                    if(!s.startsWith(StaticVarExtend.UserFix+StaticVarExtend.Mark_Fix)){
                        readers.append(StaticVarExtend.UserFix).append(StaticVarExtend.Mark_Fix);
                    }
                    readers.append(s).append(StaticVarExtend.UserSplitChar);
                }
            }
            // 部门,有前缀
            if (StringUtilExtend.isNotNull(readersList.get(1))) {
                String[] depts = readersList.get(1).split(
                        StaticVarExtend.UserSplitChar);
                for (String s : depts) {
                    if(!(s.startsWith(StaticVarExtend.DeptFix+StaticVarExtend.Mark_Fix)
                            || s.startsWith(StaticVarExtend.DeptSubFix+StaticVarExtend.Mark_Fix))){
                        if(s.startsWith("DF_") || s.startsWith("DL_") || s.startsWith("DJ_")) {
                            String deptType = s.substring(0, 2);
                            String deptId = s.substring(3);
                            String type = null;
                            if ("DJ".equals(deptType)){
                                type = "I";
                            }else if ("DL".equals(deptType)){
                                type = "C";
                            }else if ("DF".equals(deptType)){
                                type = "F";
                            }
                            String userId = organization.getDeptSpecialUser(deptId, type, dataIdentifier);
                            if (StringUtilExtend.isNotNull(userId)) {
                                readers.append(StaticVarExtend.UserFix).append(StaticVarExtend.Mark_Fix).append(userId);
                            }
                            readers.append(StaticVarExtend.SubjectionFix);
                            readers.append(StaticVarExtend.DeptFix).append(StaticVarExtend.Mark_Fix).append(deptId).append(StaticVarExtend.UserSplitChar);
                        }else{
                            readers.append(StaticVarExtend.SubjectionFix);
                            readers.append(StaticVarExtend.DeptFix).append(StaticVarExtend.Mark_Fix).append(s).append(StaticVarExtend.UserSplitChar);;
                        }
                    }else {
                        readers.append(StaticVarExtend.SubjectionFix).append(s).append(StaticVarExtend.UserSplitChar);
                    }
                }
            }
            // 群组,无前缀
            if (StringUtilExtend.isNotNull(readersList.get(2))) {
                String[] groups = readersList.get(2).split(
                        StaticVarExtend.UserSplitChar);
                for (String s : groups) {
                    readers.append(StaticVarExtend.SubjectionFix);
                    if(!s.startsWith(StaticVarExtend.GroupFix+StaticVarExtend.Mark_Fix)){
                        readers.append(StaticVarExtend.GroupFix).append(StaticVarExtend.Mark_Fix);
                    }
                    readers.append(s).append(StaticVarExtend.UserSplitChar);
                }
            }
            // 角色,无前缀
            if (StringUtilExtend.isNotNull(readersList.get(3))) {
                String[] roles = readersList.get(3).split(
                        StaticVarExtend.UserSplitChar);
                for (String s : roles) {
                    readers.append(StaticVarExtend.SubjectionFix);
                    if(!s.startsWith(StaticVarExtend.RoleFix+StaticVarExtend.Mark_Fix)){
                        readers.append(StaticVarExtend.RoleFix).append(StaticVarExtend.Mark_Fix);
                    }
                    readers.append(s).append(StaticVarExtend.UserSplitChar);
                }
            }
            // 岗位,无前缀
            if (StringUtilExtend.isNotNull(readersList.get(4))) {
                String[] positions = readersList.get(4).split(
                        StaticVarExtend.UserSplitChar);
                for (String s : positions) {
                    readers.append(StaticVarExtend.SubjectionFix);
                    if(!s.startsWith(StaticVarExtend.PosFix+StaticVarExtend.Mark_Fix)){
                        readers.append(StaticVarExtend.PosFix).append(StaticVarExtend.Mark_Fix);
                    }
                    readers.append(s).append(StaticVarExtend.UserSplitChar);
                }
            }
        }

        String readerScript = rd.getInstanceDefinition().getFlowinfo()
                .getReaderRuleScript();
        if (StringUtilExtend.isNotNull(readerScript)) {
            try {
                IRuleEngine du = PluginsUtil.getMultiInstance().getRuleEngine();
                du.setPara("RunningData", rd);

                Object rs = du.exctu(readerScript);
                if (null != rs) {
                    readers.append(String.valueOf(rs));
                }
            } catch (Exception e) {
                rd.putMsgToConsole("[err]get readerScript error!");
            }
        }
        return readers.toString();
    }

    /**
     * 根据authId生成auth对象
     *
     * @param authId
     * @return
     */
    private DBWorkAuth makeAuthByAuthId(String authId, String status,
                                        String oldStatus) {
        DBWorkAuth a = new DBWorkAuth();
        a.setAuthId(authId);
        a.setAuthNo(0);
        a.setNodeid(getCurNodeid());
        a.setNodenum(0);
        a.setStatus(status);
        a.setOldStatus(oldStatus);

        a.setTrackid(getCurTrackid());
        a.setVersion(0);
        a.setWorkid(getWorkid());
        return a;
    }

    /**
     * 正常提交（准备离开当前节点的提交）
     *
     * @param curTaskNode
     */
    private void normalSubmit(ITaskNode curTaskNode) {
        runningdata.putMsgToConsole("[msg]docurNode start.");
        boolean curResult = curTaskNode.doCurNode();
        runningdata.putMsgToConsole("[msg]docurNode end.reulst:" + result);
        // 前台参数
        if (curResult) {// false时为当前节点不允许离开 如多人处理
            leaveThisNode(curTaskNode, false);
        } else {// 不离开当前节点
            result = curTaskNode.getCurNode().getInitResult();
            if (StaticVarExtend.F_STATUS_Success == result) {
                msg = pubInfo.getInfo("Action_Msg0004", "提交成功");

                int curNodeType = getCurNodeType();
                // 当前节点是顺签和逐级办理的时候将办理人置于selectUsers用来发送待办
                if (curNodeType == NodeTypeEnum.Node_Order
                        || curNodeType == NodeTypeEnum.Node_Progressively) {
                    List<INodeUser> nodeUserList = curTaskNode.getCurNode()
                            .getListUserByNodeInit();
                    for (int i = 0, n = nodeUserList.size(); i < n; i++) {
                        INodeUser nu = nodeUserList.get(i);
                        String key = curTaskNode.getCurNode().getKeyid()
                                + StaticVarExtend.MARK_NODE_USER
                                + nu.getAuthType();
                        selectedUsers.put(key, nu.getNowid());
                    }
                    if (curNodeType == NodeTypeEnum.Node_Order) {
                        memoBuffer.append(pubInfo.getInfo("Submit_Msg0006",
                                "顺签办理"));
                    } else {
                        memoBuffer.append(pubInfo.getInfo("Submit_Msg0007",
                                "逐级审批"));
                    }
                    doMemoFromSelected(curTaskNode.getCurNode());
                } else if (curNodeType == NodeTypeEnum.Node_Merger) {
                    result = StaticVarExtend.F_STATUS_UnitSubmit;
                    msg = pubInfo.getInfo("Submit_Msg0002", "不符合离开规则,不能离开当前节点");
                } else if (curNodeType == NodeTypeEnum.Node_Multi) {// 多人处理时将剩余办理人置于selectedUsers供前台显示
                    isSendTodo = false;
                    // 并行处理，等待其他人办理
                    memoBuffer.append(pubInfo.getInfo("Submit_Msg0008",
                            "多人处理，等待其他人办理"));
                }
                isMakeTaskData = false;// 不离开当前节点，不执行task表写入
            }
            // else if(StaticVarExtend.F_STATUS_SelectAuthor == result){
            // //只有内部循环节点才会出现
            //
            // }
            // else if(StaticVarExtend.F_STATUS_SelectNode == result){
            // //只有内部循环节点才会出现
            // leaveThisNode(curTaskNode,true);
            // }
            else {
                msg = curTaskNode.getCurNode().getBackMsg();
            }

        }
    }

    /**
     * 离开当前节点 addCurNode,是否增加当前节点到选择列表中
     */
    private void leaveThisNode(ITaskNode curTaskNode, boolean addCurNode) {
        // 获取传入的下一节点和办理人信息
        initNextNodePara();
        leaveByRouter(curTaskNode);
        if (result == StaticVarExtend.F_STATUS_Success) {
            if (CollectionUtil.isListEmpty(nextNodes)) {
                result = runningdata.getResultCode();
                msg = runningdata.getBackMsg();
                return;
            }
            doWithNextNodeResult(true);
        }

        // 20150513增加下一节点按路由序号排序
        sortNextNodes();

        resultBean.setNextNodes(nextNodes);// (curTaskNode.getGNextNodes());
        StringBuilder sb = new StringBuilder(1000);
        memoBuffer.append(pubInfo.getInfo("Submit_Msg0009", "提交到节点"));
        for (int i = 0, m = nextNodes.size(); i < m; i++) {
            INextNode n = nextNodes.get(i);
            if (n.isSelected()) {
                sb.append(StaticVarExtend.MARK_NODE_SPLIT).append(
                        n.getSelectedIdStr());
                doMemoFromSelected(n);
            }
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(0);
            nextNodeId = sb.toString();

        }
    }

    private void leaveByRouter(ITaskNode curTaskNode) {
        runningdata.putMsgToConsole("[msg]leaveByRouter start.");
        // 没有传入选择节点内容时,系统默认根据定义查找下一节点
        // 前台选择人员设置格式:key=节点id_参与者类型(Author,reader),value=userid(多个使用分号|)
        // 此处传入的参数在节点进入规则接口中使用
        if (checkForFree()) {
            return;
        }
        curTaskNode.leaveByRouter(nextNodeList, selectedUsers);
        result = curTaskNode.getCurNode().getInitResult();
        int initResult = runningdata.getResultCode();
        if (initResult != StaticVarExtend.F_STATUS_Success) {
            initResult = runningdata.getResultCode();
            msg = runningdata.getBackMsg();
            return;
        }
        msg = curTaskNode.getCurNode().getBackMsg();
        nextNodes = curTaskNode.getGNextNodes();// 获取符合条件的节点列表
        runningdata.putMsgToConsole("[msg]leaveByRouter end.result:"
                + initResult + ";msg:" + msg);
    }

    /**
     * 自由提交时,用于检查节点是否有需要增加节点的处理 返回true表示终止程序
     *
     * @return
     */
    protected boolean checkForFree() {
        return false;
    }

    /**
     * 拿回状态,提交时直接给拿回之前的节点 下一节点进行处理
     */
    void doForGetBack(ITaskNode curTaskNode) {
        DBTrack track = getCurTrack();
        if (track.getFlowstatus() == StaticVarExtend.FlowStatus_GetBack) {
            runningdata.putMsgToConsole("[msg]flowstatus = getback");
            ITrackJson xmlTrack = track._getTrackJson();
            String doneNodeID = xmlTrack.getTrueRecord();
            String[] nodes = doneNodeID.split(StaticVar.StrSplitChar);
            // 获取拿回前的节点
            if (nodes.length > 1) {
                List<INodeRouter> routers = curTaskNode.getFlowNode()
                        .getAllToRouters();
                String nodeid = nodes[nodes.length - 2];
                for (int i = 0, n = routers.size(); i < n; i++) {
                    INodeRouter router = routers.get(i);
                    if (nodeid.equals(router.getNodeid())) {
                        nextNodeId = router.getRouterid() + "~" + nodeid;
                        break;
                    }
                }
                if (StringUtilExtend.isNull(nextNodeId)) {
                    // 拿回之前的节点跟当前节点无路由连接
                    runningdata.putMsgToConsole("[msg]get back from jump node");
                } else {
                    // 重新初始化下一节点列表
                    runningdata.putMsgToConsole("[msg]re init nextnodes");
                    initNextNodePara();
                }
            }
        }
    }

    private void sortNextNodes() {
        List<INextNode> nodes = nextNodes;
        List<INextNode> sortNodes = new ArrayList<INextNode>();
        List<INextNode> tmpNode = new ArrayList<INextNode>();

        for (int i = 0, n = nodes.size(); i < n; i++) {
            INextNode node = nodes.get(i);
            // 排序准备
            INodeRouter tmpRouter = node.getFromXmlRouter();
            if (tmpRouter == null) {
                sortNodes.add(node);
            } else {
                tmpNode.add(node);
            }
        }
        Collections.sort(tmpNode, new Comparator<INextNode>() {
            public int compare(INextNode o1, INextNode o2) {
                return o1.getFromXmlRouter().getSortnum()
                        - o2.getFromXmlRouter().getSortnum();
            }
        });
        sortNodes.addAll(tmpNode);

        nextNodes = sortNodes;
    }

    // =================================================================================
    /**
     * 提交成功后执行 用于子流程结束时,对主流程的修改
     *
     * @param nextNodes2
     */
    private boolean actionSuccess(List<INextNode> nextNodes2) {
        // 下一节点列表为空直接返回
        if (CollectionUtil.isListEmpty(nextNodes2) || isNotSaveToDB) {
            return true;
        }
        for (int i = 0, n = nextNodes2.size(); i < n; i++) {
            INextNode nextNode = nextNodes2.get(i);
            int nextNodeType = nextNode.getFlowNode().getNodetype();
            if (ac.isEndNode(nextNodeType)) {
                // 2016-03-17 liys 实例结束的情况下,对其他活动分支进行关闭
                if (ac.isEndInstanceNode(nextNodeType)) {
                    if(nextNodes2.size()>1){
                        msg=pubInfo.getInfo("Action_Msg0014", "下节点路由包含实例结束节点不允许多选");
                        return false;
                    }
                    runningdata.cancelOtherTrackForEndInstance(getCurTrackid());
                }
            } else if (nextNodeType == NodeTypeEnum.Node_Mutual) {
                // 引擎交互节点,
                if (!doWithMutualNode(nextNode)) {
                    return false;
                }
            } else if (nextNodeType == NodeTypeEnum.Node_Sub) {
                // 子流程节点,内嵌子流程时的处理
                if (!doWithInnerSubFlow(nextNode)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 引擎交互节点时,处理数据和相关任务
     *
     * @param node
     * @return
     */
    private boolean doWithMutualNode(INextNode node) {
        // 放到ActionExtraData.doWithNextNodesExtraData(RunningData,
        // List<Object>)中处理
        // 此处无法获确定trackid
        return true;
    }

    /**
     * 内嵌子流程启动处理
     *
     * @param node
     * @return
     */
    private boolean doWithInnerSubFlow(INextNode node) {
        // 放到ActionExtraData.doWithNextNodesExtraData(RunningData,
        // List<Object>)中处理
        return true;
    }

    /**
     * 给task表添加数据
     */
    public Map<String, List<Object>> actionForTask() {
        runningdata.putMsgToConsole("[msg]actionForTask start.");
        Map<String, List<Object>> saveMap = new LinkedHashMap<String, List<Object>>();
        if (!isMakeTaskData) {// 不执行task表的写入
            return saveMap;
        }
        if (isNotSaveToDB
                || paraBean.getFunname().equals(
                StaticVarExtend.OPERATOR_FUNNAME_URGE)) {
            return saveMap;
        }
        // 流程结束,无论是否配置删除版本,task都需要清理
        if (runningdata.isFlowEnd()) {
            // 20161122 liys 子流程结束时,对主流程的处理,由actionSuccess方法中移动到此处
            // 可以避免子流程只是分支结束时,也对主流程的处理
            subflowEnd = new SubflowEnd(this);
            if (!subflowEnd.doWithSubFlowEnd()) {
                // 结束节点时的额外处理
                runningdata.setResultCode(StaticVarExtend.F_STATUS_OtherError);
                return null;
            }

//			List<Object> para = new ArrayList<Object>(1);
//			para.add(runningdata.getInitData().getWorkid());
//			List<Object> lst = new ArrayList<Object>();
//			lst.add(para);
//			saveMap.put(
//					("DELETE FROM " + StaticVarExtend.Table_Task + " WHERE WORKID=? "),
//					lst);
            DBTask.delSQLByWorkid(saveMap, runningdata.getResultJson(), runningdata.getWork().getId());
            return saveMap;
        }
        actionForTask(saveMap);
        // 下一节点任务创建
        for (int i = 0, n = runningdata.getNextTrackList().size(); i < n; i++) {
            DBTrack tTrack = runningdata.getNextTrackList().get(i);
            createTaskObj(null, tTrack, saveMap);
        }
        runningdata.putMsgToConsole("[msg]actionForTask end.");
        return saveMap;
    }

    // =================================================================================
    /**
     * 取消分支时调用
     */
    public void cancelTrackAction(String cancelTrackids, List<DBWorkAuth> auths) {
        if (isNotSaveToDB) {
            return;
        }
        makeSendInfoByCurAuthList(auths);
    }

    /**
     * 当取消某个路径的激活状态时,对应的权限变化规则设定<br>
     * (比如把待办的状态改为只读,或者是删除,或者忽略)<br>
     * 如果不指定,则忽略权限变更(比如Reader不需要处理)<br>
     * 主要用于合并节点提交时,如果有其他分支未到达时,对未到达的分支的参与者进行处理<br>
     *
     * @return key=修改前的权限名称(比如:办理人Author),value=修改后的权限名称(比如:只读权限CReader)
     */
    public Map<String, String> getCancelTrackAuthRuleMap() {
        Map<String, String> map = new HashMap<String, String>();
        if (!isNotSaveToDB) {
            // 取消其他分支时,哪些权限需要变更,在map中设置即可
            map.put(StaticVarExtend.AUTH_AUTHOR, StaticVarExtend.AUTH_CREADER);
            map.put(StaticVarExtend.AUTH_SECOND_AUTHOR,
                    StaticVarExtend.AUTH_CREADER);
            map.put(StaticVarExtend.AUTH_START_HUIQIAN_AUTHOR,
                    StaticVarExtend.AUTH_CREADER);
            map.put(StaticVarExtend.AUTH_HUIQIAN_AUTHOR,
                    StaticVarExtend.AUTH_CREADER);
            map.put(StaticVarExtend.AUTH_SUBFLOW_AUTHOR,
                    StaticVarExtend.AUTH_CREADER);
        }
        return map;
    }

    /**
     * 当前节点权限处理(由操作再次干预参与者的接口)<br>
     * auths列表中为系统节点默认处理完毕后的当前节点的参与者列表 对应的消息是否需要处理,可以在这个方法中写
     */
    public boolean chgCurNodeAuth(List<DBWorkAuth> auths) {
        if (CollectionUtil.isListNotEmpty(auths)) {
            makeSendInfoByCurAuthList(auths);
        }
        // 20160719 liys 从execute方法中移动此处,解决异步拿回后再次提交时,出现新的分支问题
        runningdata.getCurTrack().setFlowstatus(
                StaticVarExtend.FlowStatus_Normal);
        return true;
    }

    /**
     * 保存数据之前的接口方法.例如:消息数据的处理 key=sql,value=parameter
     */
    public Map<String, List<Object>> actionBeforeSaveToDB() {
        Map<String, List<Object>> saveMap = new LinkedHashMap<String, List<Object>>();
        if (!StaticFunExtend.getActionExtraData()
                .doWithNextNodesExtraData(this)) {
            return null;
        }
        if (subflowEnd != null) {
            if (!subflowEnd.mainInstanceContinue(saveMap, getTaskLists())) {
                return null;
            }
        }
        // 20180312 liys 增加记录:当前节点的已办权限设置的表单信息
        // 用于满足不同节点的主办提交后变成已办时能显示跟主办节点相关的表单信息
        // 用于在打开实例时,如果是已办从这个记录中获取之前主办节点时的设置信息
        if (HZResourceBundle.getInstance().isDoneAuthFormAuthorNode()) {
            recodeDoneAuthForCurUserInCurNode(saveMap);
        }

        if (isSendTodo) {
            sendTodo();
        }
        actionBefore(saveMap);

        actionBeforeForSubFlow(saveMap);

        return saveMap;
    }

    private void recodeDoneAuthForCurUserInCurNode(
            Map<String, List<Object>> saveMap) {
        if ("Start".equals(getCurNodeid())) {
            return;
        }
        // 获取已办权限信息
        IFlowNode curNodeXml = getCurFlowNode();
        INodeControl doneControl = curNodeXml
                .getParticipantsControl(StaticVarExtend.AUTH_DONE + "_DO");
        if (doneControl == null) {
            return;
        }
        List<INodeForm> doneForms = doneControl.getAllNodeForms();
        boolean isHaveTrack = false;
        boolean isAgent = StringUtilExtend.isNotNull(getCurUser().getAgentUser());
        for (INodeForm form : doneForms) {
            String formId = form.getFormid();
            if ("FlowTrack".equals(formId)) {
                isHaveTrack = true;
                continue;
            }

            // 记录当前节点,当前人,权限
            makeDone(form, saveMap, isAgent);
        }
        if (isHaveTrack) {
            makeDone(null, saveMap, isAgent);
        }
    }

    private void makeDone(INodeForm form, Map<String, List<Object>> saveMap,
                          boolean isAgent) {
        DBDone done = new DBDone();
        done.setId(StaticFunExtend.getUnid());
        done.setWorkid(getWorkid());
        done.setNodeid(getCurNodeid());
        done.setUserid(getCurUserid());
        done.setFormid(form == null ? "FlowTrack" : form.getFormid());
        done.setFormbutton(form == null ? "" : form.getFormButton());
        done.setFieldauthid(form == null ? "" : form.getRealFormid());
        done.getSQL(saveMap,runningdata.getResultJson());

        if (isAgent) {
            done.setId(StaticFunExtend.getUnid());
            done.setUserid(getCurUser().getAgentUser());
            done.getSQL(saveMap,runningdata.getResultJson());
        }
    }

    /**
     * 保存之后的接口方法.例如:消息数据的更新
     */
    public void actionAfterSaveToDB() {
        if (isNotSaveToDB) {
            return;
        }
        // 处理多人并行节点，没有离开节点的情况下，不触发“待办变已办”方法的问题;
        // https://www.huizhengsoft.com/hznetwork/support/know/jump.html?pageId=HZ2881ea7b9f1fde017b9f4333b702c7&formDataId=HZ28831d934da6a4019370bdf42d331a
        actionStartTodoThread();
//         if (isSendTodo) {
//             actionStartTodoThread();
//         }
        actionAfterForSubFlow();
        // 发送定时任务
        super.actionAfterSaveToDB();
        //操作执行完毕后的事件执行
        executeEventAfterToDB();
    }

    /**
     * 发送待办(可继承重写)
     */
    protected void sendTodo() {
        sendTodoForSelectedUsers();
    }

}
