package cn.myapps.runtime.rest.workflow.service;

import static cn.myapps.runtime.workflow.FlowType.START2RUNNING;

import java.util.*;

import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import cn.myapps.base.web.WebUser;
import cn.myapps.common.auth.IUser;
import cn.myapps.common.dao.workflow.definition.FileSystemBillDefiDAO;
import cn.myapps.common.data.ParamsTable;
import cn.myapps.common.model.workflow.BillDefiVO;
import cn.myapps.common.util.StringUtil;
import cn.myapps.designtime.common.service.DesignTimeServiceManager;
import cn.myapps.designtime.workflow.definition.service.BillDefiDesignTimeService;
import cn.myapps.runtime.common.service.RunTimeServiceManager;
import cn.myapps.runtime.dynaform.document.model.IDocument;
import cn.myapps.runtime.workflow.element.AutoNode;
import cn.myapps.runtime.workflow.element.CompleteNode;
import cn.myapps.runtime.workflow.element.EndNode;
import cn.myapps.runtime.workflow.element.FlowDiagram;
import cn.myapps.runtime.workflow.element.ManualNode;
import cn.myapps.runtime.workflow.element.Node;
import cn.myapps.runtime.workflow.element.StartNode;
import cn.myapps.runtime.workflow.element.SubFlow;
import cn.myapps.runtime.workflow.element.SuspendNode;
import cn.myapps.runtime.workflow.engine.StateMachine;
import cn.myapps.runtime.workflow.engine.StateMachineUtil;
import cn.myapps.runtime.workflow.storage.runtime.ejb.FlowRuntimeService;
import cn.myapps.runtime.workflow.storage.runtime.ejb.FlowRuntimeServiceImpl;
import cn.myapps.runtime.workflow.storage.runtime.ejb.FlowStateRT;
import cn.myapps.runtime.workflow.storage.runtime.ejb.NodeRT;
import cn.myapps.runtime.workflow.storage.runtime.ejb.TaskInfoProcess;

@Service
public class WorkflowQueryServiceImpl implements WorkflowQueryService {

	@Override
	public JSONObject queryWorkflow(String applicationId, String instanceId) throws Exception {
		FlowRuntimeService flowStateRTProcess = new FlowRuntimeServiceImpl( applicationId);

		FlowStateRT flowInstance = (FlowStateRT) flowStateRTProcess.findFlowStateRT(instanceId);
		if (flowInstance == null) {
			return new JSONObject();
		}
		IDocument doc = flowInstance.getDocument();
		JSONArray result = new JSONArray();
		if (!StringUtil.isBlank(doc.getStateid()) && !StringUtil.isBlank(doc.getStateLabel())) {
			String stateLabelInfo = doc.getStateLabelInfo();
			result = JSON.parseArray(stateLabelInfo);
			if (result.size() > 0) {
				JSONObject stateLabelInfoJSON = result.getJSONObject(0);
				JSONArray nodes = stateLabelInfoJSON.getJSONArray("nodes");
				if (nodes.size() > 0) {
					JSONObject node = nodes.getJSONObject(0);
					/* 兼容旧数据 */
					if (!node.containsKey("auditors")) {
						return new JSONObject();
					}
				}
				return stateLabelInfoJSON;
			}
		}
		return new JSONObject();
	}

