package com.artfess.bpm.listener;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.artfess.base.exception.BaseException;
import com.artfess.base.feign.FormFeignService;
import com.artfess.base.groovy.GroovyScriptEngine;
import com.artfess.base.util.AppUtil;
import com.artfess.base.util.Base64;
import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.JsonUtil;
import com.artfess.base.util.StringUtil;
import com.artfess.base.util.ThreadMsgUtil;
import com.artfess.bpm.api.cmd.ActionCmd;
import com.artfess.bpm.api.cmd.BaseActionCmd;
import com.artfess.bpm.api.cmd.TaskFinishCmd;
import com.artfess.bpm.api.constant.BpmConstants;
import com.artfess.bpm.api.constant.DataType;
import com.artfess.bpm.api.context.ContextThreadUtil;
import com.artfess.bpm.api.model.process.def.NodeProperties;
import com.artfess.bpm.api.model.process.inst.BpmProcessInstance;
import com.artfess.bpm.api.model.process.nodedef.ext.extmodel.ProcBoDef;
import com.artfess.bpm.api.model.process.task.BpmTask;
import com.artfess.bpm.api.service.BoDataService;
import com.artfess.bpm.api.service.DataObjectHandler;
import com.artfess.bpm.engine.def.BpmDefUtil;
import com.artfess.bpm.exception.HandlerException;
import com.artfess.bpm.model.BoDataModifyRecord;
import com.artfess.bpm.persistence.manager.BoDataModifyRecordManager;
import com.artfess.bpm.persistence.manager.BpmBusLinkManager;
import com.artfess.bpm.persistence.manager.BpmProcessInstanceManager;
import com.artfess.bpm.persistence.model.BpmBusLink;
import com.artfess.bpm.persistence.model.DefaultBpmProcessDefExt;
import com.artfess.bpm.persistence.model.DefaultBpmProcessInstance;
import com.artfess.bpm.persistence.model.DefaultBpmTask;
import com.artfess.bpm.util.BoDataUtil;
import com.artfess.bpm.util.BpmUtil;
import com.artfess.bpm.util.HandlerUtil;
import com.artfess.table.operator.ITableOperator;
import com.artfess.table.operator.impl.mysql.MySQLTableOperator;
import com.artfess.uc.api.impl.util.ContextUtil;
import com.artfess.uc.api.model.IUser;

public class BusDataUtil {


	/**
	 * 处理bo数据到业务中间关联表。
	 *
	 * @param model
	 * @param boResult
	 *            void
	 */
	public static void handlerBusinessLink(BpmProcessInstance instance,List<ObjectNode> boResults,String saveMode) {
		BpmBusLinkManager bpmBusLinkManager =AppUtil.getBean(BpmBusLinkManager.class);
		List<BpmBusLink> insertBusLinks = new ArrayList<BpmBusLink>();
		List<Map<String, Object>> deleteBusLinks = new ArrayList<Map<String, Object>>();
		Set<String> addSet = new HashSet<String>();
		for(ObjectNode result:boResults){

			ObjectNode boEnt=(ObjectNode) result.get("boEnt");

			boolean isNumber= BeanUtils.isNotEmpty(boEnt.get("pkType"))&&"number".equals(JsonUtil.getString(boEnt, "pkType"));

			String action=result.get("action").asText();
			if("add".equals(action)){

				BpmBusLink busLink = BpmUtil.buildBusLink(instance,result,saveMode);
				//创建分区。
				createPartition(busLink.getFormIdentify());
				addSet.add(isNumber?busLink.getBusinesskey().toString():busLink.getBusinesskeyStr());
				insertBusLinks.add(busLink);
			}

			else if("del".equals(action)) {
				deleteBusLinks.add(getParams(result.get("pk").asText(), result.get("boEnt").get("name").asText(), isNumber));
			}
			//更新暂不做处理。
			else if("upd".equals(action)){
				// 用已有的表单数据启动流程
				BpmBusLink bbl = bpmBusLinkManager.getByBusinesKey(result.get("pk").asText(), isNumber);
				if(BeanUtils.isEmpty(bbl) && !addSet.contains(result.get("pk").asText())){
					BpmBusLink busLink = BpmUtil.buildBusLink(instance,result,saveMode);
					//创建分区。
					createPartition(busLink.getFormIdentify());
					insertBusLinks.add(busLink);
				}

			}
		}
		//批量新增
		if(BeanUtils.isNotEmpty(insertBusLinks)){
			bpmBusLinkManager.saveBatch(insertBusLinks);
		}
		//批量删除
		if(BeanUtils.isNotEmpty(deleteBusLinks)){
			bpmBusLinkManager.delBatchByBusinesKey(deleteBusLinks);
		}
	}
	
