package com.blueland.bpm.engine.core.service.impl;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.CallActivity;
import org.activiti.bpmn.model.ExclusiveGateway;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.ManualTask;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.ReceiveTask;
import org.activiti.bpmn.model.ScriptTask;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.ServiceTask;
import org.activiti.bpmn.model.SubProcess;
import org.activiti.bpmn.model.UserTask;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.util.io.InputStreamSource;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.validation.ProcessValidator;
import org.activiti.validation.ProcessValidatorFactory;
import org.activiti.validation.ValidationError;
import org.apache.commons.lang3.StringUtils;
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.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.blueland.bpm.common.util.BeanUtils;
import com.blueland.bpm.engine.config.model.ActivityInfoConfig;
import com.blueland.bpm.engine.config.model.ActivityRule;
import com.blueland.bpm.engine.config.model.ProcessInfoConfig;
import com.blueland.bpm.engine.config.service.ActivityInfoConfigManager;
import com.blueland.bpm.engine.config.service.ActivityRuleManager;
import com.blueland.bpm.engine.config.service.ProcessInfoConfigManager;
import com.blueland.bpm.engine.core.cmd.SetProcessDefinitionNameCmd;
import com.blueland.bpm.engine.core.model.ExceptionErrorCode;
import com.blueland.bpm.engine.core.model.ProcessDefinitionModel;
import com.blueland.bpm.engine.core.service.AbstractServiceHelper;
import com.blueland.bpm.engine.core.service.ProcessDefinitionService;
import com.blueland.bpm.engine.core.service.ProcessModelService;
import com.blueland.bpm.engine.util.ProcessModelUtils;
import com.blueland.bpm.engine.util.WorkFlowException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**程模型Service
 * @version:  1.0
 * @author lw 
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = false)
public class ProcessModelServiceImpl  extends AbstractServiceHelper implements ProcessModelService {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private ProcessDefinitionService processDefinitionService;
	@Autowired
	private ActivityInfoConfigManager activityInfoConfigManager;
	
	@Autowired
	private ProcessInfoConfigManager processInfoConfigManager;
	@Autowired
	ActivityRuleManager activityRuleManager;
	