	@Override
	public JSONObject submissionPanels(String applicationId, IDocument doc, WebUser user, String flowId,
			String instanceId, ParamsTable params) throws Exception {

		FlowRuntimeService stateProcess = new FlowRuntimeServiceImpl( applicationId);

		if (StringUtil.isBlank(instanceId)) {
			if (!StringUtil.isBlank(flowId)) {

				BillDefiDesignTimeService billDefiService = DesignTimeServiceManager.billDefiDesignTimeService();

				BillDefiVO flowVO = (BillDefiVO) billDefiService.doView(flowId);
				Node firstNode = StateMachine.getFirstNode(doc, flowVO, user, params);

				if (firstNode != null) {
					FlowStateRT state = stateProcess.createTransientFlowStateRT(doc, flowId, user);
					ArrayList<NodeRT> noderts = new ArrayList<NodeRT>();
					NodeRT nodert = new NodeRT(state, firstNode, START2RUNNING);
					noderts.add(nodert);
					state.setNoderts(noderts);

					doc.setState(state);// 创建瞬态流程实例
					doc.setInitiator(user.getId());// 设置流程发起人
				}
			}
		}
		if (doc != null) {
			FlowStateRT instance = stateProcess.getCurrFlowStateRT(doc, user, instanceId);
			BillDefiVO flowVO = instance.getFlowVO();
			NodeRT nodert = null;
			String currNodeId = null;
			FlowDiagram fd = null;
			if (flowVO != null) {
				fd = flowVO.toFlowDiagram();
				if (instance.isTemp()) {
					nodert = ((List<NodeRT>) instance.getNoderts()).get(0);
					currNodeId = nodert.getNodeid();
				}

				if (currNodeId == null && nodert == null) {
					doc.setState(instance);
					nodert = StateMachine.getCurrUserNodeRT(doc, user, currNodeId);
					if (nodert != null)
						currNodeId = nodert.getNodeid();
				}
			}
			// 获取当前结点
			Node currnode = null;
			if (currNodeId != null) {
				currnode = (Node) fd.getElementByID(currNodeId);
			}

			boolean issplit = false;
			int nextNodeCheckedStatus = ManualNode.NEXT_NODE_CHECKED_STATUS_CHECKED;
			boolean isAppentCirculator = false;

			if (currnode instanceof ManualNode) {
				issplit = ((ManualNode) currnode).issplit;
				nextNodeCheckedStatus = ((ManualNode) currnode).nextNodeCheckedStatus;
			} else if (currnode instanceof AutoNode) {
				issplit = ((AutoNode) currnode).issplit;
			}

			JSONObject json = new JSONObject();
			json.put("currentNodeId", currNodeId);
			json.put("isSplit", issplit);
			json.put("splitToken", currNodeId);
			json.put("flowId", flowVO.getId());
			if ((currnode instanceof ManualNode) && ((ManualNode) currnode).isCarbonCopy
					&& ((ManualNode) currnode).isSelectCirculator && !isAppentCirculator) {
				json.put("isAppentCirculator", true);
			}
			if ((currnode instanceof ManualNode) && ((ManualNode) currnode).isToPerson) {
				json.put("isToPerson", true);
			}
			Collection<Node> nextNodeList = fd.getNextNodeList(currnode.id, doc, params, user);

			JSONArray nextNodeListjson = new JSONArray();
			for (Node node : nextNodeList) {
				JSONObject nodejson = new JSONObject();
				nodejson.put("id", node.id);
				nodejson.put("name", node.name);

				if (node instanceof AutoNode) {
					nodejson.put("type", "AutoNode");
				} else if (node instanceof ManualNode) {
					nodejson.put("type", "ManualNode");
				} else if (node instanceof CompleteNode) {
					nodejson.put("type", "CompleteNode");
				} else if (node instanceof EndNode) {
					nodejson.put("type", "EndNode");
				} else if (node instanceof StartNode) {
					nodejson.put("type", "StartNode");
				} else if (node instanceof SubFlow) {
					nodejson.put("type", "SubFlow");
				} else if (node instanceof SuspendNode) {
					nodejson.put("type", "SuspendNode");
				}

				switch (nextNodeCheckedStatus) {
				case ManualNode.NEXT_NODE_CHECKED_STATUS_CHECKED:// 默认选中
					nodejson.put("checked", true);
					nodejson.put("locked", false);
					break;
				case ManualNode.NEXT_NODE_CHECKED_STATUS_UNCHECKED:// 默认不选中
					nodejson.put("checked", false);
					nodejson.put("locked", false);
					break;
				case ManualNode.NEXT_NODE_CHECKED_STATUS_CHECKED_AND_LOCKED:// 默认选中且锁定
					nodejson.put("checked", true);
					nodejson.put("locked", true);
					break;
				default:
					break;
				}

				nextNodeListjson.add(nodejson);
			}

			json.put("nextNodes", nextNodeListjson);
			return json;
		} else {
			return null;
		}
	}