	private static Map<String, Object> getParams(String businessKey, String formIdentity,
			boolean isNumber){
		Map<String, Object> params=new HashMap<String, Object>();
		
		if(isNumber){
			params.put("businessKey", Long.parseLong(businessKey));
		}
		else{
			params.put("businessKey", businessKey);
		}
		
		if(StringUtil.isNotEmpty(formIdentity)){
			params.put("formIdentity", formIdentity);
		}
		
		params.put("isNumber", isNumber);
		
		return params;
	}

	/**
	 * 是否支持分区。
	 */
	private static int  supportPart=-1;

	private static Set<String> partions= Collections.synchronizedSet(new HashSet<String>());

	private static final String tableName="bpm_bus_link";

	/**
	 * 创建分区。
	 * @param partName
	 */
	private static void createPartition(String partName){
		if(StringUtil.isEmpty(partName)) return;

		ITableOperator tableOperator=(ITableOperator)AppUtil.getBean("tableOperator");
		if(tableOperator==null) return;
		// TODO MySQL动态创建分区的语句有误，在MySQL中不能对字符串类型的字段创建 LIST分区
		if(tableOperator instanceof MySQLTableOperator){
			return;
		}
		if(supportPart==-1){
			//表是否支持分区。
			boolean isSupport=tableOperator.supportPartition(tableName);
			supportPart=isSupport?1:0;
		}

		if(supportPart==0) return;
		//是否存在指定的分区。
		if(partions.contains(partName)) return;

		boolean isPartExist=tableOperator.isExsitPartition(tableName, partName);

		//添加缓存partions
		partions.add(partName);

		if(isPartExist) return;

		tableOperator.createPartition(tableName, partName);
	}



	/**
	 * 处理多个业务主键的业务中间表数据问题。
	 * @param cmd
	 */
	public static void handExt(ActionCmd cmd){
		Map<String,String> pairs= cmd.getDataPair();
		if(BeanUtils.isNotEmpty(pairs)) return ;
		//添加中间表。
		addBusLink(cmd);
	}


	//构建bpm_bus_link;
	private static void addBusLink(ActionCmd cmd){
		BpmProcessInstanceManager bpmProcessInstanceManager=AppUtil.getBean(BpmProcessInstanceManager.class);

		BpmBusLinkManager bpmBusLinkManager=AppUtil.getBean(BpmBusLinkManager.class);

		String instId=cmd.getInstId();

		Map<String,String> pairs=cmd.getDataPair();

		DataType dataType= cmd.getPkDataType();

		BpmProcessInstance instance= bpmProcessInstanceManager.get(instId);

		boolean isNumber=!DataType.STRING.equals(dataType);

		for (Map.Entry<String, String> entry : pairs.entrySet()) {
			String key=entry.getKey();
			String val=entry.getValue();

			BpmBusLink bpmBusLink = bpmBusLinkManager.getByBusinesKey(val, key, isNumber);
			if(bpmBusLink!=null) continue;

			BpmBusLink busLink=BpmUtil.buildBusLink(instance);
			busLink.setIsMain(1);
			busLink.setFormIdentify(key);

			if(!isNumber){
				busLink.setBusinesskeyStr(val);
			}
			else{
				busLink.setBusinesskey(Long.parseLong( val));
			}
			//添加分区。
			createPartition(key);

			bpmBusLinkManager.create(busLink);
		}
	}

