package com.blueland.bpm.manage.web;

/**
 * 流程监控
 * @version: 1.0
 * @author lw
 */
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.blueland.bpm.common.util.SysConfig;
import com.blueland.bpm.engine.config.model.ProcessInfoConfig;
import com.blueland.bpm.engine.config.service.ProcessInfoConfigManager;
import com.blueland.bpm.engine.core.model.ProcessInstanceModel;
import com.blueland.bpm.engine.core.service.ProcessInstanceService;
import com.blueland.bpm.engine.core.service.ProcessTraceService;
import com.blueland.bpm.manage.util.CheckMobile;

@Controller
@RequestMapping({ "/workflow/trace" })
public class ProcessTraceController extends BaseProcessController {
	@Autowired
	private ProcessTraceService processTraceService;
	@Autowired
	private ProcessInfoConfigManager processInfoConfigManager;
	@Autowired
	private ProcessInstanceService processInstanceService;
	private String tracePicFix="/bpmc/resource/js/plugins/zTree/css/zTreeStyle/img/diy";
	/**
	 * 流程监控总入口
	 * @param traceType
	 * @param processInstanceId
	 * @param response
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/traceProcess")
	public ModelAndView traceProcessView(String traceType, String processInstanceId, HttpServletResponse response,
			HttpServletRequest request) {
		return traceProcessOldView(traceType, processInstanceId, response, request);
	}

	@RequestMapping({ "/traceByImage" })
	public ModelAndView processTraceImage(String processInstanceId, String imageHeight, String imageWidth,
			String fileId) throws Exception {
		return traceImage(processInstanceId);
		
	}
	
	/**
	 * traceImage中会调用这个方法
	 * @param processInstanceId
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/traceNewByImage")
	@ResponseBody
	public Map<String, Object> processTraceNewImage(String processInstanceId) throws Exception {
		Map<String, Object> result = new HashMap<String, Object>();
		Map<String, Object> hisTaskLog = processTraceService.getCurTaskLog(processInstanceId);
		result.put("hisTaskLog", hisTaskLog);
		result.put("processTrace", processTraceService.getProcessTrace(processInstanceId));
		result.put("processInstance", hisTaskLog.get("curProcessInstance"));
		return result;
	}
	
	/**
	 * 流程监控-文本+图形，暂未上线
	 * 
	 * @param traceType
	 * @param processInstanceId
	 * @param response
	 * @param request
	 * @return
	 */
	public ModelAndView traceProcessNewView(String traceType, String processInstanceId, HttpServletResponse response,
			HttpServletRequest request) {
		ModelAndView modelAndView = new ModelAndView("/trace/traceImageAndText");
		List<HistoricProcessInstance> allProcessInstances = new ArrayList<HistoricProcessInstance>();
		Map<String, Object> hisTaskLog = processTraceService.getHisTaskLog(processInstanceId);
		modelAndView.addObject("hisTaskLog", hisTaskLog);
		List<HistoricProcessInstance> subProcessInstances = processTraceService.getHistoryService()
				.createHistoricProcessInstanceQuery().superProcessInstanceId(processInstanceId)
				.orderByProcessInstanceStartTime().desc().list();
		allProcessInstances.add((HistoricProcessInstance) hisTaskLog.get("curProcessInstance"));
		allProcessInstances.addAll(subProcessInstances);
		modelAndView.addObject("curProcessInstance", hisTaskLog.get("curProcessInstance"));
		modelAndView.addObject("allProcessInstances", allProcessInstances);
		modelAndView.addObject("processInstanceId", processInstanceId);
		return modelAndView;
	}