	/**
	 * 将流程Json模型转换成字节码
	 * @param modelData
	 * @return byte[]
	 */
	@Override
	public byte[] convertJsonModelToByte(String modelId) {
		BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
		byte[] bpmnBytes =null;
		try {
			JsonNode editorNode = new ObjectMapper().readTree(repositoryService
					.getModelEditorSource(modelId));
			BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);	
			BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
			bpmnBytes = xmlConverter.convertToXML(bpmnModel);
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2008,"Error parsing model",e);
		}
		return bpmnBytes;
	}
	
	
	/**
	 * 将流程模型转换成字节码
	 * @param modelData
	 * @return byte[]
	 */
	@Override
	public byte[] convertBpmnModelToByte(BpmnModel bpmnModel) throws WorkFlowException{
		byte[] bpmnBytes =null;
		updateProcessStarter("",bpmnModel);
		BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
		bpmnBytes = xmlConverter.convertToXML(bpmnModel);
		return bpmnBytes;
	}
	
	/**
	 * 将流程模型转换成字节码
	 * @param modelData
	 * @return byte[]
	 */
	@Override
	public byte[] convertBpmnModelToByte(BpmnModel bpmnModel,String processDefId) throws WorkFlowException{
		byte[] bpmnBytes =null;
		updateProcessStarter(processDefId,bpmnModel);
		BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
		bpmnBytes = xmlConverter.convertToXML(bpmnModel);
		return bpmnBytes;
	}
	
	/**
	 * 将流程模型转换成字节码
	 * @param modelData
	 * @return byte[]
	 */
	@Override
	public BpmnModel convertJsonModelToBpmnModel(Model modelData) throws WorkFlowException{
		BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
		BpmnModel bpmnModel =null;
		try {
			JsonNode editorNode = new ObjectMapper().readTree(repositoryService
					.getModelEditorSource(modelData.getId()));
			 bpmnModel = jsonConverter.convertToBpmnModel(editorNode);	
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2008,"Error parsing model",e);
		} 
		return bpmnModel;
	}
	
	
	/**
	 * 根据模型ID来获取BpmnModel
	 * @param modelId
	 * @return BpmnModel
	 */
	@Override
	public BpmnModel getBpmnModelByModelId(String modelId) {
		Model model=this.getRepositoryService().getModel(modelId);
		BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
		BpmnModel bpmnModel = null;
		try {
			JsonNode editorNode = new ObjectMapper().readTree(repositoryService
					.getModelEditorSource(model.getId()));
			bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2008,"Error parsing model",e);
		} 
		return bpmnModel;
	}
	@Override
	public BpmnModel getBpmnModelByProcDefId(String procDefId){
		BpmnModel bpmnModel = processDefinitionService.getRepositoryService().getBpmnModel(procDefId);
		return bpmnModel;
	}

	
	@Override
	public BpmnModel convertFileToBpmnModel(InputStream in) {
		BpmnModel bpmnModel = null;
		try {
			BpmnXMLConverter converter = new BpmnXMLConverter();
			boolean enableSafeBpmnXml = false;
			if (Context.getProcessEngineConfiguration() != null) {
				enableSafeBpmnXml = Context.getProcessEngineConfiguration()
						.isEnableSafeBpmnXml();
			}
			bpmnModel = converter.convertToBpmnModel(new InputStreamSource(in),
					true, enableSafeBpmnXml);
			// 外部平台导入BPMN文件有可能isExecutable=false,导致引擎不会解析bpmn文件,所以需要加此判断
			if (bpmnModel.getMainProcess() != null
					&& !bpmnModel.getMainProcess().isExecutable()) {
				bpmnModel.getMainProcess().setExecutable(true);
			}
			if (bpmnModel == null)
				throw new WorkFlowException(ExceptionErrorCode.B2008,"解析BPMN文件失败,请您验证BPMN文件是否有效！");
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2008,"Error parsing XML",e);
		}
		return bpmnModel;
	}
	
	@Override
	@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
	public boolean syncBpmnModelToDb(ProcessDefinitionModel processDefinition) {
		BpmnModel bpmnModel = getBpmnModelByProcDefId(processDefinition.getProcDefId());
		boolean result=syncProcess(bpmnModel, processDefinition, null);
		if(result){
			result=syncActivity(bpmnModel, processDefinition,null);
		}
		return result;
	}
	
	@Override
	@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
	public boolean syncBpmnModelToDb(ProcessDefinitionModel processDefinition,String modelId) {
		BpmnModel bpmnModel = getBpmnModelByModelId(modelId);
		ProcessInfoConfig prevVersionProcessConfig= processInfoConfigManager.getPrevVersionProcessConfig(processDefinition.getProcDefId());
		boolean result=syncProcess(bpmnModel, processDefinition, prevVersionProcessConfig);
		if(result){
			result=syncActivity(bpmnModel, processDefinition,prevVersionProcessConfig);
		}
		try{
			if(prevVersionProcessConfig!=null){
				prevVersionProcessConfig.setProcessMgrIsshow(ProcessInfoConfig.PROCESS_MGR_ISSHOW_N);
				processInfoConfigManager.update(prevVersionProcessConfig);
			}
		}catch(Exception e){e.printStackTrace();}
		return result;
	}

	private boolean syncProcess(BpmnModel bpmnModel,
			ProcessDefinitionModel processDefinition,
			ProcessInfoConfig prevVersionProcessConfig) {
		ProcessInfoConfig processInfoConfig = processInfoConfigManager
				.getById(processDefinition.getProcDefId());
		ProcessInfoConfig addProcessInfoConfig = new ProcessInfoConfig();
		String newProcessDefName=bpmnModel.getProcesses().get(0).getName();
		//流程名称变更逻辑处理
		if(!newProcessDefName.equals(processDefinition.getProcDefName())){
			activityInfoConfigManager.updateByProcessDefName(processDefinition.getProcDefId(),newProcessDefName);
			processDefinitionService.getManagementService().executeCommand(new SetProcessDefinitionNameCmd(processDefinition.getProcDefId(),newProcessDefName));
			processDefinition.setProcDefName(newProcessDefName);
		}
		// 待新增、更新的环节节点
		if (processInfoConfig == null) {
			if (prevVersionProcessConfig != null) {
				prevVersionProcessConfig.setLastUpdateTime(new Date());
				prevVersionProcessConfig.setCreateTime(new Date());
				BeanUtils.copyProperties(addProcessInfoConfig,
						prevVersionProcessConfig);
				addProcessInfoConfig.setProcessDefId(processDefinition
						.getProcDefId());
				addProcessInfoConfig.setProcessDefKey(processDefinition
						.getProcDefKey());
				addProcessInfoConfig.setProcessDefName(processDefinition
						.getProcDefName());
				addProcessInfoConfig.setDeploymentId(processDefinition
						.getDeploymentId());
				addProcessInfoConfig.setProcessVersion(processDefinition
						.getVersion());
				Date nowDate = new Date();
				addProcessInfoConfig.setCreateTime(nowDate);
				addProcessInfoConfig.setLastUpdateTime(nowDate);
				addProcessInfoConfig.setProcessStartIsshow("Y");
				addProcessInfoConfig.setProcessMgrState("UNRELEASE");
				try {
					List<ActivityRule> activityRules = activityRuleManager
							.findActivityRules(prevVersionProcessConfig
									.getProcessDefId(),"");
					for (ActivityRule activityRule : activityRules) {
						activityRule.setProcDefId(processDefinition
								.getProcDefId());
						activityRuleManager.save(activityRule);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else {
				addProcessInfoConfig = ProcessInfoConfig
						.build(processDefinition);
			}
			processInfoConfigManager.save(addProcessInfoConfig);
		} else {
			processInfoConfig.setLastUpdateTime(new Date());
			processInfoConfig.setProcessDefName(processDefinition.getProcDefName());
			processInfoConfig.setProcessVersion(processDefinition.getVersion());
			processInfoConfig.setDeploymentId(processDefinition
					.getDeploymentId());
			processInfoConfigManager.update(processInfoConfig);
		}
		return true;
	}
	
	
	
	private boolean syncActivity(BpmnModel bpmnModel,ProcessDefinitionModel processDefinition,ProcessInfoConfig prevVersionProcessConfig){
		List<ActivityInfoConfig> activityInfoConfigs = activityInfoConfigManager
				.findActivityInfoConfigs(processDefinition.getProcDefId());
		// 待新增、更新的环节节点
		for (Process process : bpmnModel.getProcesses()) {
			
			List <FlowElement> allFlowElements=new ArrayList<FlowElement>();
			//递归找出所有流程环节,主要递归内部嵌套子流程
			addAllFlowElement((List<FlowElement>) process.getFlowElements(),allFlowElements);
			// 待新增、更新的环节节点
			syncActivityByAddOrUpdate(process.getName(),allFlowElements,activityInfoConfigs,processDefinition,prevVersionProcessConfig);
			// 待删除的环节节点
			syncActivityByDelete(activityInfoConfigs,allFlowElements);
		}
		return true;
	}

	private void syncActivityByDelete(
			List<ActivityInfoConfig> activityInfoConfigs,
			List<FlowElement> flowElements) {
		// 待删除的环节节点
		for (ActivityInfoConfig actInfoConfig : activityInfoConfigs) {
			int isDel = 0;
			for (FlowElement flowElement : flowElements) {
				//过滤掉不处理的任务节点
				if (this.isFilterTask(flowElement)) {
					continue;
				}
				if (flowElement.getId().equalsIgnoreCase(
						actInfoConfig.getActivityDefId())) {
					// isDel=0时表示未查询到actInfoConfig,执行删除操作
					isDel++;
					break;
				}
			}
			if (isDel == 0) {
				activityInfoConfigManager.remove(actInfoConfig.getProcessDefId(),actInfoConfig
						.getActivityDefId());
			}
		}
	}
	
	
	private void addAllFlowElement(List <FlowElement> flowElements,List <FlowElement> allFlowElements){
		for (FlowElement flowElement : flowElements) {
			//过滤掉不处理的任务节点
			if (this.isFilterTask(flowElement)) {
				continue;
			}
			if (SubProcess.class.isInstance(flowElement)) {
				addAllFlowElement((ArrayList<FlowElement>) ((SubProcess) flowElement).getFlowElements(),allFlowElements);
				continue;
			}
			allFlowElements.add(flowElement);
		}
	}
	
	private void syncActivityByAddOrUpdate(String processName,
			List<FlowElement> flowElements,
			List<ActivityInfoConfig> activityInfoConfigs,
			ProcessDefinitionModel processDefinition,
			ProcessInfoConfig prevVersionProcessConfig) {
		int actOrder = 1;
		for (FlowElement flowElement : flowElements) {
			//过滤掉不处理的任务节点
			if (this.isFilterTask(flowElement)) {
				continue;
			}
			// Task task = (Task) flowElement;
			String flowElementId = flowElement.getId();
			String flowElementName = flowElement.getName();
			// 更新标记
			int isUpdate = 0;
			ActivityInfoConfig updateActInfoConfig = null;
			for (ActivityInfoConfig actInfoConfig : activityInfoConfigs) {
				if (flowElementId.equalsIgnoreCase(actInfoConfig
						.getActivityDefId())) {
					// isUpdate>0说明查询到actInfoConfig,执行更新操作,否则执行新增操作
					isUpdate++;
					updateActInfoConfig = actInfoConfig;
					break;
				}
			}
			if (isUpdate > 0) {
				// 暂时只更新环节ID和名称
				updateActInfoConfig.setActivityDefId(flowElementId);
				updateActInfoConfig.setActivityDefName(flowElementName);
				activityInfoConfigManager.update(updateActInfoConfig);
				// updateActInfoConfigs.add(temepActInfoConfig);
			} else {
				// 暂时只新增流程定义ID和名称、环节ID和名称
				ActivityInfoConfig addActInfoConfig = null;
				if (prevVersionProcessConfig != null) {
					ActivityInfoConfig prevVesionActivityInfoConfig = activityInfoConfigManager
							.getActivityInfoConfig(
									prevVersionProcessConfig.getProcessDefId(),
									flowElementId);
					if (prevVesionActivityInfoConfig != null) {
						addActInfoConfig = prevVesionActivityInfoConfig;
						addActInfoConfig.setProcessDefId(processDefinition
								.getProcDefId());
						addActInfoConfig.setProcessDefName(processName);
						addActInfoConfig.setActivityDefId(flowElementId);
						addActInfoConfig.setActivityDefName(flowElementName);
					}
				}
				if (addActInfoConfig == null) {
					addActInfoConfig = ActivityInfoConfig.build(flowElement,
							processDefinition.getProcDefId(), processName);
				}
				if(addActInfoConfig.getActivityOrder()==null){
					addActInfoConfig.setActivityOrder(actOrder);
				}
				activityInfoConfigManager.save(addActInfoConfig);
				actOrder++;
			}
		}

	}
	
	public void updateProcessStarter(String processDefId, BpmnModel bpmnModel) {
		UserTask userTask = ProcessModelUtils.findStartUserTask(bpmnModel);
		bpmnModel.getMainProcess().getCandidateStarterGroups().clear();
		bpmnModel.getMainProcess().getCandidateStarterOrgs().clear();
		bpmnModel.getMainProcess().getCandidateStarterUsers().clear();

		if (userTask.getCandidateGroups() != null
				&& !userTask.getCandidateGroups().isEmpty()
				&& bpmnModel.getMainProcess().getCandidateStarterGroups()
						.isEmpty()) {
			bpmnModel.getMainProcess().getCandidateStarterGroups()
					.addAll(userTask.getCandidateGroups());
		}
		if (userTask.getCandidateUsers() != null
				&& !userTask.getCandidateUsers().isEmpty()
				&& bpmnModel.getMainProcess().getCandidateStarterUsers()
						.isEmpty()) {
			bpmnModel.getMainProcess().getCandidateStarterUsers()
					.addAll(userTask.getCandidateUsers());
		}
		if (userTask.getCandidateOrgs() != null
				&& !userTask.getCandidateOrgs().isEmpty()
				&& bpmnModel.getMainProcess().getCandidateStarterOrgs()
						.isEmpty()) {
			bpmnModel.getMainProcess().getCandidateStarterOrgs()
					.addAll(userTask.getCandidateOrgs());
		}
		if (!StringUtils.isEmpty(processDefId)) {
			for (String groupId : bpmnModel.getMainProcess()
					.getCandidateStarterGroups()) {
				processDefinitionService.getRepositoryService()
						.deleteCandidateStarterGroup(processDefId, groupId);
				processDefinitionService.getRepositoryService()
						.addCandidateStarterGroup(processDefId, groupId);
				;
			}
			for (String userId : bpmnModel.getMainProcess()
					.getCandidateStarterUsers()) {
				processDefinitionService.getRepositoryService()
						.deleteCandidateStarterUser(processDefId, userId);
				processDefinitionService.getRepositoryService()
						.addCandidateStarterUser(processDefId, userId);
				;
			}
			for (String orgId : bpmnModel.getMainProcess()
					.getCandidateStarterOrgs()) {
				processDefinitionService.getRepositoryService()
						.deleteCandidateStarterOrg(processDefId, orgId);
				processDefinitionService.getRepositoryService()
						.addCandidateStarterOrg(processDefId, orgId);
				;
			}
		}
	}
	@Override
	public boolean syncProcessModelToJsonModel(String procDefId){
		ProcessDefinition processDefinition = processDefinitionService
				.getRepositoryService().createProcessDefinitionQuery()
				.processDefinitionId(procDefId).singleResult();
		if(processDefinition==null){
			throw new WorkFlowException(ExceptionErrorCode.B2002,"流程定义ID["+procDefId+"]无效");
		}
		
		InputStream bpmnStream = processDefinitionService
				.getRepositoryService().getResourceAsStream(
						processDefinition.getDeploymentId(),
						processDefinition.getResourceName());
		XMLInputFactory xif = XMLInputFactory.newInstance();
		XMLStreamReader xtr=null;
		try {
			InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
			xtr = xif.createXMLStreamReader(in);
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2008,e.getMessage());
		}
		
		BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
		updateProcessStarter(procDefId,bpmnModel);
		BpmnJsonConverter converter = new BpmnJsonConverter();
		ObjectNode modelNode = converter.convertToJson(bpmnModel);
		Model modelData = null;
		List<Model> modelDatas = processDefinitionService.getRepositoryService()
				.createModelQuery()
				.modelTenantId(processDefinition.getTenantId())
				.modelKey(processDefinition.getKey()).list();
		if(modelDatas!=null&&!modelDatas.isEmpty()){
			modelData=modelDatas.get(0);
		}else{
			modelData = processDefinitionService.getRepositoryService().newModel();
		}
		modelData.setKey(processDefinition.getKey());
		modelData.setName(processDefinition.getName());
		modelData.setDeploymentId(processDefinition.getDeploymentId());
		modelData.setTenantId(processDefinition.getTenantId());

		ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
		modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME,
				processDefinition.getName());
		modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION,
				processDefinition.getVersion());
		modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION,
				processDefinition.getDescription());
		modelData.setMetaInfo(modelObjectNode.toString());
		modelData.setModelState("RELEASE");
		// 内部默认会选择新增或者更新
		processDefinitionService.getRepositoryService().saveModel(modelData);
		try {
			processDefinitionService.getRepositoryService().addModelEditorSource(
					modelData.getId(), modelNode.toString().getBytes("utf-8"));
			//更新bpmn.xml
			processDefinitionService.updateDeploymentResource(processDefinition.getDeploymentId(),procDefId,this.convertBpmnModelToByte(bpmnModel),false);
			//更新流程定义缓存
			processDefinitionService.refreshProcessDefineCache(procDefId);
		
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2009,e.getMessage());
		}
		return true;

	}

	
	@Override
	public void syncProcessModelToJsonModelByUpdate(String modelKey){
		ProcessDefinition processDefinition = processDefinitionService
				.getRepositoryService().createProcessDefinitionQuery().latestVersion().processDefinitionKey(modelKey).singleResult();
		if(processDefinition==null){
			return;
		}
		ProcessInfoConfig processInfoConfig=processInfoConfigManager.getById(processDefinition.getId());
		if(processInfoConfig==null||!processInfoConfig.isUpdate()){
			return;
		}
		Model modelData = getModel(processDefinition.getKey(),processDefinition.getTenantId());
		InputStream bpmnStream = processDefinitionService
				.getRepositoryService().getResourceAsStream(
						processDefinition.getDeploymentId(),
						processDefinition.getResourceName());
		XMLInputFactory xif = XMLInputFactory.newInstance();
		XMLStreamReader xtr=null;
		try {
			InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
			xtr = xif.createXMLStreamReader(in);
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2008,e.getMessage());
		}
		
		BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
		updateProcessStarter(processDefinition.getId(),bpmnModel);
		BpmnJsonConverter converter = new BpmnJsonConverter();
		ObjectNode modelNode = converter.convertToJson(bpmnModel);
		if(modelData==null){
			modelData = processDefinitionService.getRepositoryService().newModel();
		}
		modelData.setKey(processDefinition.getKey());
		modelData.setName(processDefinition.getName());
		modelData.setDeploymentId(processDefinition.getDeploymentId());
		modelData.setTenantId(processDefinition.getTenantId());

		ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
		modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME,
				processDefinition.getName());
		modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION,
				processDefinition.getVersion());
		modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION,
				processDefinition.getDescription());
		modelData.setMetaInfo(modelObjectNode.toString());
		// 内部默认会选择新增或者更新
		processDefinitionService.getRepositoryService().saveModel(modelData);
		try {
			processDefinitionService.getRepositoryService().addModelEditorSource(
					modelData.getId(), modelNode.toString().getBytes("utf-8"));
			//更新bpmn.xml
			processDefinitionService.updateDeploymentResource(processDefinition.getDeploymentId(),processDefinition.getId(),this.convertBpmnModelToByte(bpmnModel),false);
		
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2009,e.getMessage());
		}

	}
	
	
	/**
	 * 验证BPMN文件
	 * @param in
	 * @return
	 */
	public List<ValidationError> validateBpmnXml(InputStream in) {
		List<ValidationError> validationErrors = null;
		try {
			BpmnModel bpmnModel = this.convertFileToBpmnModel(in);
			ProcessValidator processValidator = new ProcessValidatorFactory()
					.createDefaultProcessValidator();
			validationErrors = processValidator.validate(bpmnModel);
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2008,"Error parsing XML",e);
		}
		return validationErrors;
	}
	/**
	 * 验证BPMN模型
	 * @param in
	 * @return
	 */
	public List<ValidationError> validateBpmnModel(BpmnModel bpmnModel) {
		List<ValidationError> validationErrors = null;
		try {
			ProcessValidator processValidator = new ProcessValidatorFactory()
					.createDefaultProcessValidator();
			validationErrors = processValidator.validate(bpmnModel);
		} catch (Exception e) {
			throw new WorkFlowException(ExceptionErrorCode.B2008,"Error parsing XML",e);
		}
		return validationErrors;
	}
	

	/**
	 * 根据Model部署流程
	 */
	@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
	public String deploy(String modelId,String tenantId) {
		byte[] bpmnBytes = null;
		String result="";
		try {
			if(StringUtils.isEmpty(modelId)){
				result="传入modelId为空值,无法找到模型！";
				return result;
			}
			Model modelData = repositoryService.getModel(modelId);
			BpmnModel bpmnModel = convertJsonModelToBpmnModel(modelData);
			/*
			List<ValidationError> validationErrors = null;
			try {
				validationErrors =validateBpmnModel(bpmnModel);
			} catch (Exception e) {
				logger.error("",e);
				return "验证bpmn.xml出现异常，非法的bpmn.xml";
			}
			if (!validationErrors.isEmpty()) {
				return validationErrors.toString();
			}*/
		    bpmnBytes=convertBpmnModelToByte(bpmnModel);
			String processName = modelData.getName() + ".bpmn20.xml";
			DeploymentBuilder deploymentBuilder=repositoryService.createDeployment();
			deploymentBuilder.name(modelData.getName());
			deploymentBuilder.tenantId(tenantId);
			Deployment deployment = deploymentBuilder.addInputStream(processName, new ByteArrayInputStream(bpmnBytes)).deploy();
			
			modelData.setDeploymentId(deployment.getId());
			modelData.setModelState("RELEASE");
			repositoryService.saveModel(modelData);
			result="部署成功";
			//同步模型到数据库中
			ProcessDefinitionModel proceDefModel=processDefinitionService.getProcessDefBykey(modelData.getKey());
			syncBpmnModelToDb(proceDefModel,modelId);
		} catch (Exception e) {
			String errorMsg=String.format("根据流程模型[%s]来部署流程失败,错误信息:[%s]", modelId,e.getLocalizedMessage());
			logger.error(errorMsg,e);
			result=errorMsg;
		}
		return result;
	}
	


	/**
	 * 判断流程是否已部署
	 */
	public boolean isPprocessDeployment (String modelId,String tenantId) {
		boolean result = false;
		try {
			if(StringUtils.isEmpty(modelId)){
				return result;
			}
			Model modelData = repositoryService.getModel(modelId);
			ProcessDefinitionModel proceDefModel=processDefinitionService.getProcessDefBykey(modelData.getKey());
			if(proceDefModel!=null){
				result=true;
			}
		} catch (Exception e) {
			String errorMsg=String.format("判断流程是否已部署出现异常,modelId:[%s],错误信息:[%s]", modelId,e.getLocalizedMessage());
			logger.error(errorMsg,e);
		}
		return result;
	}
	
	

	/**
	 * 判断流程是否更新中
	 */
	public boolean isProcessUpdate(String modelId) {
		boolean result = true;
		try {
			if(StringUtils.isEmpty(modelId)){
				return result;
			}
			Model modelData = repositoryService.getModel(modelId);
			if(modelData==null){
				return result;
			}
			ProcessDefinitionModel proceDefModel=processDefinitionService.getProcessDefBykey(modelData.getKey());
			if(proceDefModel==null){
				return result;
			}
			ProcessInfoConfig processInfoConfig = processInfoConfigManager
					.getById(proceDefModel.getProcDefId());
			if(processInfoConfig==null){
				return result;
			}
			if(processInfoConfig.isUpdate()){
				 result=false;
			}
			
		} catch (Exception e) {
			String errorMsg=String.format("判断流程是否修订出现异常,modelId:[%s],错误信息:[%s]", modelId,e.getLocalizedMessage());
			logger.error(errorMsg,e);
		}
		return result;
	}
	
	

	/**
	 * 
	 */
	public String getFlowElementUptMsg(String modelId) {
		String msg = "";
		try {
			
			BpmnModel newBpmnModel=this.getBpmnModelByModelId(modelId);
			Model modelData = repositoryService.getModel(modelId);
			
			ProcessDefinitionModel proceDefModel=processDefinitionService.getProcessDefBykey(modelData.getKey());
			BpmnModel oldBpmnModel=this.getBpmnModelByProcDefId(proceDefModel.getProcDefId());
			// 待新增、更新的环节节点
			for (Process oldprocess : oldBpmnModel.getProcesses()) {
				List<FlowElement> oldflowElements=(List<FlowElement>) oldprocess.getFlowElements();
				for (FlowElement oldflowElement : oldflowElements) {
					for (Process newprocess : newBpmnModel.getProcesses()) {
						if(newprocess.getFlowElement(oldflowElement.getId())==null&&(!SequenceFlow.class.isInstance(oldflowElement))){
							if(StringUtils.isNotEmpty(oldflowElement.getName())){
								msg+=oldflowElement.getName()+",";
							}
						}
						
					}
				}
			}
			if(StringUtils.isNotEmpty(msg)){
				msg+="这些节点已删除或ID已变更,请生成新版本部署！";
			}
			
		} catch (Exception e) {
			String errorMsg=String.format("判断流程是否修订出现异常,modelId:[%s],错误信息:[%s]", modelId,e.getLocalizedMessage());
			logger.error(errorMsg,e);
		}
		return msg;
	}

	/**
	 * 直接覆盖已有流程定义版本，并更新流程定义的缓存
	 */
	@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
	public String deployCascodeUpdate(String modelId) {
		byte[] bpmnBytes = null;
		String result="";
		try {
			if(StringUtils.isEmpty(modelId)){
				result="传入modelId为空值,无法找到模型！";
				return result;
			}
			//获取Model
			Model modelData = repositoryService.getModel(modelId);
			BpmnModel bpmnModel = convertJsonModelToBpmnModel(modelData);
			/*List<ValidationError> validationErrors = null;
			try {
				validationErrors = validateBpmnModel(bpmnModel);
			} catch (Exception e) {
				logger.error("",e);
				return "验证bpmn.xml出现异常，非法的bpmn.xml";
			}
			if (!validationErrors.isEmpty()) {
				return validationErrors.toString();
			}*/
			//获取最新版本的流程定义
			ProcessDefinitionModel proceDefModel=processDefinitionService.getProcessDefBykey(modelData.getKey());
			//将bpmnModel转换成字节数组
		    bpmnBytes= convertBpmnModelToByte(bpmnModel,proceDefModel.getProcDefId());
			if(proceDefModel!=null){
				//更新bpmn.xml
				processDefinitionService.updateDeploymentResource(proceDefModel.getDeploymentId(),proceDefModel.getProcDefId(),bpmnBytes,true);
				//更新流程定义缓存
				processDefinitionService.refreshProcessDefineCache(proceDefModel.getProcDefId());
				result="部署成功";
			}
			//同步模型到数据库中
			syncBpmnModelToDb(proceDefModel,modelId);
			updateModelState(proceDefModel.getProcDefKey(), proceDefModel.getTenantId(), "RELEASE");
		} catch (Exception e) {
			logger.error("根据模型部署流程失败：modelId={}", modelId, e);
			result="根据模型部署流程失败，原因："+e.getCause().getMessage();
		}
		return result;
	}
	
	
	
	
	@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
	public BpmnModel importBpmnFile(byte[] fileBytes, String tenantId) {
		BpmnModel bpmnModel = null;
		try {
			bpmnModel = convertFileToBpmnModel(new ByteArrayInputStream(
					fileBytes));
		} catch (Exception e) {
			this.logger.error("", e);
			throw new WorkFlowException(ExceptionErrorCode.B2008,"非法的BPMN文件!");
		}
		Model oldModel = repositoryService.createModelQuery()
				.modelKey(bpmnModel.getMainProcess().getId()).singleResult();
		if (oldModel != null && !oldModel.getTenantId().equals(tenantId)) {
			throw new WorkFlowException(ExceptionErrorCode.B2010,
					String.format(
							"[%s]应用系统已经存在KEY为[%s]的流程模型,系统不允许导入重复KEY的流程模型,请您手工修改文件中的流程KEY",
							oldModel.getTenantId(), bpmnModel.getMainProcess()
									.getId()));
		}

		try {
			BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
			ObjectNode editorNode = jsonConverter.convertToJson(bpmnModel);
			ObjectMapper objectMapper = new ObjectMapper();
			editorNode.put("id", "canvas");
			editorNode.put("resourceId", "canvas");
			ObjectNode stencilSetNode = objectMapper.createObjectNode();
			stencilSetNode.put("namespace",
					"http://b3mn.org/stencilset/bpmn2.0#");
			editorNode.put("stencilset", stencilSetNode);

			ObjectNode propertiesNode = objectMapper.createObjectNode();
			propertiesNode
					.put("process_id", bpmnModel.getMainProcess().getId());
			propertiesNode.put("name", bpmnModel.getMainProcess().getName());
			editorNode.put("properties", propertiesNode);

			Model modelData = repositoryService.newModel();
			modelData.setTenantId(tenantId);
			modelData.setKey(StringUtils.defaultString(bpmnModel
					.getMainProcess().getId()));
			if (oldModel != null) {
				modelData.setId(oldModel.getId());
				modelData.setRevision(oldModel.getRevision());
			} else {
				modelData.setRevision(1);
			}
			ObjectNode modelObjectNode = objectMapper.createObjectNode();
			modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, bpmnModel
					.getMainProcess().getName());
			modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION,
					modelData.getRevision());
			String description = StringUtils.defaultString(bpmnModel
					.getMainProcess().getDocumentation());
			modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION,
					description);
			modelData.setMetaInfo(modelObjectNode.toString());
			modelData.setName(bpmnModel.getMainProcess().getName());
			modelData.setModelState("RELEASE");
			repositoryService.saveModel(modelData);
			repositoryService.addModelEditorSource(modelData.getId(),
					editorNode.toString().getBytes("utf-8"));

		} catch (Exception e) {
			this.logger.error("导入流程模型失败!", e);
			throw new WorkFlowException(ExceptionErrorCode.B2010,"导入流程模型失败!", e);

		}
		return bpmnModel;
	}
	
	private void validateModel(String key){
		Model oldModel=repositoryService.createModelQuery().modelKey(key).singleResult();
		if(oldModel!=null){
			throw new WorkFlowException(ExceptionErrorCode.B2010,String.format("[%s]应用系统已经存在KEY为[%s]的流程模型,请您重新输入流程模型KEY!",oldModel.getTenantId(),key));
		}
	}
	
	public void copy(String modelId, String name, String key,
			String description) {
		validateModel(key);
		try {
			if (StringUtils.isEmpty(modelId)) {
				return ;
			}
			Model oldModelData = repositoryService.getModel(modelId);
			if (oldModelData == null) {
				return ;
			}
			ObjectMapper objectMapper = new ObjectMapper();
			ObjectNode editorNode = (ObjectNode) objectMapper
					.readTree(repositoryService
							.getModelEditorSource(oldModelData.getId()));
			if (editorNode == null) {
				return;
			}

			ObjectNode propertiesNode = objectMapper.createObjectNode();
			propertiesNode.put("process_id", key);
			propertiesNode.put("name", name);
			editorNode.put("properties", propertiesNode);

			Model modelData = repositoryService.newModel();
			ObjectNode modelObjectNode = objectMapper.createObjectNode();
			modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
			modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
			description = StringUtils.defaultString(description);
			modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION,
					description);
			modelData.setMetaInfo(modelObjectNode.toString());
			modelData.setName(name);
			modelData.setKey(StringUtils.defaultString(key));
			modelData.setTenantId(oldModelData.getTenantId());
			modelData.setModelState("UNRELEASE");
			repositoryService.saveModel(modelData);
			repositoryService.addModelEditorSource(modelData.getId(),
					editorNode.toString().getBytes("utf-8"));

		} catch (Exception e) {
			logger.error("复制模型失败：", e);
			throw new WorkFlowException(ExceptionErrorCode.B2010,String.format("复制模型失败"),e);
		}
	}

	/**
	 * 创建模型
	 */
	public String create(String name, String key, String description,String tenantId) {
		String modelId="";
		validateModel(key);
		try {
			ObjectMapper objectMapper = new ObjectMapper();
			ObjectNode editorNode = objectMapper.createObjectNode();
			editorNode.put("id", "canvas");
			editorNode.put("resourceId", "canvas");
			ObjectNode stencilSetNode = objectMapper.createObjectNode();
			stencilSetNode.put("namespace",
					"http://b3mn.org/stencilset/bpmn2.0#");
			editorNode.put("stencilset", stencilSetNode);
			
			ObjectNode propertiesNode = objectMapper.createObjectNode();
			propertiesNode.put("process_id",key);
			propertiesNode.put("name",name);
			editorNode.put("properties", propertiesNode);
			Model modelData = repositoryService.newModel();
			ObjectNode modelObjectNode = objectMapper.createObjectNode();
			modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
			modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
			description = StringUtils.defaultString(description);
			modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION,
					description);
			modelData.setMetaInfo(modelObjectNode.toString());
			modelData.setName(name);
			modelData.setKey(StringUtils.defaultString(key));
			modelData.setTenantId(tenantId);
			repositoryService.saveModel(modelData);
			repositoryService.addModelEditorSource(modelData.getId(),
					editorNode.toString().getBytes("utf-8"));
			modelId= modelData.getId();
		} catch (Exception e) {
			logger.error("创建模型失败：", e);
			throw new WorkFlowException(ExceptionErrorCode.B2010,String.format("创建模型失败"),e);
		}
		return modelId;
		
	}


	@Override
	public void updateModelState(String key, String tenantId,String modelState) {
		Model model=null;
		try{
			model=getModel(key,tenantId);
		}catch(Exception e){
			logger.error("",e);
			return;
		}
		model.setModelState(modelState);
		repositoryService.saveModel(model);
	}

	private Model getModel(String procDefKey,String tenantId){
		if(procDefKey==null){
			throw new WorkFlowException(ExceptionErrorCode.B2001,"流程定义KEY["+procDefKey+"]不能为空");
		}
		if(tenantId==null){
			throw new WorkFlowException(ExceptionErrorCode.B2001,"租户ID["+tenantId+"]不能为空");
		}
		List<Model> modelDatas = processDefinitionService.getRepositoryService()
				.createModelQuery()
				.modelTenantId(tenantId)
				.modelKey(procDefKey).list();
		if(modelDatas!=null&&modelDatas.size()>1){
			throw new WorkFlowException(ExceptionErrorCode.B2010,"流程模型存在["+modelDatas.size()+"]份数据,modelDatas:"+modelDatas);
		}if(modelDatas.isEmpty()){
			throw new WorkFlowException(ExceptionErrorCode.B2002,"流程定义KEY和租户ID无法查询出Model对象,procDefKey:"+procDefKey+",tenantId:"+tenantId);
			
		}
		return modelDatas.get(0);
	}
	
	/**
	 * 过滤掉不处理的任务节点
	 * @param flowElement
	 * @return
	 */
	private boolean isFilterTask(FlowElement flowElement){
		if (!ExclusiveGateway.class.isInstance(flowElement)
				&& !UserTask.class.isInstance(flowElement)
				&& !SubProcess.class.isInstance(flowElement)
				&& !ScriptTask.class.isInstance(flowElement)
				&& !ServiceTask.class.isInstance(flowElement)
				&& !CallActivity.class.isInstance(flowElement)
				&& !ReceiveTask.class.isInstance(flowElement)
				&& !ManualTask.class.isInstance(flowElement)) {
			return true;
		}
		return false;
	}
	
}