	/**
	 * 支持处理器。
	 * @param properties
	 * @param actionCmd
	 * @param isBefore
	 */
	public static void executeHandler(NodeProperties properties,ActionCmd actionCmd,boolean isBefore ){
		if(properties==null) return;


		String handler=isBefore?properties.getPrevHandler():properties.getPostHandler();
		if(StringUtil.isEmpty(handler)) return;

		try{
			HandlerUtil.invokeHandler(actionCmd,handler );
		}
		catch(Exception ex){
			throw new HandlerException(ex.getMessage(), ex.getCause());
		}
	}
	
	
	/**
	 * 通过流程实例id和任务id更新bo数据
	 * @param instId 实例id
	 * @param nodeId 节点id，如果能获取到请务必传入。不然可能导致子表权限计算异常
	 * @param formData 表单数据字符串（base64解密后的）
	 * @throws Exception
	 */
	public static void updateBoData(String instId,String nodeId, String formData) throws Exception{
        ActionCmd actionCmd = ContextThreadUtil.getActionCmd();
        DefaultBpmProcessInstance instance =null;
        if (BeanUtils.isNotEmpty(actionCmd) && BeanUtils.isNotEmpty(actionCmd.getTransitVars(BpmConstants.PROCESS_INST))) {
        	instance = (DefaultBpmProcessInstance) actionCmd.getTransitVars(BpmConstants.PROCESS_INST);
		}
        if (BeanUtils.isEmpty(instance)) {
        	BpmProcessInstanceManager instanceManager = AppUtil.getBean(BpmProcessInstanceManager.class);
        	instance = instanceManager.get(instId);
        	if (BeanUtils.isEmpty(instance)) {
        		throw new BaseException(String.format("根据实例id【%s】未找到流程实例", instId));
			}
		}
		DefaultBpmProcessDefExt bpmProcessDefExt = BpmDefUtil.getProcessExt(instance);
        List<ObjectNode> boDatas = BusDataUtil.transFormDataToBoData(bpmProcessDefExt, formData);
	    ObjectNode[] dataArray = boDatas.toArray(new ObjectNode[boDatas.size()]);
	    updateBoData(instance.getId(),nodeId,dataArray);
	}
	
	/**
	 * 通过流程实例对象，更新bo数据
	 * @param instance 流程实例对象
	 * @param nodeId 节点id，如果能获取到请务必传入。不然可能导致子表权限计算异常
	 * @param formData 表单数据字符串（base64解密后的）
	 * @throws Exception
	 */
	public static void updateBoData(DefaultBpmProcessInstance instance,String nodeId, String formData) throws Exception{
		if (BeanUtils.isEmpty(instance)) {
    		throw new BaseException("根据实例对象更新表单数据时，实例对象不能为空");
		}
		DefaultBpmProcessDefExt bpmProcessDefExt = BpmDefUtil.getProcessExt(instance);
        List<ObjectNode> boDatas = BusDataUtil.transFormDataToBoData(bpmProcessDefExt, formData);
	    ObjectNode[] dataArray = boDatas.toArray(new ObjectNode[boDatas.size()]);
	    updateBoData(instance.getId(),nodeId,dataArray);
	}
	

	/**
	 * 通过流程实例id，更新bodata
	 * @param instanceId  实例id
	 * @param boDatas boData数组
	 */
	private static void updateBoData(String instanceId,String nodeId, ObjectNode...boDatas){
	     FormFeignService formRestfulService=AppUtil.getBean(FormFeignService.class);
	     List<List<ObjectNode>> boResultList = formRestfulService.batchHandlerBoData(getFormRestParamByBoDatas(instanceId,nodeId,false,boDatas));
	     BusDataUtil.handlerBodataModify(boResultList);
	}