	/**
	 * 老版本流程监控入口
	 * 
	 * @param traceType
	 * @param processInstanceId
	 * @param response
	 * @param request
	 * @return
	 */
	private ModelAndView 	traceProcessOldView(String traceType, String processInstanceId, HttpServletResponse response,
			HttpServletRequest request) {
		boolean isFromMobile = false;
		try {
			String userAgent = request.getHeader("USER-AGENT").toLowerCase();
			if (userAgent == null) {
				userAgent = "";
			}
			isFromMobile = CheckMobile.check(userAgent);

			if (isFromMobile) {
				return traceProcessMobile(processInstanceId, response);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		ModelAndView modelAndView = new ModelAndView("/trace/traceProcess");
		ProcessInstanceModel processInstance = this.processInstanceService.getProcessInstanceById(processInstanceId);
		modelAndView.addObject("traceType", traceType);
		modelAndView.addObject("processInstanceId", processInstanceId);
		if(processInstance!=null) {
			ProcessInfoConfig processInfoConfig = this.processInfoConfigManager.getById(processInstance.getProcDefId());
			modelAndView.addObject("processInstance", processInstance);
			if (StringUtils.isNotEmpty(processInfoConfig.getArisCode()))
				modelAndView.addObject("arisUrl", SysConfig.getValue("ARIS_URL") + processInfoConfig.getArisCode());
			if (StringUtils.isNotEmpty(processInfoConfig.getArisCode())) {
				modelAndView.addObject("arisCode", processInfoConfig.getArisCode());
			}
		}
		return modelAndView;
	}

	@RequestMapping({ "/traceProcessMobile" })
	public ModelAndView traceProcessMobile(String processInstanceId, HttpServletResponse response) {
		ModelAndView modelAndView = new ModelAndView("/trace/traceProcessMobile");

		ProcessInstanceModel processInstance = this.processInstanceService.getProcessInstanceById(processInstanceId);
		ProcessInfoConfig processInfoConfig = this.processInfoConfigManager.getById(processInstance.getProcDefId());

		List<HistoricProcessInstance> allProcessInstances = new ArrayList();
		HistoricProcessInstance curProcessInstance = (HistoricProcessInstance) this.processTraceService
				.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(processInstanceId)
				.singleResult();
		modelAndView.addObject("curProcessInstance", curProcessInstance);
		List<HistoricProcessInstance> subProcessInstances =

				((HistoricProcessInstanceQuery) this.processTraceService.getHistoryService()
						.createHistoricProcessInstanceQuery().superProcessInstanceId(curProcessInstance.getId())
						.orderByProcessInstanceStartTime().desc()).list();
		allProcessInstances.add(curProcessInstance);
		allProcessInstances.addAll(subProcessInstances);

		Map<String, Object> hisTaskLog = this.processTraceService.getHisTaskLog(processInstanceId);
		modelAndView.addObject("hisTaskLog", hisTaskLog);
		HistoricProcessInstance historicProcessInstance = (HistoricProcessInstance) this.processTraceService
				.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(processInstanceId)
				.singleResult();
		try {
			String[] size = this.processTraceService
					.getProcessDiagramSize(historicProcessInstance.getProcessDefinitionId());
			modelAndView.addObject("imageWidth", size[0]);
			modelAndView.addObject("imageHeight", size[1]);
		} catch (Exception e) {
			e.printStackTrace();
		}

		modelAndView.addObject("allProcessInstances", allProcessInstances);

		modelAndView.addObject("processInstanceId", processInstanceId);
		modelAndView.addObject("processInstance", processInstance);
		modelAndView.addObject("processDefinitonDiv",
				this.processTraceService.getProcessDefinitionDiv(historicProcessInstance.getProcessDefinitionId()));
		if (StringUtils.isNotEmpty(processInfoConfig.getArisCode()))
			modelAndView.addObject("arisUrl", SysConfig.getValue("ARIS_URL") + processInfoConfig.getArisCode());
		return modelAndView;
	}

	/**
	 * 老版本流程监控
	 * 
	 * @param processInstanceId
	 * @param imageHeight
	 * @param imageWidth
	 * @param fileId
	 * @return
	 * @throws Exception
	 */
	private ModelAndView processTraceOldImage(String processInstanceId, String imageHeight, String imageWidth,
			String fileId) throws Exception {
		ModelAndView modelAndView = new ModelAndView("/trace/traceByImage");
		Map<String, Object> hisTaskLog = this.processTraceService.getCurTaskLog(processInstanceId);
		modelAndView.addObject("hisTaskLog", hisTaskLog);
		HistoricProcessInstance historicProcessInstance=(HistoricProcessInstance)hisTaskLog.get("curProcessInstance");
		try {
			String[] size = this.processTraceService
					.getProcessDiagramSize(historicProcessInstance.getProcessDefinitionId());
			modelAndView.addObject("imageWidth", size[0]);
			modelAndView.addObject("imageHeight", size[1]);
		} catch (Exception e) {
			e.printStackTrace();
		}
		modelAndView.addObject("processInstance", historicProcessInstance);
		modelAndView.addObject("procTitle", historicProcessInstance.getProcTitle().replaceAll("\"", "\'"));
		modelAndView.addObject("fileId", fileId);
		modelAndView.addObject("processDefinitonDiv",
				this.processTraceService.getProcessDefinitionDiv(historicProcessInstance.getProcessDefinitionId()));

		return modelAndView;
	}
	
	/**
	 * 流程监控图入口
	 * 
	 * @param processInstanceId
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/traceImage")
	public ModelAndView traceImage(String processInstanceId) throws Exception {
		ModelAndView modelAndView = new ModelAndView("/trace/traceImage");
		modelAndView.addObject("processInstanceId", processInstanceId);
		return modelAndView;
	}

	/**
	 * 新版本流程监控
	 */
	private ModelAndView processTraceNewImage(String processInstanceId, String fileId) throws Exception {
		ModelAndView modelAndView = new ModelAndView("/trace/traceByImage");
		Map<String, Object> hisTaskLog = processTraceService.getCurTaskLog(processInstanceId);
		modelAndView.addObject("hisTaskLog", hisTaskLog);
		HistoricProcessInstance historicProcessInstance=(HistoricProcessInstance)hisTaskLog.get("curProcessInstance");
		modelAndView.addObject("processTrace", processTraceService.getProcessTrace(processInstanceId));
		modelAndView.addObject("processInstance", historicProcessInstance);
		modelAndView.addObject("fileId", fileId);
		return modelAndView;
	}
	
	

	/**
	 * 老版本流程监控-文本
	 * 
	 * @param processInstanceId
	 * @return
	 * @throws Exception
	 */
	@RequestMapping({ "/traceByText" })
	public ModelAndView processTraceText(String processInstanceId) throws Exception {
		ModelAndView modelAndView = new ModelAndView("/trace/traceByText");
		Map<String, Object> hisTaskLog = this.processTraceService.getHisTaskLog(processInstanceId);
		modelAndView.addObject("hisTaskLog", hisTaskLog);
		List<HistoricProcessInstance> allProcessInstances = new ArrayList();
		HistoricProcessInstance curProcessInstance=(HistoricProcessInstance)hisTaskLog.get("curProcessInstance");
		if(curProcessInstance!=null) {
			modelAndView.addObject("procTitle", curProcessInstance.getProcTitle().replaceAll("\"", "\'"));
		}else {
			curProcessInstance=new HistoricProcessInstanceEntity();
		}
			List<HistoricProcessInstance> subProcessInstances =
					((HistoricProcessInstanceQuery) this.processTraceService.getHistoryService()
							.createHistoricProcessInstanceQuery().superProcessInstanceId(curProcessInstance.getId())
							.orderByProcessInstanceStartTime().desc()).list();
			allProcessInstances.add(curProcessInstance);
			allProcessInstances.addAll(subProcessInstances);
			modelAndView.addObject("allProcessInstances", allProcessInstances);
		
		modelAndView.addObject("curProcessInstance", curProcessInstance);
		modelAndView.addObject("processInstanceId", processInstanceId);
		return modelAndView;
	}

	@RequestMapping({ "/processTitleTree" })
	public ModelAndView processTitleTree(String processInstanceId) throws Exception {
		ModelAndView modelAndView = new ModelAndView("/trace/processTitleTree");
		modelAndView.addObject("processInstanceId", processInstanceId);
		return modelAndView;
	}

	/**
	 * 流程监控-子流程使用
	 * 
	 * @param processInstanceId
	 * @return
	 * @throws Exception
	 */
	@RequestMapping({ "/allProcessInstance" })
	@ResponseBody
	public List<TreeNode> allProcessInstance(String processInstanceId) throws Exception {
		List<ProcessInstanceModel> historicProcessInstances = this.processInstanceService
				.getAllProcessInstance(processInstanceId);
		List<TreeNode> treeNodes = new ArrayList();
		for (ProcessInstanceModel hisPro : historicProcessInstances) {
			TreeNode treeNode = null;
			if (StringUtils.isEmpty(hisPro.getParentProcInstId())) {
				if (hisPro.isFinishProcess()) {
					treeNode = new TreeNode(hisPro.getProcInstId(), "-1", hisPro.getProcTitle(), false,
							"NODENOTFINISH");
				} else {
					treeNode = new TreeNode(hisPro.getProcInstId(), "-1", hisPro.getProcTitle(), false, "NODEFINISH");
				}

			} else {
				treeNode = new TreeNode(hisPro.getProcInstId(), hisPro.getParentProcInstId(),
						hisPro.getProcTitle() + "(" + hisPro.getStartUserName() + ")", false, "NODE");
				if (hisPro.isFinishProcess()) {
					treeNode.setIcon(tracePicFix+"/ico-agree1.png");
				} else {
					treeNode.setIcon(tracePicFix+"/ico-agree.png");
				}
			}
			treeNode.setIcon(SysConfig.getValue("CTX") + treeNode.getIcon());
			treeNodes.add(treeNode);
		}
		return treeNodes;
	}


	@RequestMapping({ "/detailLog" })
	public ModelAndView detailLog(String processInstanceId) throws Exception {
		ModelAndView modelAndView = new ModelAndView("/trace/detailLog");
		Map<String, Object> hisTaskLog = this.processTraceService.getHisTaskLog(processInstanceId);
		modelAndView.addObject("hisTaskLog", hisTaskLog);
		return modelAndView;
	}

	@RequestMapping({ "/resource1" })
	public void graphHistoryProcessInstance(String resourceType, String processInstanceId, HttpServletResponse response)
			throws Exception {
		response.setContentType("image/png");
		InputStream is = this.processTraceService.getProcessInstanceDiagram(processInstanceId);
		IOUtils.copy(is, response.getOutputStream());
	}

	public static long differByDay(Date startDate, Date endDate) {
		if ((startDate == null) || (endDate == null)) {
			return 0L;
		}
		return endDate.getTime() / 86400000L - startDate.getTime() / 86400000L;
	}
}