	@Override
	public JSONObject backPanels(String applicationId, String instanceid, WebUser user) throws Exception {

		FlowRuntimeService flowStateRTProcess = new FlowRuntimeServiceImpl( applicationId);
		FlowStateRT instance = (FlowStateRT) flowStateRTProcess.findFlowStateRT(instanceid);

		if (instance != null) {
			IDocument doc = instance.getDocument();
			doc.setApplicationid(applicationId);
			BillDefiVO flowVO = instance.getFlowVO();

			NodeRT nodert = null;
			String currNodeId = null;
			FlowDiagram fd = null;
			if (flowVO != null) {
				fd = flowVO.toFlowDiagram();
				if (currNodeId == null && nodert == null) {
					nodert = StateMachine.getCurrUserNodeRT(doc, user, currNodeId);
					if (nodert != null)
						currNodeId = nodert.getNodeid();
				}
			}
			// 获取当前结点
			Node currnode = null;
			if (currNodeId != null) {
				currnode = (Node) fd.getElementByID(currNodeId);
			}

			JSONObject json = new JSONObject();
			json.put("currentNodeId", currNodeId);
			json.put("splitToken", currNodeId);
			json.put("flowId", flowVO.getId());

			Collection<Node> backNodeList = null;
			if (((ManualNode) currnode).backType == 1 && ((ManualNode) currnode).cBack) {
				backNodeList = StateMachine.getBackToNodeList(flowVO, nodert, user, 0);
			} else if (((ManualNode) currnode).backType == 0 && ((ManualNode) currnode).cBack) {
				backNodeList = StateMachine.getBackToNodeList(doc, flowVO, nodert, user, 0);
			} else if (((ManualNode) currnode).retracementScript == null) {// 兼容旧版本
				backNodeList = StateMachine.getBackToNodeList(doc, flowVO, nodert, user, 0);
			}

			JSONArray nodeListjson = new JSONArray();
			for (Node node : backNodeList) {
				JSONObject nodejson = new JSONObject();
				nodejson.put("id", node.id);
				nodejson.put("name", node.name);
				nodejson.put("type", node.getClass().getSimpleName());
				nodeListjson.add(nodejson);
			}
			json.put("backNodes", nodeListjson);
			return json;
		}
		return null;
	}

	@Override
	public JSONObject taskInfo(String instanceid, WebUser user, String applicationid) throws Exception {
		String userName = user.getName();
		TaskInfoProcess process = RunTimeServiceManager.taskInfoProcess(applicationid);
		Collection<NodeRT> collection = process.queryTask(instanceid, userName);
		JSONArray nextNodeListjson = new JSONArray();
		for (NodeRT nodeRT : collection) {
			JSONObject nodejson = new JSONObject();
			nodejson.put("NodeRTId", nodeRT.getId());
			nodejson.put("NodeRTName", nodeRT.getName());
			nodejson.put("flowStateRTId", nodeRT.getFlowstatertid());
			nodejson.put("Deadline", nodeRT.getDeadline());
			nodejson.put("position", nodeRT.getPosition());
			nodejson.put("reminderTime", nodeRT.getReminderTimes());
			nodejson.put("StateLabel", nodeRT.getStatelabel());
			nodejson.put("FlowOption", nodeRT.getFlowoption());
			nodejson.put("SplitToken", nodeRT.getSplitToken());
			nextNodeListjson.add(nodejson);
		}
		JSONObject json = new JSONObject();
		json.put("NodeRTInfo", nextNodeListjson);
		return json;
	}