	private  static void handlerBodataModify(List<List<ObjectNode>> boResultList ){
		BaseActionCmd actionCmd = (BaseActionCmd) ContextThreadUtil.getActionCmd();
		BoDataModifyRecordManager boDataModifyRecordManager = AppUtil.getBean(BoDataModifyRecordManager.class);
		if(BeanUtils.isEmpty(actionCmd)){
			return;
		}
		List<BoDataModifyRecord> saveList = new ArrayList<>();
		for (List<ObjectNode> boResult : boResultList) {
			String modifyRes = "";
			String refId = "";
			String data = "";
			for (ObjectNode objectNode : boResult) {
				if (objectNode.hasNonNull("modifyDetail") && StringUtil.isNotEmpty(objectNode.get("modifyDetail").asText())) {
					modifyRes = objectNode.get("modifyDetail").asText();
					data = objectNode.get("data").asText();
					refId = objectNode.get("pk").asText();
					break;
				}
			}
			if (StringUtil.isEmpty(modifyRes)) {
				continue;
			}
			BoDataModifyRecord record = new BoDataModifyRecord();
			//添加外键
			if(StringUtil.isNotEmpty(refId)) {
				record.setRefId(refId);
			}
			if (actionCmd instanceof TaskFinishCmd) {
				record.setReason(((TaskFinishCmd)actionCmd).getApprovalOpinion());
			}
			record.setInstId(actionCmd.getInstId());
			record.setModifyTime(LocalDateTime.now());
			IUser currentUser = ContextUtil.getCurrentUser();
			record.setUserId(currentUser.getUserId());
			record.setUserName(currentUser.getFullname());
			DefaultBpmTask task =(DefaultBpmTask) actionCmd.getTransitVars(BpmConstants.BPM_TASK);
			if (BeanUtils.isNotEmpty(task)) {
				record.setTaskId(task.getTaskId());
				record.setNodeId(task.getNodeId());
				record.setTaskName(task.getName());
			}
			record.setDetail(modifyRes);
			record.setData(data);
			saveList.add(record);
		}
		boDataModifyRecordManager.saveOrUpdateBatch(saveList);
	}


