package com.horizon.wf.action;

import com.horizon.common.collect.Lists;
import com.horizon.db.Access;
import com.horizon.wf.action.base.BaseForTask;
import com.horizon.wf.action.base.IActionForStartSubFlow;
import com.horizon.wf.core.node.INextNode;
import com.horizon.wf.core.node.ITaskNode;
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.entity.db.DBTrack;
import com.horizon.wf.entity.db.DBWorkAuth;
import com.horizon.wf.global.CollectionUtil;
import com.horizon.wf.global.StaticFunExtend;
import com.horizon.wf.global.StaticVarExtend;
import com.horizon.wf.tools.CStrUtil;

import java.util.*;

/**
 * 二、节点间任意退回操作实现类
 * 1.需要指定退回节点
 * 2.可前台指定是否连带退回其他分支节点
 * @author liys
 * @version 1.0
 * @since v7.0
 */
public class ActionRejectByJump extends BaseForTask implements ICustomAction,IActionForStartSubFlow {
    public boolean execute(ITaskNode curTaskNode){

        //2023-12-5 add 增加退回给申请人功能
        List cusNextNodeList = Lists.newArrayList();
        if (paraBean.getFunname().equals("jumprejectstart")) {
            String sql = "select * from tw_hz_log where workid = ? and nodeid= 'Start' and action = 'autofirst'";
            List param = Lists.newArrayList();
            param.add(paraBean.getWorkId());
            Map map = Access.getSingleMap(sql, param, paraBean.getDataIdentifier());
            if (null != map && !map.isEmpty()) {
                cusNextNodeList = Arrays.asList(map.get("nextnodeids").toString().split(";"));
            }
        }
        if (null == cusNextNodeList || cusNextNodeList.isEmpty()) {
            initNextNodePara();//初始化下一节点信息
        } else {
            nextNodeList = cusNextNodeList;
        }
        //edit 放到上面if中做判断
        //initNextNodePara();//初始化下一节点信息
        //2023-12-5  end

        // initNextNodePara();//初始化下一节点信息
        runningdata.setFunname(StaticVarExtend.OPERATOR_FUNNAME_JUMP_REJECT);
        setActionname("Reject_Msg1001","任意退回");
        DBTrack track = getCurTrack();
        if(null == nextNodeList || nextNodeList.isEmpty()){
            runningdata.putMsgToConsole("[msg]goto operator need select node!");
            result = StaticVarExtend.F_STATUS_SelectNode;
            msg = pubInfo.getInfo("Reject_Msg1002","请选择退回节点");
            resultBean.setNextNodes(getRejectNodes());
        }
        else{
            List<INextNode> nextNodes = chgSelectedNode();
            if(!isAllowReject(nextNodes)){
                result = StaticVarExtend.F_STATUS_OtherError;
                msg = pubInfo.getInfo("Reject_Msg1006","指定的节点不允许退回");
            }
            //获取退回节点的办理人
            else{
                executeReject(curTaskNode);
                nextNodes = curTaskNode.getGNextNodes();

                if(StaticVarExtend.F_STATUS_Success == result){

                    doWithNextNodeResult(false);
                    if(StaticVarExtend.F_STATUS_Success == result){
                        msg = pubInfo.getInfo("Reject_Msg1003","任意退回成功");
                        doWithCurNodeAuth();
                        track.setEnd(true);//结束当前节点
                        ac.dowithTimer("cancel", getCurNodeType(), runningdata, getIdentifier());//如果当前节点包含定时任务则撤销定时任务
                        if(executeEventSave()){
//							selectedUsers = ac.makeAgentUser(selectedUsers, runningdata);
                            runningdata.setUpdateTask(true);
                            runningdata.setTitle(paraBean.getTitle());//设置待办发送的标题
                        }

                        memoBuffer.append(pubInfo.getInfo("Reject_Msg1004","任意退回到节点"));
                        for(int i=0,n=nextNodes.size();i<n;i++){
                            doMemoFromSelected(nextNodes.get(i));
                        }

                        //如果选择多个退回节点则不支持连带,最后保存数据时执行,下一节点是当前节点时,不执行连带功能
                        if(nextNodes.size() == 1 && runningdata.isContinueSave()
                                && (!nextNodes.get(0).getNodeid().equals(curTaskNode.getNodeid()))){
                            //增加判断是否连带退回
                            boolean rejectOtherBranch = false;
                            boolean isContinueGet = false;//是否继续从其他地方获取
                            String tmpFlag = paraBean.getRejectOtherBranch();
                            if(tmpFlag == null || "".equals(tmpFlag)){
                                isContinueGet = true;
                            }
                            else{
                                rejectOtherBranch = "1".equals(tmpFlag);
                            }
                            //如果前台未设置,则从配置文件中获取
                            if(isContinueGet){
                                rejectOtherBranch = "1".equals(runningdata.getCurFlowNode().getRejectOtherBranch());
                            }
                            //测试代码
                            if(rejectOtherBranch){
                                String cancelname = runningdata.closeBranchFromRejectNode(nextNodes.get(0).getNodeid());
                                if(CStrUtil.isNotNull(cancelname)){
                                    memoBuffer.append(pubInfo.getInfo("Reject_Msg1005",",连带退回节点(|nodename|)")
                                            .replace("|nodename|", cancelname.substring(1)));
                                }
                            }
                        }
                    }
                }
            }
            if(CollectionUtil.isListNotEmpty(nextNodes)){
                resultBean.setNextNodes(nextNodes);
            }
        }

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

    /**
     * 获取可以退回的节点
     * @return
     */
    private List<INextNode> getRejectNodes(){
        runningdata.putMsgToConsole("[msg]get goto nodes start.");
        List<IFlowNode> nodes = new ArrayList<IFlowNode>();
        //获取所有跟当前分支相关的已办理节点,包含上一路径下的节点
        String[] alldonenodes = runningdata.getAllDoneNodes(getCurTrack().getId())
                .split(StaticVarExtend.StrSplitChar);
        IFlowInfo fInfo = runningdata.getInstanceDefinition().getFlowinfo();
        String curNodeid = getCurNodeid();
        List<String> allRejectNodes = getRejectNode();
        //去掉当前节点
        for(String n:alldonenodes){
            IFlowNode node = fInfo.getNodeById(n);
            if(null==node)continue;
            int nodetype = node.getNodetype();
            //去掉当前节点,结束节点,自动节点，事件节点，网关节点,开始节点
            if(curNodeid.equals(node.getNodeid())){continue;}
            //20200508 LIYS 增加任意退回的范围限制
            if(ac.isNormalNode(nodetype) &&
                    (allRejectNodes == null || allRejectNodes.contains(node.getNodeid()))){
                runningdata.putMsgToConsole("[msg]reject to node:"+node.getNodeid());
                nodes.add(node);
            }
        }
        runningdata.putMsgToConsole("[msg]get reject nodes end.");
        return runningdata.chgXmlNodeToNextNode(nodes);
    }

    /**
     * 获取退回节点的限制列表
     * @return
     */
    private List<String> getRejectNode(){
        IFlowNode node = runningdata.getCurFlowNode();
        INodeControl control = node.getParticipantsControl(StaticVarExtend.AUTH_AUTHOR);
        String allNodes = "";
        if(null != control){
            allNodes = control.getAllowRejectNode();
        }
        if(CStrUtil.isNull(allNodes)){
            return null;
        }
        return Arrays.asList(allNodes.split(";"));
    }

    /**
     * 把选择的返回节点转换成需要的列表
     * @return
     */
    private List<INextNode> chgSelectedNode(){
        List<IFlowNode> nodes = new ArrayList<IFlowNode>();
        IFlowInfo fInfo = runningdata.getInstanceDefinition().getFlowinfo();
        for(String n:nextNodeList){
            IFlowNode node = fInfo.getNodeById(n);
            nodes.add(node);
        }
        return runningdata.chgXmlNodeToNextNode(nodes);
    }

    /**
     * 判断选择的节点是否是允许回退的节点类型
     * @param nodes
     * @return true: 允许回退
     */
    private boolean isAllowReject(List<INextNode> nodes){
        List<String> allRejectNodes = getRejectNode();
        for(int i=0,n=nodes.size();i<n;i++){
            INextNode node = nodes.get(i);
            int nodetype = node.getFlowNode().getNodetype();
            if(!ac.isNormalNode(nodetype) || (null!=allRejectNodes && !allRejectNodes.contains(node.getNodeid())) ){
                runningdata.putMsgToConsole("[msg]reject nodetype:"+nodetype+",nodeid"+node.getNodeid()+",nodename:"+node.getNodename());
                return false;
            }
        }
        return true;
    }

    private void executeReject(ITaskNode curTaskNode) {
        //执行回退
        curTaskNode.rejectToPrevNode(nextNodeList, selectedUsers);
        INextNode curNode = curTaskNode.getCurNode();
        result = curNode.getInitResult();
        msg = curNode.getBackMsg();
    }

    /**
     * 处理当前节点参与者权限
     */
    private void doWithCurNodeAuth() {
        List<DBWorkAuth> auths = runningdata
                .getListAuthLikeAuthorByTrackid(getCurTrack().getId());
        if(CollectionUtil.isListNotEmpty(auths)){
            for(int i=0,n=auths.size();i<n;i++){
                DBWorkAuth auth = auths.get(i);
                if(auth.equalsRunUser(getCurUser())){
                    auth.setStatus(StaticVarExtend.AUTH_DONE);
                }
                else{
                    auth.setStatus(StaticVarExtend.AUTH_CREADER);
                }
            }
        }
        runningdata.setCurAuthToMap(auths);
    }

    public Map<String,List<Object>>  actionForTask() {
        Map<String, List<Object>> saveMap = new LinkedHashMap<String, List<Object>>();
        actionForTask(saveMap);
        //下一节点任务创建
        for(int i=0,n=runningdata.getNextTrackList().size();i<n;i++){
            DBTrack tTrack = runningdata.getNextTrackList().get(i);
            createTaskObj(null,tTrack,saveMap);
        }
        return saveMap;
    }
    /**
     * 取消分支时调用,在需要调用的操作中重写该类
     * @param trackids 要取消的分支id，多个用“；”隔开
     */
    public void cancelTrackAction(String trackids, 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.put(StaticVarExtend.AUTH_AUTHOR, StaticVarExtend.AUTH_CREADER);
            map.put(StaticVarExtend.AUTH_SECOND_AUTHOR, StaticVarExtend.AUTH_CREADER);
            map.put(StaticVarExtend.AUTH_SUBFLOW_AUTHOR, StaticVarExtend.AUTH_CREADER);
            map.put(StaticVarExtend.AUTH_HUIQIAN_AUTHOR,StaticVarExtend.AUTH_CREADER);
            map.put(StaticVarExtend.AUTH_START_HUIQIAN_AUTHOR,StaticVarExtend.AUTH_CREADER);
        }
        return map;
    }
    /**
     * 保存之后的接口方法.例如:消息数据的更新
     */
    public void actionAfterSaveToDB() {
        if(isNotSaveToDB){
            return;
        }
        actionStartTodoThread();
        //发送定时任务
        super.actionAfterSaveToDB();
    }
    /**
     * 保存数据之前的接口方法.例如:消息数据的处理
     * 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;
        }
        sendTodo();
        actionBefore(saveMap);
        return saveMap ;
    }
    /**
     * 当前节点权限处理(由操作再次干预参与者的接口)<br>
     * auths列表中为系统节点默认处理完毕后的当前节点的参与者列表
     * 对应的消息是否需要处理,可以在这个方法中写
     */
    public boolean chgCurNodeAuth(List<DBWorkAuth> auths) {
        if(CollectionUtil.isListNotEmpty(auths)){
            makeSendInfoByCurAuthList(auths);
        }
        return true;
    }
    /**
     * 发送待办
     */
    protected void sendTodo(){
        sendTodoForSelectedUsers();
    }
}