	@Override
	public JSONObject taskNum(String instanceid, WebUser user, String applicationid) throws Exception {
		String userName = user.getName();
		TaskInfoProcess process = RunTimeServiceManager.taskInfoProcess(applicationid);
		int num = process.queryTaskNum(instanceid, userName);
		JSONObject numJsonObject = new JSONObject();
		numJsonObject.put("number", num);
		return numJsonObject;
	}

	@Override
	public JSONObject getNodeRT(String instanceid, String nodeRTId, String applicationId) throws Exception {
		FlowRuntimeService process = new FlowRuntimeServiceImpl(applicationId);
		Collection<Map<String, String>> collection = process.queryActorRTByNoderRTAndFlowInstanceId(nodeRTId, instanceid);
		JSONObject numJsonObject = new JSONObject();
		numJsonObject.put("actor", collection);
		return numJsonObject;
	}

	@Override
	public JSONObject getAllActor(WebUser user, ParamsTable params, String applicationId, String nodeId, String flowId,
			String instanceId) throws Exception {
		JSONObject result = new JSONObject();
		JSONArray jsonArray = new JSONArray();
		Node nodeCh = null;
		try {
			FlowRuntimeService flowStateRTProcess = new FlowRuntimeServiceImpl(applicationId);
			FlowStateRT flowInstance = (FlowStateRT) flowStateRTProcess.findFlowStateRT(instanceId);
			IDocument doc = flowInstance.getDocument();
			doc.setState(flowInstance);
			FileSystemBillDefiDAO billDefiDAO = new FileSystemBillDefiDAO(BillDefiVO.class);
			BillDefiVO billDefiVO = billDefiDAO.findById(flowId);
			Collection<Node> collectionNode = billDefiVO.getAllExecuteableNodes();
			for (Node node : collectionNode) {
				String id = node.id;
				if (id.equals(nodeId)) {
					nodeCh = node;
					break;
				}
			}

			Collection<IUser> collection = StateMachineUtil.getPrincipalList(doc, params, nodeCh, user.getDomainid(),
					applicationId, user);
			for (IUser baseUser : collection) {
				JSONObject userJson = new JSONObject();
				userJson.put("id", baseUser.getId());
				userJson.put("name", baseUser.getName());
				userJson.put("userCode",baseUser.getLoginno());
				jsonArray.add(userJson);
			}
			result.put("actor", jsonArray);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result ;
	}

	@Override
	public List<NodeRT> remindPanels(String applicationId, WebUser user, String instanceId) throws Exception {
		FlowRuntimeService flowStateRTProcess = new FlowRuntimeServiceImpl( applicationId);
		FlowStateRT instance = flowStateRTProcess.findFlowStateRT(instanceId);
		List<NodeRT> list = new ArrayList<NodeRT>();
		if(instance.isTemp() || instance.isTerminated()) return list;
		// 获取当前流程实例的节点(nodeRT)
		Collection<NodeRT> noderts = flowStateRTProcess.doQueryNodeRT(instanceId);
		//获取当前NodeRT对应的ManualNode对象
		BillDefiVO flowVO = instance.getFlowVO();
		FlowDiagram fd = flowVO.toFlowDiagram();
		for (Iterator<NodeRT> iterator = noderts.iterator(); iterator.hasNext();) {
			NodeRT nodeRT = iterator.next();
			if (nodeRT.getActorIdList().contains(user.getId())) {
				continue;
			}
			Node node =fd.getNodeByID(nodeRT.getNodeid());
			if(node instanceof ManualNode){
				if(((ManualNode)node).isAllowUrge2Approval(instance.getDocument(), new ParamsTable(), user)){
					list.add(nodeRT);
				}
			}
		}
		return list;
	}
}