	/**
	 * 处理bo数据。
	 * @param instance
	 * @param cmd
	 * @throws Exception
	 */
	@SuppressWarnings("rawtypes")
	public static void handSaveBoData(BpmProcessInstance instance,  ActionCmd cmd) throws Exception  {
		Object taskObj = cmd.getTransitVars(BpmConstants.BPM_TASK);
		BpmTask bpmTask = null;

		if(BeanUtils.isNotEmpty(taskObj) && taskObj instanceof BpmTask) {
			bpmTask = (BpmTask)taskObj;
			// 如果是启动流程时跳过第一个节点时 不再处理bo数据
			if(bpmTask.getSkipResult().isSkipTask()) {
				return;
			}
		}
		String boJson=cmd.getBusData();
		FormFeignService formRestfulService=AppUtil.getBean(FormFeignService.class);
		if(StringUtil.isEmpty(boJson)) {
			BoDataService boDataService = AppUtil.getBean(BoDataService.class);
			List<ObjectNode> boDatas = boDataService.getDataByInst(instance);
			Map<String,ObjectNode> boMap=new HashMap<String, ObjectNode>();
			for(ObjectNode data:boDatas){
				String code="";
				if(data.hasNonNull("boDefAlias")){
					code = data.get("boDefAlias").asText();
				}else  {
					code=data.get("boDef").get("alias").asText();
				}
				ObjectNode bodefByAlias = formRestfulService.getBodefByAlias(code);
				if(BeanUtils.isNotEmpty(bodefByAlias) && "forbidden".equals(bodefByAlias.get("status").asText())) throw new BaseException("该流程绑定的表单所对应的业务建模已被禁用，无法启动。");
				boMap.put(code, data);
			}
			// 将BO放入cmd上下文中。
			cmd.getTransitVars().put(BpmConstants.BO_INST, boMap);
			return;
		}
		
		DataObjectHandler dataObjectHandler=AppUtil.getBean(DataObjectHandler.class);
		DefaultBpmProcessDefExt bpmProcessDefExt = BpmDefUtil.getProcessExt(instance);
		List<ObjectNode> boDatas=transFormDataToBoData(bpmProcessDefExt, boJson);
		String nodeId = "";
		if(BeanUtils.isNotEmpty(bpmTask)){
			nodeId = bpmTask.getNodeId();
			dataObjectHandler.handSaveData(instance,nodeId, boDatas);
		}else{
			dataObjectHandler.handSaveData(instance, boDatas);
		}
		cmd.addTransitVars(BpmConstants.PROCESS_INST,instance);
		List<ObjectNode> formRestParams = getFormRestParamByBoDatas(instance.getId(),nodeId,true,boDatas.toArray(new ObjectNode[boDatas.size()]));
		String saveType="database";
		//批量处理bodata
		List<List<ObjectNode>> boResultList= formRestfulService.batchHandlerBoData(formRestParams);
		
		String formKey= cmd.getFormKey();
		List formDataTemplateExtendList = null;
		if (StringUtil.isNotEmpty(formKey)) {
			formDataTemplateExtendList = formRestfulService.getDataTemplateExtendByFormKey(formKey);
		}
		Map<String, ObjectNode> boMap = new HashMap<String, ObjectNode>();
		for (int i = 0; i < boDatas.size(); i++) {
			List<ObjectNode> boResults =  boResultList.get(i);
			ObjectNode boData  = boDatas.get(i);
			ObjectNode boEnt =(ObjectNode) boData.get("boEnt");
			ObjectNode def= (ObjectNode) boData.get("boDef");
			if (!def.get("supportDb").asBoolean()) {
				saveType="boObject";
			}
			String id= formRestParams.get(i).get("boid").asText();
			for(ObjectNode result : boResults) {
				//新增完毕后将主键放入bodata，以免用户任务1之后的脚本任务无法更新数据
				if (JsonUtil.getString(result, "parentId", "").equals("0") && "add".equals(result.get("action").asText())) {
					ThreadMsgUtil.addMapMsg("curBoPkVal", result.get("pk").asText());
					boData.put(boEnt.get("pkKey").asText(), result.get("pk").asText());
				}
			}
			if(StringUtil.isNotEmpty(formKey)){
				handeDataTemplateExtend(id,boData,boResults,formDataTemplateExtendList);
			}
			//处理业务中间表数据信息。
			BusDataUtil.handlerBusinessLink(instance, boResults,saveType);
			boMap.put(def.get("alias").asText(), boData);
		}
		//新增表单修改记录
		BusDataUtil.handlerBodataModify(boResultList);
		// 将BO放入cmd上下文中。
		cmd.getTransitVars().put(BpmConstants.BO_INST, boMap);
	}
	
