package com.huigou.bpm.engine.delegate;

import com.huigou.bpm.management.domain.model.ProcInst;
import com.huigou.bpm.management.domain.model.ProcessDeployment;
import com.huigou.bpm.management.repository.ProcInstRepository;
import com.huigou.bpm.management.repository.ProcessDeploymentRepository;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.repository.ProcessDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * 流程实例执行监听器。
 *
 * @author yonghuan
 */
@Service("procInstExecutionListener")
public class ProcInstExecutionListener implements ExecutionListener {

    private final static Logger LOG = LoggerFactory.getLogger(ProcInstExecutionListener.class);
    private ProcInstRepository procInstRepository;
    private RepositoryService repositoryService;
    private ProcessDeploymentRepository processDeploymentRepository;

    @Autowired
    public void setProcInstRepository(ProcInstRepository procInstRepository) {
        this.procInstRepository = procInstRepository;
    }

    @Autowired
    public void setRepositoryService(RepositoryService repositoryService) {
        this.repositoryService = repositoryService;
    }

    @Autowired
    public void setProcessDeploymentRepository(ProcessDeploymentRepository processDeploymentRepository) {
        this.processDeploymentRepository = processDeploymentRepository;
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void notify(DelegateExecution execution) throws Exception {
        String eventName = execution.getEventName();
        switch (eventName) {
            case EVENTNAME_START:
                onStart(execution);
                break;
            case EVENTNAME_END:
                onEnd(execution);
                break;
            default:
                break;
        }
    }

    private void onStart(DelegateExecution execution) {
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(execution.getProcessDefinitionId())
                .singleResult();
        ProcessDeployment deployment = processDeploymentRepository.findByActProcdefId(pd.getId());
        ProcInst procInst = new ProcInst();
        procInst.setName(pd.getName());
        procInst.setDescription(pd.getDescription());
        procInst.setId(execution.getProcessInstanceId());
        procInst.setProcDeployId(deployment.getId());
        procInst.setStatus(ProcInst.Status.STARTED.id);
        procInst.setBizKey(execution.getProcessBusinessKey());
        procInstRepository.save(procInst);
    }

    private void onEnd(DelegateExecution execution) {
        ProcInst procInst = procInstRepository.getOne(execution.getProcessInstanceId());
        if (procInst == null) {
            LOG.warn("根据 actProcInstId={} 未找到匹配的流程实例，无法设置流程实例的完成时间。", execution.getProcessInstanceId());
            return;
        }
        procInst.setStatus(ProcInst.Status.COMPLETED.id);
        procInst.setCompleteDate(new Date());
        procInstRepository.save(procInst);
    }
}
