package com.blueland.bpm.manage.web;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.persistence.entity.HistoricActivityInstanceEntity;
import org.activiti.engine.impl.persistence.entity.HistoricTaskInstanceEntity;
import org.activiti.engine.impl.persistence.entity.SuspensionState;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.blueland.bpm.common.page.Page;
import com.blueland.bpm.engine.core.model.ActivityInstanceModel;
import com.blueland.bpm.engine.core.model.ProcessInputModel;
import com.blueland.bpm.engine.core.model.ProcessInstanceModel;
import com.blueland.bpm.engine.core.model.ProcessMgrDataShare;
import com.blueland.bpm.engine.core.model.SearchProcessListDTO;
import com.blueland.bpm.engine.core.service.AutoRunOneProcess;
import com.blueland.bpm.engine.core.service.ProcessExecuteService;
import com.blueland.bpm.engine.core.service.ProcessInstanceService;
import com.blueland.bpm.engine.core.service.ProcessTraceService;
import com.blueland.bpm.engine.util.WorkFlowContants;
import com.blueland.bpm.engine.util.WorkFlowException;
import com.blueland.bpm.manage.service.ProcessRestoreService;
import com.blueland.bpm.manage.service.ProcessUpdateTimeService;
import com.blueland.bpm.manage.util.BaseUser;
import com.blueland.bpm.manage.util.MyContants;