	@SuppressWarnings("rawtypes")
	private static void handeDataTemplateExtend(String id,ObjectNode boData,List<ObjectNode> boResults, List formDataTemplateExtendList) throws IOException{
		FormFeignService formRestfulService=AppUtil.getBean(FormFeignService.class);
		GroovyScriptEngine groovyScriptEngine=AppUtil.getBean(GroovyScriptEngine.class);
		if(StringUtil.isNotEmpty(id)){
			formRestfulService.deleteFormRemindDataByBoDataId(id);
		}else{
			ObjectNode a =boResults.stream().filter(b->"add".equals(b.get("action").asText())).findAny().orElse(null);
			if(a!=null){
				id=a.get("pk").asText();
			}
		}
		List<ObjectNode> insertList=new ArrayList<>();
		for (int i = 0; i <formDataTemplateExtendList.size() ; i++) {
			JsonNode formDataTemplateExtend=JsonUtil.toJsonNode(formDataTemplateExtendList.get(i));
			String scriptJson= formDataTemplateExtend.get("rule").asText();
			if(StringUtil.isEmpty(scriptJson)){
				continue;
			}
			JsonNode node = JsonUtil.toJsonNode(scriptJson);
			String script=node.get("scriptStr").asText();
			boolean res= groovyScriptEngine.executeBoolean(Base64.getFromBase64(script),JsonUtil.toMap(boData.toString()));
			if(res){//符合提醒条件
				String typeObj= formDataTemplateExtend.get("typeObj").asText();
				String objId= formDataTemplateExtend.get("objId").asText();
				String content= formDataTemplateExtend.get("content").asText();
				String count= formDataTemplateExtend.get("count").asText();
				String subject= formDataTemplateExtend.get("subject").asText();
				String refId=formDataTemplateExtend.get("id").asText();
				if(typeObj.equals("script")){
					objId=boData.get(objId).asText();
					ObjectNode formRemindData=JsonUtil.getMapper().createObjectNode();
					formRemindData.put("content", content);
					formRemindData.put("count", count);
					formRemindData.put("objId", objId);
					formRemindData.put("typeObj", "user");
					formRemindData.put("opemId", id);
					formRemindData.put("subject", subject);
					formRemindData.put("refId", refId);
					formRemindData.put("opemType", formDataTemplateExtend.get("alias").asText());
					insertList.add(formRemindData);
				}else{
					String[] objIds= objId.split(",");
					for (int j = 0; j <objIds.length ; j++) {
						ObjectNode formRemindData=JsonUtil.getMapper().createObjectNode();
						formRemindData.put("content", content);
						formRemindData.put("count", count);
						formRemindData.put("objId", objIds[j]);
						formRemindData.put("typeObj", typeObj);
						formRemindData.put("opemId", id);
						formRemindData.put("subject", subject);
						formRemindData.put("refId", refId);
						formRemindData.put("opemType", BeanUtils.isNotEmpty(formDataTemplateExtend.get("alias"))?formDataTemplateExtend.get("alias").asText():"");
						insertList.add(formRemindData);
					}
				}
			}
		}
		formRestfulService.saveBatch(insertList);
	}

	/**
	 * 将前端传入的表单数据转化成List BoData
	 * @param bpmProcessDefExt 流程定义扩展类
	 * @param boJson 表单数据
	 * @return
	 * @throws IOException
	 */
	public static List<ObjectNode> transFormDataToBoData(DefaultBpmProcessDefExt  bpmProcessDefExt,  String boJson) throws IOException  {
		
		ObjectNode jsonObj = (ObjectNode) JsonUtil.toJsonNode(boJson);
		// 验证BO数据。
		BoDataUtil.validBo(bpmProcessDefExt, jsonObj);
		// BO Map数据。
		Map<String, ObjectNode> jsonMap = BoDataUtil.getMap(jsonObj);
		
		FormFeignService formRestfulService=AppUtil.getBean(FormFeignService.class);
		
		List<ObjectNode> boDatas=new ArrayList<ObjectNode>();

		Set<String> set=jsonMap.keySet();
		if (BeanUtils.isEmpty(set)) {
			return new ArrayList<>();
		}
		List<ProcBoDef> list = bpmProcessDefExt.getBoDefList();
		Set<String> bindBoSet=new HashSet<>();
		for (ProcBoDef boDef : list) {
			bindBoSet.add(boDef.getKey());
		}
		//先校验传入的formData是否规范
		for (String string : set) {
			if (!bindBoSet.contains(string)) {
				throw new BaseException(String.format("表单数据有误，流程并未绑定含有别名为【%s】的建模", string));
			}
		}
		//根据建模别名批量获取数据建模
		List<ObjectNode> bodefsByAliasList = formRestfulService.getBodefWithMainEntByAlias(StringUtil.join(set));
		for (ObjectNode bodefByAlias : bodefsByAliasList) {
			if(BeanUtils.isNotEmpty(bodefByAlias) && "forbidden".equals(bodefByAlias.get("status").asText())){
				 throw new BaseException(String.format("该流程绑定的表单所对应的业务建模【%s】已被禁用，无法启动。", bodefByAlias.get("description").asText()));
			}
			ObjectNode json = jsonMap.get(bodefByAlias.get("alias").asText());
			//BO数据。
			ObjectNode curData= (ObjectNode) BoDataUtil.transJSON(json);
			//为了适应之前的逻辑，把boent从bodef里取出来
			curData.set("boEnt", bodefByAlias.get("boEnt"));
			bodefByAlias.remove("boEnt");
			curData.set("boDef", bodefByAlias);
			curData.set("data", json);
			boDatas.add(curData);
		}
		return boDatas;
	}

