package com.leanwo.activiti.service.base.impl;

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

import javax.inject.Inject;
import javax.inject.Named;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.HistoricProcessInstanceQueryImpl;
import org.activiti.engine.impl.HistoricProcessInstanceQueryProperty;
import org.activiti.engine.impl.ProcessInstanceQueryImpl;
import org.activiti.engine.impl.ProcessInstanceQueryProperty;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;

import com.leanwo.activiti.dto.BaseResponse;
import com.leanwo.activiti.dto.SortDirection;
import com.leanwo.activiti.dto.manage.ProcessInstanceDocInfo;
import com.leanwo.activiti.dto.manage.ProcessInstanceDocRequest;
import com.leanwo.activiti.dto.manage.ProcessInstanceDocResponse;
import com.leanwo.activiti.dto.manage.ProcessInstanceStatus;
import com.leanwo.activiti.dto.manage.TaskDocInfo;
import com.leanwo.activiti.service.base.DocManagmentService;
import com.leanwo.activiti.util.StringUtil;

@Named
public class DocManagmentServiceImpl implements DocManagmentService {

	@Inject
	private RuntimeService runtimeService;

	@Inject
	private TaskService taskService;
	
	@Inject
	private HistoryService historyService;
	
	@Override
	public ProcessInstanceDocResponse query(ProcessInstanceDocRequest processInstanceDocRequest) {
		
		ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
		
		ProcessInstanceStatus status = processInstanceDocRequest.getStatus();
		if(status != null && status.equals(ProcessInstanceStatus.Running)) {
			processInstanceQuery = processInstanceQuery.active();
		}else if(status != null && status.equals(ProcessInstanceStatus.Suspended)) {
			processInstanceQuery = processInstanceQuery.suspended();
		}else if(status != null && status.equals(ProcessInstanceStatus.Finished)) {
			return queryHistory(processInstanceDocRequest);
		}
		
		String documentNo = processInstanceDocRequest.getDocumentNo();
		String title = processInstanceDocRequest.getTitle();
		String content = processInstanceDocRequest.getContent();
		Date startAfter = processInstanceDocRequest.getStartAfter();
		Date startBefore = processInstanceDocRequest.getStartBefore();
		SortDirection sortDirection = processInstanceDocRequest.getSortDirection();
		
		if(StringUtil.isNotEmpty(documentNo)) {
			processInstanceQuery = processInstanceQuery.variableValueLike(UserPreference.DOCUMENT_NO,
					'%' + documentNo + "%");
		}

		if(StringUtil.isNotEmpty(title)) {
			processInstanceQuery = processInstanceQuery.variableValueLike(UserPreference.APPROVE_TITLE,
					'%' + title + "%");
		}

		if(StringUtil.isNotEmpty(content)) {
			processInstanceQuery = processInstanceQuery.variableValueLike(UserPreference.APPROVE_CONTENT,
					'%' + content + "%");
		}
		
		if (startAfter != null) {
			processInstanceQuery = processInstanceQuery.startedAfter(startAfter);
		}
		
		if (startBefore != null) {
			processInstanceQuery = processInstanceQuery.startedBefore(startBefore);
		}
		
		Long count = processInstanceQuery.count();
		
		if(processInstanceQuery instanceof ProcessInstanceQueryImpl) {
			ProcessInstanceQueryImpl processInstanceQueryImpl = (ProcessInstanceQueryImpl) processInstanceQuery;
			// processInstanceQuery = processInstanceQueryImpl.orderBy(new ProcessInstanceQueryProperty("START_TIME_"));
			processInstanceQuery = processInstanceQueryImpl.orderBy(new ProcessInstanceQueryProperty("TEMPRES_START_TIME_"));
			
			
			if(sortDirection != null && sortDirection.equals(SortDirection.ASC)) {
				processInstanceQuery = processInstanceQuery.asc();
			}else {
				processInstanceQuery = processInstanceQuery.desc();
			}
		}
		
		List<ProcessInstance> processInstances = processInstanceQuery.includeProcessVariables().listPage(processInstanceDocRequest.getStart(), processInstanceDocRequest.getLength());
		
		ProcessInstanceDocResponse processInstanceDocResponse = new ProcessInstanceDocResponse();
		processInstanceDocResponse.setTotal(count.intValue());
		processInstanceDocResponse.setStart(processInstanceDocRequest.getStart());

		List<ProcessInstanceDocInfo> datas = new ArrayList<ProcessInstanceDocInfo>();
		if(processInstances != null) {
			for(ProcessInstance processInstance : processInstances) {
				ProcessInstanceDocInfo processInstanceDocInfo = new ProcessInstanceDocInfo();
				processInstanceDocInfo.setProcessInstanceId(processInstance.getId());
				Map<String, Object> variables = processInstance.getProcessVariables();
				if(variables != null && variables.containsKey(UserPreference.DOCUMENT_NO)) {
					processInstanceDocInfo.setDocumentNo((String)variables.get(UserPreference.DOCUMENT_NO));
				}
				if(variables != null && variables.containsKey(UserPreference.APPROVE_CONTENT)) {
					processInstanceDocInfo.setContent((String)variables.get(UserPreference.APPROVE_CONTENT));
				}
				if(variables != null && variables.containsKey(UserPreference.APPROVE_TITLE)) {
					processInstanceDocInfo.setTitle((String)variables.get(UserPreference.APPROVE_TITLE));
				}
				if(processInstance.isSuspended()) {
					processInstanceDocInfo.setStatus(ProcessInstanceStatus.Suspended);
				}else if(processInstance.isEnded()) {
					processInstanceDocInfo.setStatus(ProcessInstanceStatus.Finished);
				}else if(!processInstance.isEnded()) {
					processInstanceDocInfo.setStatus(ProcessInstanceStatus.Running);
				}
				processInstanceDocInfo.setStartTime(processInstance.getStartTime());
				datas.add(processInstanceDocInfo);
			}
		}
		processInstanceDocResponse.setDatas(datas);
		
		return processInstanceDocResponse;
	}

	
	public ProcessInstanceDocResponse queryHistory(ProcessInstanceDocRequest processInstanceDocRequest) {
		
		HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
		
		ProcessInstanceStatus status = processInstanceDocRequest.getStatus();
		if(status != null && status.equals(ProcessInstanceStatus.Finished)) {
			historicProcessInstanceQuery = historicProcessInstanceQuery.finished();
		}
		
		String documentNo = processInstanceDocRequest.getDocumentNo();
		String title = processInstanceDocRequest.getTitle();
		String content = processInstanceDocRequest.getContent();
		Date startAfter = processInstanceDocRequest.getStartAfter();
		Date startBefore = processInstanceDocRequest.getStartBefore();
		SortDirection sortDirection = processInstanceDocRequest.getSortDirection();
		
		if(StringUtil.isNotEmpty(documentNo)) {
			historicProcessInstanceQuery = historicProcessInstanceQuery.variableValueLike(UserPreference.DOCUMENT_NO,
					'%' + documentNo + "%");
		}

		if(StringUtil.isNotEmpty(title)) {
			historicProcessInstanceQuery = historicProcessInstanceQuery.variableValueLike(UserPreference.APPROVE_TITLE,
					'%' + title + "%");
		}

		if(StringUtil.isNotEmpty(content)) {
			historicProcessInstanceQuery = historicProcessInstanceQuery.variableValueLike(UserPreference.APPROVE_CONTENT,
					'%' + content + "%");
		}
		
		if (startAfter != null) {
			historicProcessInstanceQuery = historicProcessInstanceQuery.startedAfter(startAfter);
		}
		
		if (startBefore != null) {
			historicProcessInstanceQuery = historicProcessInstanceQuery.startedBefore(startBefore);
		}
		
		Long count = historicProcessInstanceQuery.count();
		
		if(historicProcessInstanceQuery instanceof HistoricProcessInstanceQueryImpl) {
			HistoricProcessInstanceQueryImpl historicProcessInstanceQueryImpl = (HistoricProcessInstanceQueryImpl) historicProcessInstanceQuery;
			// historicProcessInstanceQuery = historicProcessInstanceQueryImpl.orderBy(new HistoricProcessInstanceQueryProperty("START_TIME_"));
			historicProcessInstanceQuery = historicProcessInstanceQueryImpl.orderBy(new ProcessInstanceQueryProperty("TEMPRES_START_TIME_"));
			if(sortDirection != null && sortDirection.equals(SortDirection.ASC)) {
				historicProcessInstanceQuery = historicProcessInstanceQuery.asc();
			}else {
				historicProcessInstanceQuery = historicProcessInstanceQuery.desc();
			}
		}
		
		List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.includeProcessVariables().listPage(processInstanceDocRequest.getStart(), processInstanceDocRequest.getLength());
		
		ProcessInstanceDocResponse processInstanceDocResponse = new ProcessInstanceDocResponse();
		processInstanceDocResponse.setTotal(count.intValue());
		processInstanceDocResponse.setStart(processInstanceDocRequest.getStart());

		List<ProcessInstanceDocInfo> datas = new ArrayList<ProcessInstanceDocInfo>();
		if(historicProcessInstances != null) {
			for(HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
				ProcessInstanceDocInfo processInstanceDocInfo = new ProcessInstanceDocInfo();
				processInstanceDocInfo.setProcessInstanceId(historicProcessInstance.getId());
				Map<String, Object> variables = historicProcessInstance.getProcessVariables();
				if(variables != null && variables.containsKey(UserPreference.DOCUMENT_NO)) {
					processInstanceDocInfo.setDocumentNo((String)variables.get(UserPreference.DOCUMENT_NO));
				}
				if(variables != null && variables.containsKey(UserPreference.APPROVE_CONTENT)) {
					processInstanceDocInfo.setContent((String)variables.get(UserPreference.APPROVE_CONTENT));
				}
				if(variables != null && variables.containsKey(UserPreference.APPROVE_TITLE)) {
					processInstanceDocInfo.setTitle((String)variables.get(UserPreference.APPROVE_TITLE));
				}

				processInstanceDocInfo.setStatus(ProcessInstanceStatus.Finished);
				processInstanceDocInfo.setStartTime(historicProcessInstance.getStartTime());
				processInstanceDocInfo.setEndTime(historicProcessInstance.getEndTime());
				datas.add(processInstanceDocInfo);
			}
		}
		processInstanceDocResponse.setDatas(datas);
		
		return processInstanceDocResponse;		
	}