@Controller
@RequestMapping(value = "/procInstMgr")
public class ProcessInstanceController extends BaseProcessController{
	@Autowired
	private ProcessInstanceService processInstanceService;
	@Autowired
	ProcessExecuteService processExecuteService;
	@Autowired
	AutoRunOneProcess autoRunOneProcess;
	@Autowired
	ProcessUpdateTimeService processUpdateTimeService;
	@Autowired
	private ProcessTraceService processTraceService;
	@Autowired
	private HistoryService historyService;
	@Autowired
	private ProcessRestoreService processRestoreService;
	@RequestMapping(value = "/historyList")
	public ModelAndView historyList(String tenantId,SearchProcessListDTO pageRequest,
			HttpServletRequest request) {
		HistoricProcessInstanceQuery query = processInstanceService
				.getHistoryService().createHistoricProcessInstanceQuery()
				.finished();
		pageRequest = (SearchProcessListDTO) bindPageRequest(request,
				pageRequest, "");
		if (StringUtils.isNotEmpty(pageRequest.getProcessDefKey())) {
			query.processDefinitionKey(pageRequest.getProcessDefKey());

		}if (StringUtils.isNotEmpty(pageRequest.getProcessDefName())) {
			query.processDefinitionName("%"+pageRequest.getProcessDefName()+"%");

		}
		if (StringUtils.isNotEmpty(pageRequest.getTitle())) {
			query.procTitle("%"+pageRequest.getTitle()+"%");

		}
		if (StringUtils.isNotEmpty(pageRequest.getProcessInstanceId())) {
			query.processInstanceId(pageRequest.getProcessInstanceId());
		}
		if (StringUtils.isNotEmpty(pageRequest.getUserId())) {
			query.startedBy(pageRequest.getUserId());
		}
		if(null!=pageRequest.getProcState()){
			query.procState(pageRequest.getProcState());
		}
		String appId = "";
		if(StringUtils.isNotEmpty(tenantId)){
			appId= tenantId;
		}else{
			appId = BaseUser.getInstance().getLoginUserAppId(request);
		}
		if ("true".equalsIgnoreCase(MyContants.IS_OPEN_TENANT) && (!StringUtils.isEmpty(appId))) {
			query.processInstanceTenantId(appId);
		}
		Page page = new Page(pageRequest, Integer.MAX_VALUE);

		List<HistoricProcessInstance> historicProcessInstances = query
				.orderByProcessInstanceStartTime().desc()
				.listPage(page.getFirstResult(), page.getPageSize());
		ModelAndView modelAndView = new ModelAndView("/procInstMgr/historyList");

		page.setResult(historicProcessInstances);
		modelAndView.addAllObjects(toModelMap(page, pageRequest));
		return modelAndView;
	}
	
	
	@RequestMapping(value="/list")
	public ModelAndView list(SearchProcessListDTO pageRequest,HttpServletRequest request) throws Exception {
		HistoricProcessInstanceQuery query=processInstanceService.getHistoryService().createHistoricProcessInstanceQuery();
		pageRequest = (SearchProcessListDTO) bindPageRequest(request,
				pageRequest, "");
		if (StringUtils.isNotEmpty(pageRequest.getProcessDefKey())) {
			query.processDefinitionKey(pageRequest.getProcessDefKey());

		}
		if (StringUtils.isNotEmpty(pageRequest.getProcessDefName())) {
			query.processDefinitionName("%"+pageRequest.getProcessDefName()+"%");

		}
		if (StringUtils.isNotEmpty(pageRequest.getTitle())) {
			query.procTitle("%"+pageRequest.getTitle()+"%");

		}
		if (StringUtils.isNotEmpty(pageRequest.getProcessInstanceId())) {
			query.processInstanceId(pageRequest.getProcessInstanceId());
		}
		if (StringUtils.isNotEmpty(pageRequest.getUserId())) {
			query.startedBy(pageRequest.getUserId());
		}
		
		query.procState(1);
		
		
		String appId=BaseUser.getInstance().getLoginUserAppId(request);
		if("true".equalsIgnoreCase(MyContants.IS_OPEN_TENANT)&&(!StringUtils.isEmpty(appId))){
			query.processInstanceTenantId(appId);
		}

		//pageRequest.setPageSize(500);
		Page page = new Page(pageRequest, Integer.MAX_VALUE);
		
		List<HistoricProcessInstance> historicProcessInstances=query.orderByProcessInstanceStartTime().desc().listPage(page.getFirstResult(),page.getPageSize());
		ModelAndView modelAndView = new ModelAndView("/procInstMgr/list");
		
		page.setResult(historicProcessInstances);
		modelAndView.addAllObjects(toModelMap(page, pageRequest));
		modelAndView.addObject("isBpmAdmin",BaseUser.isEbpmAdmin(BaseUser.getInstance().getSessionUser(request)));
		return modelAndView;
	}
	
	
	
	
	
	
	@RequestMapping(value="/suspend",method=RequestMethod.POST)
	@ResponseBody
	public String suspend(String processInstanceId,HttpServletRequest request) {
		ProcessInstance processInstance=processInstanceService.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
		if(processInstance==null){
			return this.ACTION_ERROR;
		}
		if(!processInstance.isSuspended()){
			processInstanceService.getRuntimeService().suspendProcessInstanceById(processInstanceId);
		}
		return this.ACTION_SUCCESS;
	}
	
	@RequestMapping(value="/restore",method=RequestMethod.POST)
	@ResponseBody
	public String restore(String processInstanceId,HttpServletRequest request) {
		ProcessInstance processInstance=processInstanceService.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
		if(processInstance==null){
			return this.ACTION_ERROR;
		}
		if(processInstance.isSuspended()){
			processInstanceService.getRuntimeService().activateProcessInstanceById(processInstanceId);
		}
		return this.ACTION_SUCCESS;
	}
	