    /**
     * 整理bodata数据，返回保存bodata需要的Param
     * @param instId
     * @param checkFormDataRev
     * @param boDatas
     * @return
     */
    public static List<ObjectNode> getFormRestParamByBoDatas(String instId,String nodeId,boolean checkFormDataRev,ObjectNode...boDatas){
        BpmBusLinkManager  bpmBusLinkManager=AppUtil.getBean(BpmBusLinkManager.class);
        Map<String,BpmBusLink> linkMap=bpmBusLinkManager.getMapByInstId(instId);
        ActionCmd actionCmd = ContextThreadUtil.getActionCmd();

        if (StringUtil.isEmpty(nodeId)) {
        	nodeId = (String) ContextThreadUtil.getCommuVar("nodeId","");
		}
        
        DefaultBpmProcessInstance instance =null;
        if (BeanUtils.isNotEmpty(actionCmd)) {
        	if (BeanUtils.isNotEmpty(actionCmd.getTransitVars(BpmConstants.PROCESS_INST))) {
        		instance = (DefaultBpmProcessInstance) actionCmd.getTransitVars(BpmConstants.PROCESS_INST);
			}
        	if (StringUtil.isEmpty(nodeId) && BeanUtils.isNotEmpty( actionCmd.getTransitVars(BpmConstants.BPM_TASK))) {
        		nodeId =( (DefaultBpmTask) actionCmd.getTransitVars(BpmConstants.BPM_TASK)).getNodeId();
			}
		}
        if (BeanUtils.isEmpty(instance)) {
        	BpmProcessInstanceManager instanceManager = AppUtil.getBean(BpmProcessInstanceManager.class);
        	instance = instanceManager.get(instId);
        	if (BeanUtils.isEmpty(instance)) {
        		throw new BaseException(String.format("根据实例id【%s】未找到流程实例", instId));
			}
		}
        
        if (StringUtil.isEmpty(nodeId)) {
        	nodeId = (String) ContextThreadUtil.getCommuVar("nodeId","");
		}
        
        String saveType="database";
        List<ObjectNode> formRestParams = new ArrayList<>();
        for (ObjectNode boData : boDatas) {
            ObjectNode boEnt =(ObjectNode) boData.get("boEnt");
            ObjectNode def= (ObjectNode) boData.get("boDef");
            String id="";
            //新增
            if(BeanUtils.isNotEmpty(linkMap)){
                BpmBusLink busLink=linkMap.get(def.get("alias").asText());
                //取得主键。
                if(busLink!= null){
                    boolean isNumber="number".equals(JsonUtil.getString(boEnt, "pkType"));
                    id=isNumber? busLink.getBusinesskey().toString():  busLink.getBusinesskeyStr();
                }
            }
            if (!def.get("supportDb").asBoolean()) {
            	saveType="boObject";
			}
            ObjectNode formRestParam=JsonUtil.getMapper().createObjectNode();
    
            if (StringUtil.isEmpty(nodeId)) {
            	nodeId = JsonUtil.getString(boData, "nodeId");
    		}
            formRestParam.put("boid", id);
            formRestParam.put("defId", def.get("id").asText());
            formRestParam.set("boData", boData);
            formRestParam.put("saveType", saveType);
            formRestParam.put("flowDefId", instance.getProcDefId());
            formRestParam.put("flowKey", instance.getProcDefKey());
            formRestParam.put("nodeId",nodeId);
            formRestParam.put("parentDefKey",BpmConstants.LOCAL);
            formRestParam.put("hasCheckFormDataRev", checkFormDataRev);
            if (BeanUtils.isNotEmpty(actionCmd)) {
            	formRestParam.put("formkey", actionCmd.getFormKey());
			}
            if (StringUtil.isEmpty(id)) {
				formRestParam.put("updateSubTableJson",(String) ThreadMsgUtil.getMapMsg("updateSubTableJson"));
			}
            formRestParams.add(formRestParam);
        }
		return formRestParams;
    }
    
}
