package com.jeeww.activiti.service.impl;

import java.io.InputStream;
import java.util.List;
import java.util.Map;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.bpmn.diagram.ProcessDiagramGenerator;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jeeww.activiti.service.ActivitiCoreService;
import com.jeeww.core.utils.JsonUtils;
import com.jeeww.core.vo.Pager;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/**
 * 类描述：activiti核心自定义接口.
 * @author 蒋文武
 */
@Service("ActivitiCoreServiceImpl")
public class ActivitiCoreServiceImpl implements ActivitiCoreService {
    /**
     * 当不分页查询时，默认显示的流程定义数.
     */
    private static final int DEFAULT_GRID_COUNT = 20;
    /**
     * logger.
     */
    private Logger logger = Logger.getLogger(ActivitiCoreServiceImpl.class);
    /**
     * processEngine.
     */
    @Autowired
    private ProcessEngine processEngine;
    /**
     * processEngineFactoryBean.
     */
    @Autowired
    private ProcessEngineFactoryBean processEngineFactoryBean;

    @Override
    public String startProcess(final String processDefinitionId, final Map<String, Object> variables) throws Exception {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionId, variables);
        String processInstanceId = processInstance.getProcessInstanceId();
        return processInstanceId;
    }

    @Override
    public InputStream getProcessDiagramByPdid(final String processDefinitionId) throws Exception {
        InputStream imageStream = null;
        logger.info("历史流程实例, 流程ID:" + processDefinitionId);
        ProcessDefinition processDefinition = processEngine.getRepositoryService().createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId).singleResult();
        String diagramResourceName = processDefinition.getDiagramResourceName();
        imageStream = processEngine.getRepositoryService().getResourceAsStream(processDefinition.getDeploymentId(),
                diagramResourceName);
        return imageStream;
    }

    @Override
    public InputStream getActivieDiagramByPiid(final String processInstanceId) throws Exception {
        ProcessInstanceQuery processInstanceQuery = processEngine.getRuntimeService().createProcessInstanceQuery()
                .processInstanceId(processInstanceId);
        ProcessInstance processInstance = processInstanceQuery.singleResult();
        if (processInstance != null) {
            String processDefinitionId = processInstance.getProcessDefinitionId();
            BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(processDefinitionId);
            List<String> activeActivityIds = processEngine.getRuntimeService().getActiveActivityIds(processInstanceId);
            Context.setProcessEngineConfiguration(processEngineFactoryBean.getProcessEngineConfiguration());
            InputStream imageStream = ProcessDiagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds);
            // InputStream imageStream = ProcessDiagramGenerator.generateDiagram(bpmnModel, "jpg", activeActivityIds);
            return imageStream;
        }
        return null;
    }

    @Override
    public String getActiviePoint(final String processInstanceId) throws Exception {
        Execution execution = processEngine.getRuntimeService().createExecutionQuery().executionId(processInstanceId)
                .singleResult(); // 执行实例
        Object property = PropertyUtils.getProperty(execution, "activityId");
        String activityId = "";
        if (property != null) {
            activityId = property.toString();
        }
        ProcessInstance processInstance = processEngine.getRuntimeService().createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) processEngine
                .getRepositoryService()).getDeployedProcessDefinition(processInstance.getProcessDefinitionId());
        List<ActivityImpl> activitiList = processDefinition.getActivities(); // 获得当前任务的所有节点
        ActivityImpl activity = null;
        for (ActivityImpl activityImpl : activitiList) {
            String id = activityImpl.getId();
            if (id.equals(activityId)) { // 获得执行到那个节点
                activity = activityImpl;
                break;
            }
        }
        if (activity != null) {
            JSONObject obj = new JSONObject();
            int x = activity.getX() - 1;
            int y = activity.getY() - 1;
            int height = activity.getHeight();
            int width = activity.getWidth();
            obj.put("taskId", activity.getId());
            obj.put("piid", processInstanceId);
            obj.put("pdid", processInstance.getProcessDefinitionId());
            obj.put("x", x);
            obj.put("y", y);
            obj.put("height", height);
            obj.put("width", width);
            return obj.toJSONString();
        }
        return null;
    }

    @Override
    public Pager<ProcessInstance> getProcessInstances(final Pager<ProcessInstance> pager) throws Exception {
        ProcessInstanceQuery processInstanceQuery = processEngine.getRuntimeService().createProcessInstanceQuery();
        int maxResults = pager.getPageSize();
        int firstResult = (pager.getPage() - 1) * pager.getPageSize();
        long resultCount = processInstanceQuery.count();
        if (maxResults == 0) {
            maxResults = DEFAULT_GRID_COUNT;
        }
        List<ProcessInstance> processInstanceList = processInstanceQuery.listPage(firstResult, maxResults);
        pager.setResult(processInstanceList);
        pager.setResultCount((int) resultCount);
        return pager;
    }

    @Override
    public Pager<ProcessDefinition> getProcessDefinations(final Pager<ProcessDefinition> pager) throws Exception {
        ProcessDefinitionQuery processDefinitionQuery = processEngine.getRepositoryService()
                .createProcessDefinitionQuery();
        int maxResults = pager.getPageSize();
        int firstResult = (pager.getPage() - 1) * pager.getPageSize();
        long resultCount = processDefinitionQuery.count();
        if (maxResults == 0) {
            maxResults = DEFAULT_GRID_COUNT;
        }
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(firstResult, maxResults);
        pager.setResult(processDefinitionList);
        pager.setResultCount((int) resultCount);
        return pager;
    }

    @Override
    public String getActiveTasksByUid(final String assignee) throws Exception {
        // 根据任务指定人查出任务.
        List<Task> tasks = processEngine.getTaskService().createTaskQuery().includeProcessVariables()
                .taskAssignee(assignee).list();
        JSONArray arr = new JSONArray();
        for (Task task : tasks) {
            JSONObject obj = new JSONObject();
            obj.put("pdid", task.getProcessDefinitionId());
            obj.put("piid", task.getProcessInstanceId());
            obj.put("taskId", task.getId());
            obj.put("taskName", task.getName());
            obj.put("taskCreateDate", task.getCreateTime());
            Map<String, Object> taskVars = task.getProcessVariables();
            if (taskVars != null) {
                obj.put("handleTaskUrl", taskVars.get("handleTaskUrl"));
            }
            arr.add(obj);
        }
        return arr.toJSONString();
    }

    @Override
    public String getActiveTasksByGroupId(final String group) throws Exception {
        // 根据角色查询出所有的任务
        List<Task> tasks = processEngine.getTaskService().createTaskQuery().taskCandidateGroup(group).list();
        for (Task task : tasks) {
            logger.info("通过组(角色)查询出的任务: " + task.getName());
        }
        String taskStr = JsonUtils.list2SimpleJSONArray(tasks).toJSONString();
        return taskStr;
    }

    @Override
    public void deployActiviti() throws Exception {
        processEngine.getRepositoryService().createDeployment().name("VacationRequest.bar")
                .addClasspathResource("com/jeeww/bpm/activiti/vacationRequest.bpmn20.xml")
                .addClasspathResource("com/jeeww/bpm/activiti/vacationRequest.png").deploy();
    }

    @Override
    public void completeTask(final String taskId, final Map<String, Object> variables) throws Exception {
        List<Task> taskList = processEngine.getTaskService().createTaskQuery().taskId(taskId).list();
        for (Task task : taskList) {
            if (task.getId().equals(taskId)) {
                processEngine.getTaskService().complete(task.getId(), variables);
            }
        }
    }

    @Override
    public String getTaskPointInfoByPdid(final String pdid) throws Exception {
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) processEngine
                .getRepositoryService()).getDeployedProcessDefinition(pdid);
        Map<String, TaskDefinition> taskInfo = processDefinition.getTaskDefinitions();
        List<ActivityImpl> activitiList = processDefinition.getActivities(); // 获得当前任务的所有节点
        JSONArray taskPointArr = new JSONArray();
        for (ActivityImpl activityImpl : activitiList) {
            JSONObject taskPoint = new JSONObject();
            int x = activityImpl.getX() - 1;
            int y = activityImpl.getY() - 1;
            int height = activityImpl.getHeight();
            int width = activityImpl.getWidth();
            String taskId = activityImpl.getId();
            taskPoint.put("taskId", taskId);
            taskPoint.put("pdid", pdid);
            taskPoint.put("x", x);
            taskPoint.put("y", y);
            taskPoint.put("height", height);
            taskPoint.put("width", width);
            TaskDefinition task = taskInfo.get(taskId);
            if (task != null && task.getDescriptionExpression() != null) {
                taskPoint.put("description", task.getDescriptionExpression().getExpressionText().substring(0, 10)
                        .replaceAll("", ""));
            }
            if (task != null && task.getAssigneeExpression() != null) {
                taskPoint.put("assignee", task.getAssigneeExpression().getExpressionText());
            }
            if (task != null && !task.getCandidateGroupIdExpressions().isEmpty()) {
                // taskPoint.put("candidateGroupId", task.getCandidateGroupIdExpressions());
            }
            if (task != null && !task.getCandidateUserIdExpressions().isEmpty()) {
                // taskPoint.put("candidateUserId", task.getCandidateUserIdExpressions());
            }
            taskPointArr.add(taskPoint);
        }
        return taskPointArr.toJSONString();
    }
}