	@RequestMapping(value = "/cancel",method=RequestMethod.POST)
	@ResponseBody
	public String cancel(String processInstanceId, HttpServletRequest request)
			throws Exception {
		if (processInstanceId == null) {
			return this.ACTION_ERROR;
		}

		String[] processInstanceIds = null;
		if (processInstanceId.indexOf(";") != -1) {
			processInstanceIds = processInstanceId.split(";");
		} else {
			processInstanceIds = new String[] { processInstanceId };
		}
		String errorMsg="";
		for (String pid : processInstanceIds) {
			try {
				ProcessInstance processInstance = processInstanceService
						.getRuntimeService().createProcessInstanceQuery()
						.processInstanceId(pid).singleResult();
				if (processInstance == null) {
					return this.ACTION_ERROR;
				}
				List<Task> tasks = processInstanceService.getTaskService()
						.createTaskQuery()
						.processInstanceId(processInstance.getId()).active()
						.orderByTaskCreateTime().desc().list();
				ProcessInputModel processInputModel = null;
				if (tasks != null && !tasks.isEmpty()) {
					Task task = tasks.get(0);
					processInputModel = (ProcessInputModel) processInstanceService
							.getTaskVariables(task.getId())
							.get(WorkFlowContants.WF_PROCESS_INPUT_VARIABLE_KEY);
					if (processInputModel != null) {
						processInputModel.setWf_curActInstId(task.getId());
					}

				}
				if (processInputModel == null) {
					processInputModel = new ProcessInputModel();
				}
				processInputModel
						.setWf_actionType(WorkFlowContants.ACTION_TYPE_CANCEL_PROCESS);
				processInputModel.setWf_procDefId(processInstance
						.getProcessDefinitionId());
				processInputModel.setWf_procInstId(processInstance
						.getProcessInstanceId());
				processInputModel
						.setWf_curComment("流程管理端作废，操作人："
								+ BaseUser.getInstance()
										.getSessionUser(request).getUserId());
				ProcessMgrDataShare.setProcessMgrData(WorkFlowContants.PROCESS_DEF_DEL_MANAGE_OPT);		
				Map<String, Object> resultMap = processExecuteService
						.nextExecute(processInputModel);
				MyContants.saveUserOperate(request, "processInstanceId", true,
						"作废成功", MyContants.LOGIN_SESSION_USER,
						MyContants.APPLICATION);
				if ("ERROR".equals(resultMap.get("executeStatus"))) {
					errorMsg+=resultMap.get("executeErrorMsg")+",";
				}
				ProcessMgrDataShare.clear();
			} catch (Exception e) {
				e.printStackTrace();
				errorMsg+=WorkFlowException.getWorkFlowException(e)
						.getMessage()+",";
			}
		}
		if(StringUtils.isNotEmpty(errorMsg)){
			return this.ACTION_ERROR + "," + errorMsg;
		}
		return this.ACTION_SUCCESS;
	}
	
	
	@RequestMapping(value="/delete",method=RequestMethod.POST)
	@ResponseBody
	public String delete(String processInstanceId,boolean isHistory,HttpServletRequest request) throws Exception {
		if(processInstanceId==null){
			return this.ACTION_ERROR;
		}
		
		String[] processInstanceIds=null;
		if(processInstanceId.indexOf(";")!=-1){
			processInstanceIds=processInstanceId.split(";");
		}else{
			processInstanceIds=new String[]{processInstanceId};
		}
		for (String pid : processInstanceIds) {
			MyContants.saveUserOperate(request, "processInstanceId;isHistory", true, "删除成功",
					MyContants.LOGIN_SESSION_USER,MyContants.APPLICATION);
			ProcessInstance processInstance=null;
			HistoricProcessInstance historicProcessInstance=null;
			ProcessMgrDataShare.setProcessMgrData(WorkFlowContants.PROCESS_DEF_DEL_MANAGE_OPT);
			
			try{
					if(isHistory){		
				historicProcessInstance=processInstanceService.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(pid).singleResult();
				if(historicProcessInstance==null){
					return this.ACTION_ERROR;
				}
				processInstanceService.getHistoryService().deleteHistoricProcessInstance(pid);
			}else{
				processInstance=processInstanceService.getRuntimeService().createProcessInstanceQuery().processInstanceId(pid).singleResult();
				if(processInstance==null){
					return this.ACTION_ERROR;
				}
				processInstanceService.getRuntimeService().deleteProcessInstance(pid,"action:/procInstMgr/delete,actionUser:"+BaseUser.getInstance().getSessionUser(request).getUserId());
			}
			ProcessMgrDataShare.clear();
			}catch(Exception e){
				e.printStackTrace();
				String errorMsg=WorkFlowException.getWorkFlowException(e).getMessage();
				return this.ACTION_ERROR+","+errorMsg;
			}
		}
		return this.ACTION_SUCCESS;
	}
	 /**
     * 计算时间day
     * @param String startDate
     * @param String endDate
     * @return day
     */
	@SuppressWarnings("deprecation")
	public static String differByDay(Date startDate, Date endDate) {
		if(startDate==null||endDate==null){
			return "";
		}
		return "" + (endDate.getTime() / 86400000 - startDate.getTime() / 86400000);
	}
	
	
	@RequestMapping(value="/autoRunVeiw")
	public ModelAndView autoRunVeiw(String procDefKy,HttpServletRequest request) throws Exception {
		ModelAndView modelAndView = new ModelAndView("/autoRun/autoRunProcess");
		return modelAndView;
	}
	@RequestMapping(value="/autoRun",method=RequestMethod.POST)
	public ModelAndView autoRun(String procDefKey,String procStartUserId,HttpServletRequest request) throws Exception {
		ModelAndView modelAndView = new ModelAndView("/autoRun/autoRunProcess");
		if(StringUtils.isNotEmpty(procDefKey)){
			ProcessInstanceModel processInstance=autoRunOneProcess.autoRunOneProcess(procDefKey.split(":")[0], procStartUserId,BaseUser.getInstance().getLoginUserAppId(request));
			modelAndView.addObject("processInstance",processInstance);
		}
		return modelAndView;
	}
	