	@Override
	public List<TaskDocInfo> listTasks(String processInstanceId) {
		TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(processInstanceId).includeProcessVariables().orderByTaskCreateTime().asc();
		List<Task> tasks = taskQuery.list();
		List<TaskDocInfo> taskDocInfos = new ArrayList<TaskDocInfo>();
		if(tasks != null) {
			for(Task task : tasks) {
				TaskDocInfo taskDocInfo = new TaskDocInfo();
				taskDocInfo.setId(task.getId());
				taskDocInfo.setName(task.getName());
				if(StringUtil.isNotEmpty(task.getAssignee())) {
					taskDocInfo.setAssigneeId(Long.parseLong(task.getAssignee()));
				}
				taskDocInfo.setCreateTime(task.getCreateTime());
				Map<String, Object> variables = task.getTaskLocalVariables();
				if(variables != null && variables.containsKey(UserPreference.APPROVE_CONTENT)) {
					taskDocInfo.setComments((String) variables.get(UserPreference.APPROVE_CONTENT));
				}
				taskDocInfos.add(taskDocInfo);
			}
		}
		return taskDocInfos;
	}


	@Override
	public List<TaskDocInfo> listHistoricTasks(String processInstanceId) {
		HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).includeProcessVariables().orderByTaskCreateTime().asc();
		List<HistoricTaskInstance> historicTaskInstances = historicTaskInstanceQuery.list();
		List<TaskDocInfo> taskDocInfos = new ArrayList<TaskDocInfo>();
		if(historicTaskInstances != null) {
			for(HistoricTaskInstance historicTaskInstance : historicTaskInstances) {
				TaskDocInfo taskDocInfo = new TaskDocInfo();
				taskDocInfo.setId(historicTaskInstance.getId());
				taskDocInfo.setName(historicTaskInstance.getName());
				if(StringUtil.isNotEmpty(historicTaskInstance.getAssignee())) {
					taskDocInfo.setAssigneeId(Long.parseLong(historicTaskInstance.getAssignee()));
				}
				taskDocInfo.setCreateTime(historicTaskInstance.getCreateTime());
				taskDocInfo.setEndTime(historicTaskInstance.getEndTime());
				Map<String, Object> variables = historicTaskInstance.getTaskLocalVariables();
				if(variables != null && variables.containsKey(UserPreference.APPROVE_CONTENT)) {
					taskDocInfo.setComments((String) variables.get(UserPreference.APPROVE_CONTENT));
				}
				taskDocInfos.add(taskDocInfo);
			}
		}
		return taskDocInfos;
	}


	@Override
	public BaseResponse changeProcessInstance(String changeType, String processInstanceId, String reason) {

		ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId);
		long count = processInstanceQuery.count();
		if(count == 0) {
			BaseResponse baseResponse = new BaseResponse();
			baseResponse.setErrorCode(1);
			baseResponse.setErrorMessage("流程实例已经不存在，或许已经结束了。");
			return baseResponse;
		}
		
		ProcessInstance processInstance = processInstanceQuery.singleResult();
		
		if(changeType.equals("suspend")) {
			if(processInstance.isSuspended()) {
				BaseResponse baseResponse = new BaseResponse();
				baseResponse.setErrorCode(2);
				baseResponse.setErrorMessage("流程实例已经处于暂停的状态。");
				return baseResponse;
			}
		}else if(changeType.equals("activate")) {
			if(!processInstance.isSuspended()) {
				BaseResponse baseResponse = new BaseResponse();
				baseResponse.setErrorCode(2);
				baseResponse.setErrorMessage("流程实例已经处于活动的状态。");
				return baseResponse;
			}
		}		
		
		
		
		if(processInstance.isEnded()) {
			BaseResponse baseResponse = new BaseResponse();
			baseResponse.setErrorCode(3);
			baseResponse.setErrorMessage("流程实例已经处于停止的状态。");
			return baseResponse;
		}

		BaseResponse baseResponse = new BaseResponse();
		baseResponse.setErrorCode(0);
		if(changeType.equals("suspend")) {
			runtimeService.suspendProcessInstanceById(processInstanceId);
			baseResponse.setErrorMessage("流程实例暂停成功。");
		}else if(changeType.equals("activate")) {
			runtimeService.activateProcessInstanceById(processInstanceId);
			baseResponse.setErrorMessage("流程实例激活成功。");
		}else if(changeType.equals("delete")) {
			runtimeService.deleteProcessInstance(processInstanceId, reason);
			baseResponse.setErrorMessage("流程实例删除成功。");
		}
		
		return baseResponse;
	}


	
}
