package com.lightinit.hsdatagateway.modules.act.service.cmd;

import java.io.ByteArrayInputStream;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.db.DbSqlSession;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.DeploymentEntity;
import org.activiti.engine.impl.persistence.entity.ResourceEntity;
import org.activiti.engine.impl.persistence.entity.ResourceEntityManager;
import org.activiti.engine.impl.util.IoUtil;
import org.activiti.engine.repository.ProcessDefinition;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 模型部署或更新到流程定义
 * @Author yangrui
 * @version 2016年8月2日
 */
public class ModelDeployProcessDefinitionCmd implements Command<java.lang.Void> {
	
	private String modelId;
	private String procDefKey;
	private String procDefName;

	public ModelDeployProcessDefinitionCmd(String modelId, String procDefKey, String procDefName) {
		this.modelId = modelId;
		this.procDefKey = procDefKey;
		this.procDefName = procDefName;
	}

	@Override
	public Void execute(CommandContext commandContext) {
		RepositoryService repositoryService = Context.getProcessEngineConfiguration()
				.getRepositoryService();
		try{
			// 生成部署名称和数据 ThinkGem
			JsonNode editorNode = new ObjectMapper().readTree(repositoryService
						.getModelEditorSource(modelId));
			BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(editorNode);
			byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
			
			// 查询流程定义是否已经存在了 ThinkGem
			ProcessDefinition processDefinition = Context.getProcessEngineConfiguration()
					.getRepositoryService().createProcessDefinitionQuery()
					.processDefinitionKey(procDefKey).latestVersion().singleResult();
			if (processDefinition != null){
				ResourceEntityManager resourceEntityManager = commandContext.getResourceEntityManager();
				DeploymentEntity deployment = (DeploymentEntity)repositoryService.createDeploymentQuery()
						.deploymentId(processDefinition.getDeploymentId()).singleResult();
				
				// 删除原资源
				resourceEntityManager.deleteResourcesByDeploymentId(deployment.getId());
				Context.getCommandContext().getSession(DbSqlSession.class).flush();
				
				// 插入新资源
			    ResourceEntity resource = new ResourceEntity();
			    resource.setDeploymentId(deployment.getId());
			    resource.setName(procDefName + ".bpmn20.xml");
			    resource.setBytes(bpmnBytes);
				deployment.addResource(resource);
				resourceEntityManager.insertResource(resource);
				
				// 插入资源图片
				ProcessEngineConfigurationImpl processEngineConfiguration = Context.getProcessEngineConfiguration();
				byte[] diagramBytes = IoUtil.readInputStream(processEngineConfiguration.
	                    getProcessDiagramGenerator().generateDiagram(bpmnModel, "png", processEngineConfiguration.getActivityFontName(),
	                        processEngineConfiguration.getLabelFontName(),processEngineConfiguration.getAnnotationFontName(), processEngineConfiguration.getClassLoader()), null);
				ResourceEntity diagramResource = new ResourceEntity();
				diagramResource.setDeploymentId(deployment.getId());
				diagramResource.setName(procDefName + "." + processDefinition.getKey() + ".png");
				diagramResource.setBytes(diagramBytes);
				deployment.addResource(diagramResource);
				resourceEntityManager.insertResource(diagramResource);
			}
			// 不存在部署一个新的流程 ThinkGem
			else{ 
				repositoryService.createDeployment().name(procDefName).addInputStream(
						procDefName + ".bpmn20.xml", new ByteArrayInputStream(bpmnBytes)).deploy();
			}
		}catch(Exception e){
			throw new ActivitiException("模型部署到流程定义错误", e);
		}
		return null;
	}
}