	/**
	 * 打开对应流程，修改流程流转时间页面
	 * @param procInstId
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/updateProcessTimeView")
	public ModelAndView updateProcessTimeView(String procInstId,HttpServletRequest request) throws Exception {
		List<ActivityInstanceModel> allActivityInstance = processUpdateTimeService.getAllHistTaskByProcess(procInstId);
		/**
		 * 处理最后结束时间的数据
		 * 1、把结束时间的信息放到所有环节中，显示在页面，以id为actInstId
		 * 2、actState:0(结束以前的环节)、1（结束环节）
		 */
		HistoricProcessInstance curProcessInstance = historyService
				.createHistoricProcessInstanceQuery()
				.processInstanceId(procInstId).singleResult();
		List<ActivityInstanceModel> allActivityInstanceNew = new ArrayList<ActivityInstanceModel>();
	    for (ActivityInstanceModel act : allActivityInstance) {
	    	 act.setActState("0");
	    	 allActivityInstanceNew.add(act);
		}
	    if (curProcessInstance.getProcState() == SuspensionState.FINISH
				.getStateCode()
				&& curProcessInstance.getEndTime() != null
				&& curProcessInstance.getEndActivityId() != null) {
	    	// 将办结节点加入historicTaskInstances中
			List<HistoricActivityInstance> hisActInsts = historyService
					.createHistoricActivityInstanceQuery()
					.processInstanceId(curProcessInstance.getId())
					.activityId(curProcessInstance.getEndActivityId())
					.orderByHistoricActivityInstanceStartTime().desc().list();
		    //组装最后一个环节数据
			if (hisActInsts != null && !hisActInsts.isEmpty()) {
				HistoricActivityInstanceEntity hisActInst = (HistoricActivityInstanceEntity) hisActInsts
						.get(0);
				HistoricTaskInstanceEntity task = new HistoricTaskInstanceEntity();
				task.setSender(hisActInst != null ? hisActInst.getSender() : "");
				task.setSenderOrgId(hisActInst != null ? hisActInst.getSenderOrgId() : "");
				task.setSendUserId(hisActInst != null ? hisActInst.getSendUserId() : "");
				task.setSendUserName(hisActInst != null ? hisActInst.getSendUserName() : "");
				task.setSenderOrgName(hisActInst != null ? hisActInst.getSenderOrgName() : "");
				task.setId(hisActInst.getTaskId());
				task.setProcessInstanceId(hisActInst.getProcessInstanceId());
				task.setExecutionId(hisActInst.getExecutionId());
				task.setTaskDefinitionKey(hisActInst.getActivityId());
				String activityName = hisActInst.getActivityName();
				if ("endEvent".equals(hisActInst.getActivityType())
						&& StringUtils.isEmpty(activityName)) {
					activityName = "结束";
				}
				task.setName(activityName);
				task.setActionType(hisActInst.getActivityType());
				task.setPreTaskDefKey(hisActInst != null ? hisActInst
						.getPreActId() : "");
				task.setPreTaskDefName(hisActInst != null ? hisActInst
						.getPreActName() : "");
				task.setPreTaskId(hisActInst != null ? hisActInst
						.getPreActInstId() : "");
				task.setStartTime(hisActInst.getStartTime());
				task.setEndTime(hisActInst.getEndTime());
				task.setProcTitle(hisActInst.getProcTitle());
				task.setId(hisActInst.getId());
				allActivityInstanceNew.add(ActivityInstanceModel.buildAndActDef(
						(HistoricTaskInstance) task, null));
			}
	    }
		//查询对应流程信息,用于修改流程时间
		HistoricProcessInstance historicProcessInstance=processTraceService.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(procInstId).singleResult();
		ModelAndView modelAndView = new ModelAndView("/taskMgr/updateProcessTime");
		request.setAttribute("procInstId", procInstId);
		request.setAttribute("allActivityInstance", allActivityInstanceNew);
		request.setAttribute("historicProcessInstance", historicProcessInstance);
		return modelAndView;
	}
	
	/**
	 * 修改流程流转时间
	 */
	@RequestMapping(value = "/updateActInstTime",method=RequestMethod.POST)
	@ResponseBody
	public boolean updateActInstTime(@RequestBody List<ActivityInstanceModel> list){
		Boolean status= processUpdateTimeService.updateActInstTime(list);
		return status;
	}
	
	/**
	 * 修改当前流程开始、结束时间
	 * @param procInstId
	 * @param createTime
	 * @param endTime
	 * @return
	 */
	@RequestMapping(value = "/updateProcessTime",method=RequestMethod.POST)
	@ResponseBody
	public boolean updateProcessTime(@RequestParam String procInstId,@RequestParam String createTime,@RequestParam String endTime){
		Boolean status= processUpdateTimeService.updateProcTime(procInstId, createTime, endTime);
		return status;
	}
	
	
	/**
	 * 恢复流程
	 * @param processInstanceId
	 * @return
	 */
	@RequestMapping(value = "/processRestore",method=RequestMethod.POST)
	@ResponseBody
	public Map<String,Object> processRestore(@RequestParam String processInstanceId){
		
		return processRestoreService.processRestore(processInstanceId);
	}
	/**
	 * 打开对应流程，删除流程流转页面
	 * @param procInstId
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/delProcessRoamView")
	public ModelAndView delProcessRoamView(String procInstId,HttpServletRequest request) throws Exception {
		List<ActivityInstanceModel> allActivityInstance = processUpdateTimeService.getAllHistTaskByProcess(procInstId);
		//查询对应流程信息,用于修改流程时间
		HistoricProcessInstance historicProcessInstance=processTraceService.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(procInstId).singleResult();
		ModelAndView modelAndView = new ModelAndView("/taskMgr/delProcessRoam");
		request.setAttribute("procInstId", procInstId);
		request.setAttribute("allActivityInstance", allActivityInstance);
		request.setAttribute("historicProcessInstance", historicProcessInstance);
		return modelAndView;
	}
	/**
	 * 删除当前流程环节
	 * @param list
	 * @return
	 */
	@RequestMapping(value = "/delActInst",method=RequestMethod.POST)
	@ResponseBody
	public boolean delActInst(@RequestBody List<ActivityInstanceModel> list){
		Boolean status= processUpdateTimeService.delActInst(list);
		return status;
	}
	/**
	 * 修改当前流程环节信息
	 * @param list
	 * @return
	 */
	@RequestMapping(value = "/updateActInst",method=RequestMethod.POST)
	@ResponseBody
	public boolean updateActInst(@RequestBody List<ActivityInstanceModel> list){
		Boolean status= processUpdateTimeService.updateActInst(list);
		return status;
	}
}
