package com.sagacloud.utils;

import com.google.common.base.Strings;
import com.sagacloud.broadcast.MessageHandler;
import com.sagacloud.dict.CsStaticInfo;
import com.sagacloud.dict.EqStaticInfo;
import com.sagacloud.dict.InfosUtil;
import com.sagacloud.dict.TlStaticInfo;
import com.sagacloud.endpoints.VirtualObject;
import com.sagacloud.endpoints.item.PhysicalObject;
import com.sagacloud.exception.IdGenException;
import com.sagacloud.exception.OperationFailedException;
import com.sagacloud.exception.WrongInfosException;
//import com.sagacloud.json.JSONArray;
//import com.sagacloud.json.JSONObject;
//import com.sagacloud.json.JSONValue;
import com.alibaba.fastjson.*;
import com.sagacloud.utils.jsonHelper.infoPoint.InfoPoint;
import com.sagacloud.utils.objectLog.ActivityLogObject;
import com.sagacloud.utils.objectLog.ActivityLogRunnable;
import com.sagacloud.utils.objectLog.ActivityLogUtil;
import com.sagacloud.utils.objects.*;
import com.sagacloud.utils.relationUtils.RelationUtil;
import com.sagacloud.utils.relationUtils.SubsetUtil;
import com.sagacloud.utils.tables.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by Xiaoyu on 2017/12/27
 */
public class ObjectUtil {
    private static final Logger log = LoggerFactory.getLogger(ObjectUtil.class);

    /**
     * 根据updateIdSet集合指定的id，将批量新增参数参数转为批量更新参数并执行批量更新操作
	 * @param projectId 项目id,Pj开头
	 * @param postBody 批量新增参数
	 * @param insetResultBody 执行批量新增接口后的结果对象
	 * @param updateIdSet 需要进行更新的对象id集合
	 * @return
	 */
	public static String insertParamToExcuteUpdate(String projectId, JSONObject postBody, JSONObject insetResultBody,
			Set<String> updateIdSet) {
		String insertBatchResult;
		JSONObject jsonUpdateBatch = new JSONObject();
		// 选填, 当有信息点不属于指定类型的时候, 跳过错误信息点, 默认false不跳过, true是跳过
		jsonUpdateBatch.put("skipErrorInfo", postBody.get("skipErrorInfo")==null?false:postBody.get("skipErrorInfo"));
		// 选填(修改信息点时使用), 是否覆盖该设备信息点到关联的资产, 默认是true覆盖, false是不覆盖
		jsonUpdateBatch.put("coverInfos", postBody.get("coverInfos")==null?false:postBody.get("coverInfos"));
		
		JSONArray criteriasUpdate = new JSONArray();
		JSONArray criteriasInsert = postBody.getJSONArray("criterias");
		if(null != criteriasInsert) {
			JSONObject tempItem = null;
			
			for(int i=0; i<criteriasInsert.size(); i++) {
				tempItem = criteriasInsert.getJSONObject(i);
				
				if(updateIdSet.contains(tempItem.getString("id"))) {
					JSONObject updateItem = new JSONObject();
					updateItem.put("id", tempItem.getString("id"));
					updateItem.put("infos", tempItem.getJSONObject("infos"));
					criteriasUpdate.add(updateItem);
				}
			}
			
			if(!criteriasUpdate.isEmpty()) {
				jsonUpdateBatch.put("criterias", criteriasUpdate);
				
				String updateResult = null;
				try {
		            CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(jsonUpdateBatch);
		            HashMap<String, HashSet<String>> idInfos = new HashMap<>();
		            if (cqc.isCoverInfos()) {
		            	JSONArray criterias = (JSONArray) jsonUpdateBatch.get("criterias");
		                for (Object criteria : criterias) {
		                    JSONObject singleObj = (JSONObject) criteria;
		                    if (singleObj.get("id") == null || idInfos.containsKey(singleObj.get("id").toString()) || !DpUtils.checkId(singleObj.get("id").toString()))
		                        throw new Exception("请检查Id!");
		                    JSONObject infos = (JSONObject) singleObj.get("infos");
		                    HashSet<String> infoSet = new HashSet<>(infos.keySet());
		                    idInfos.put(singleObj.get("id").toString(), infoSet);
		                }
		            }
		            ArrayList<String> error = ObjectUtil.batchUpdate(projectId, (JSONArray) jsonUpdateBatch.get("criterias"), true, false, true, cqc);
		            if (cqc.isCoverInfos()) {
		                PropertyUtil.syncInfos(projectId.substring(2), idInfos);
		            }
		            if (error.size() > 0) {
		                StringBuilder sb = new StringBuilder();
		                for (String str : error)
		                    sb.append(str).append('|');
		                sb.deleteCharAt(sb.length() - 1);
		                updateResult = DpUtils.errorJsonMsg(sb.toString());
		            }
		            updateResult = DpUtils.successJsonMsg("");
		        } catch (Exception ex) {
		            ex.printStackTrace();
		            updateResult = DpUtils.errorJsonMsg(ex.getMessage());
		        }
				
				// 批量更新失败
				if(null != updateResult && updateResult.contains("failure")) {
					JSONObject updateResultJson = JSONObject.parseObject(updateResult);
					insetResultBody.put("error_update", updateResultJson.getJSONObject("ResultMsg"));
					insetResultBody.put("Result", "failure");
				}
			}
		}
		
		insertBatchResult = insetResultBody.toJSONString();
		return insertBatchResult;
	}
    
    public static String genObjId(String pjId, String objType, String idPre) throws IdGenException {
        JSONObject re = null;
        try {
            re = CommonUtil.querySimpleObjs(pjId, objType, idPre, false);
            String countStr = DecimalTONBigit.toString((int) (re.getLongValue("Count") + 1));
            String formatStr = "%1$3s";
            if (objType.startsWith(Const.OBJ_TYPE_VO)) {
                formatStr = "%1$4s";
            }
            String genId = String.format(formatStr, countStr).replace(' ', '0');
            JSONArray arr = (JSONArray) re.get("Content");
            for (int i = 0; i < arr.size(); i++) {
                if (((String) (((JSONObject) arr.get(i)).get(ObjectTable.KEY_OBJ_ID))).endsWith(genId)) {
                    countStr = DecimalTONBigit.toString(DecimalTONBigit.toInt(countStr) + 1);
                    genId = String.format(formatStr, countStr).replace(' ', '0');
                    i = -1;
                }
            }
            return idPre + genId;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IdGenException();
        }
    }

    /**
     * @param areaCode
     * @return 4位项目id
     * @throws IdGenException
     */
    public static String genPjId(String areaCode) throws IdGenException {
        try {

            JSONObject json = JSONObject.parseObject("{\"QueryType\":\"select\",\"Datatable\":\"projects\"}");
            json.put("Database", OssUtils.getProperty("database.name"));
            JSONObject criteria = new JSONObject();
            JSONObject range = new JSONObject();
            range.put("$gte", areaCode);
            range.put("$lte", areaCode + "9999");
            criteria.put(ProjectTable.KEY_PJ_ID, range);
            json.put(Const.JSON_FIELD_CRITERIA, criteria);
            json = ZillionAgentProvider.GetAgent().Query(json);
            if (json.getLongValue("Count") + 1 > 9999) {
                throw new IdGenException();
            }
            String countStr = String.valueOf(json.getLongValue("Count") + 1);
            String genId = String.format("%1$4s", countStr).replace(' ', '0');
            JSONArray content = (JSONArray) json.get("Content");
            for (int i = 0; i < content.size(); i++) {
                if (((String) (((JSONObject) content.get(i)).get(ProjectTable.KEY_PJ_ID))).endsWith(genId)) {
                    countStr = String.valueOf(Long.valueOf(countStr) + 1);
                    genId = String.format("%1$4s", countStr).replace(' ', '0');
                    i = -1;
                }
            }
            return genId;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IdGenException();
        }
    }

    public static String addVirtualObj(String pjId, String objType, String userId, JSONObject infos, ObjectType ot, ObjectIdName name, boolean isMonitor) throws Exception {
        JSONObject insertObj = new JSONObject();
        insertObj.put(ObjectTable.KEY_PJ_ID, pjId);
        insertObj.put(ObjectTable.KEY_OBJ_TYPE, objType);
        String objId = DpUtils.generateUUID("", true);
        if(userId != null && userId.length() > 0){
            if(!objType.equals(userId.substring(0, 4)))
                throw new Exception("id和类型不匹配");
            objId = userId.substring(14);
        }
        try {
            insertObj.put(ObjectTable.KEY_OBJ_ID, objId);
            insertObj.put(ObjectTable.COL_VALID, true);
//            json.put("InsertObject", insertObj);
            // 开始检验信息点valid
            String missingInfo = null;
            String realId = CommonUtil.combineId(pjId, objType, objId);
            if (ot.equals(ObjectType.equipment) || ot.equals(ObjectType.system) || ot.equals(ObjectType.component)) {
                missingInfo = InfosUtil.CheckIntegrityAtCreation(pjId, ot, objType.substring(4), infos, realId, name);
            } else {
                missingInfo = InfosUtil.CheckIntegrityAtCreation(pjId, ot, objType, infos, realId, name);
            }
            if (missingInfo != null)
                throw new WrongInfosException("信息点名称错误: " + missingInfo);
            // 检测完毕
            insertObj.put(ObjectTable.KEY_CREATE_TIME, name.getCreateTime());
            JSONObject re = CommonUtil.insert(false ,HBaseTable.objects, insertObj);
            if (!re.get("Result").toString().equalsIgnoreCase("success")) {
                throw new OperationFailedException();
            }else if(re.getIntValue("Count") > 0){
                throw new Exception("指定id已存在");
            }
            JSONArray arr = new JSONArray();
            JSONObject oneObject = new JSONObject();
            oneObject.put(ObjInfosTable.KEY_PJ_ID, pjId);
            oneObject.put(ObjInfosTable.KEY_OBJ_TYPE, objType);
            oneObject.put(ObjInfosTable.KEY_OBJ_ID, objId);
            oneObject.put(Const.JSON_FIELD_JSON_DATA_INFOS, infos);
            if (ot.equals(ObjectType.building) && !infos.containsKey("Holiday")) {
                JSONArray holiday = new JSONArray();
                JSONObject holidayValue = new JSONObject();
                holiday.add(holidayValue);
                StringBuilder sb = new StringBuilder();
                sb.append(pjId).append(objId).append("-1");
                holidayValue.put("value", sb.toString());
                holidayValue.put("time", CommonUtil.getTime());
                infos.put("Holiday", holiday);
            }
            arr.add(oneObject);
            ArrayList<String> errors = new ArrayList<>();
            try {
                errors = batchUpdate(pjId, arr, false, true, false, new CommonQueryCriteria());
            } catch (Exception ex) {
            }
            // 打印错误信息到日志
            if (errors.size() > 0) {
                StringBuilder sb = new StringBuilder();
                for (String error : errors)
                    sb.append(error).append('|');
                log.error(sb.toString());
            }
            if (isMonitor)
                ActivityLogUtil.objectLog(realId, name.getCreateTime(), ot, MQType.objectCreate);
            return realId;
        } catch (IdGenException e) {
            log.error("Failed to generate id.");
            throw new OperationFailedException();
        } catch (WrongInfosException ex) {
            throw ex;
        } catch (Exception e) {
            throw new OperationFailedException();
        }
    }

    public static String addObj(String pjId, String objType, String subType, JSONObject infos, ObjectType ot, ObjectIdName name, String assignedObjId, boolean isMonitor) throws Exception {
        JSONObject json = JSONObject.parseObject("{\"QueryType\":\"insert\",\"Datatable\":\"objects\"}");
        json.put("Database", OssUtils.getProperty("database.name"));
        JSONObject insertObj = new JSONObject();
        insertObj.put(ObjectTable.KEY_PJ_ID, pjId);
        insertObj.put(ObjectTable.KEY_OBJ_TYPE, objType);
        String objId = null;
        try {
            if (assignedObjId != null) {
                objId = assignedObjId;
            } else {
//                objId = genObjId(pjId, objType, idPre);
                objId = DpUtils.generateUUID("", true);
            }

            insertObj.put(ObjectTable.KEY_OBJ_ID, objId);
            insertObj.put(ObjectTable.COL_VALID, true);
            json.put("InsertObject", insertObj);
            // 开始检验信息点valid
            String missingInfo = null;
            String realId = CommonUtil.combineId(pjId, objType, objId);
            missingInfo = InfosUtil.CheckIntegrityAtCreation(pjId, ot, subType, infos, realId, name);
            if (ot.equals(ObjectType.equipment) || ot.equals(ObjectType.system) || ot.equals(ObjectType.component) || ot.equals(ObjectType.space)) {
                insertObj.put(ObjectTable.COL_SUBTYPE, subType);
            }
            if (missingInfo != null)
                throw new WrongInfosException("信息点名称错误: " + missingInfo);
            CommonUtil.verifyInfosObject(infos);

            // 检测完毕
            insertObj.put(ObjectTable.KEY_CREATE_TIME, name.getCreateTime());
            JSONObject re = ZillionAgentProvider.GetAgent().Query(json);
            if (!re.get("Result").toString().equalsIgnoreCase("success")) {
                if (re.getLong("Count") > 0L)
                    throw new Exception("已存在的对象!");
                throw new OperationFailedException();
            }

            //batchInsertInfos(pjId, objType, objId, infos);
            JSONArray arr = new JSONArray();
            JSONObject oneObject = new JSONObject();
            oneObject.put(ObjInfosTable.KEY_PJ_ID, pjId);
            oneObject.put(ObjInfosTable.KEY_OBJ_TYPE, objType);
            oneObject.put(ObjInfosTable.KEY_OBJ_ID, objId);
            oneObject.put(Const.JSON_FIELD_JSON_DATA_INFOS, infos);
            if (ot.equals(ObjectType.building) && !infos.containsKey("Holiday")) {
                JSONArray holiday = new JSONArray();
                JSONObject holidayValue = new JSONObject();
                holiday.add(holidayValue);
                StringBuilder sb = new StringBuilder();
                sb.append(pjId).append(objId).append("-1");
                holidayValue.put("value", sb.toString());
                holidayValue.put("time", CommonUtil.getTime());
                infos.put("Holiday", holiday);
            }
            arr.add(oneObject);
            ArrayList<String> errors = new ArrayList<>();
            try {
                errors = batchUpdate(pjId, arr, false, true, false, new CommonQueryCriteria());
            } catch (Exception ex) {
            }
            // 打印错误信息到日志
            if (errors.size() > 0) {
                StringBuilder sb = new StringBuilder();
                for (String error : errors)
                    sb.append(error).append('|');
                log.error(sb.toString());
            }
            if (isMonitor)
                ActivityLogUtil.objectLog(realId, name.getCreateTime(), ot, MQType.objectCreate);
            getObjectName(realId, name);
            return realId;
        } catch (IdGenException e) {
            log.error("Failed to generate id.");
            throw new OperationFailedException();
        } catch (WrongInfosException ex) {
            throw ex;
        } catch (Exception e) {
            throw e;
        }

    }

    private static void getObjectName(String realId, ObjectIdName name) {
        String value = null;
        try {
            value = (String) getSingleInfoValue(realId, name.getNameKey());
        } catch (Exception ignore) {
        }
        if (value != null)
            name.setNameValue(value);
        else
            name.setNameKey(null);
    }

    private static Object getSingleInfoValue(String realId, String infoName) throws Exception {
        JSONObject criteria = new JSONObject();
        criteria.put("id", realId);
        DpUtils.rewriteCriteria(criteria, "id", true);
        criteria.put(ObjInfosTable.KEY_INFO_ID, infoName);
        JSONObject result = CommonUtil.query(false, HBaseTable.obj_infos, criteria);

        JSONObject infoObj = CommonUtil.processInfoPointsToJSONDataWithId((JSONArray) result.get("Content"), true, false, false);
        return infoObj.get(infoName);
    }

    // 获取所有项目的id和密码.
    public static JSONArray getProjectPwd() {
        String jsonStr = "{\"QueryType\":\"select\",\"Datatable\":\"obj_infos\", \"Criteria\" : {}}";
        JSONObject json = JSONObject.parseObject(jsonStr);
        json.put("Database", OssUtils.getProperty("database.name"));
        json.put("Datatable", Const.TABLE_PROJECT_NAME);
        JSONObject re = null;
        try {
            re = ZillionAgentProvider.GetAgent().Query(json);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        JSONArray arr = (JSONArray) re.get("Content");
        for (int i = 0; i < arr.size(); ++i) {
            JSONObject single = (JSONObject) arr.get(i);
            if (single.containsKey(Const.TABLE_KEY_NAME_VALID) && single.get(Const.TABLE_KEY_NAME_VALID) != null) {
                if (single.get(Const.TABLE_KEY_NAME_VALID).equals(false)) {
                    arr.remove(i);
                    --i;
                }
            }
        }
        return arr;
    }
    
    /**
     * 根据项目id获取项目本地编码
     * @param projectIdNoPjStart 项目数据字典id，不包含前缀Pj
     * @return 项目本地编码或者null
     */
    public static String getProjLocalID(String projectIdNoPjStart) {
    	String jsonStr = "{\"QueryType\":\"select\",\"Datatable\":\"obj_infos\"}";
        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONObject criteria = new JSONObject();
        criteria.put("project_id", projectIdNoPjStart);
        criteria.put("obj_type", Const.OBJ_TYPE_PROJECT);
        json.put("Criteria", criteria);
        
        json.put("Database", OssUtils.getProperty("database.name"));
        try {
        	JSONObject re = ZillionAgentProvider.GetAgent().Query(json);
            JSONArray arr = (JSONArray) re.get("Content");
            TreeMap<String, String> timeValue = new TreeMap<>();
            String defaultValue = null;
        	for (int i = 0; i < arr.size(); ++i) {
        		JSONObject single = (JSONObject) arr.get(i);
        		String infoId = single.getString("info_id");
        		if(null != infoId && infoId.equals("ProjLocalID")) {
        			String value = single.getString("s_value");
        			String time = single.getString("time");
        			if(time != null) {
        				timeValue.put(time, value);
        			}
        			if(null == defaultValue) {
        				defaultValue = value;
        			}
        		}
        	}
        	
        	if(timeValue.isEmpty()) {
        		return defaultValue;
        	}else {
        		return timeValue.lastEntry().getValue();
        	}
        } catch (Exception e) {
        	e.printStackTrace();
            return null;
        }
    }

    public static JSONObject generateFloorCriteria(String id, String project_id, String type, Boolean valid, JSONObject createTime) throws Exception {
        JSONObject objCriteria = new JSONObject();
        JSONObject range_objId = new JSONObject();
        objCriteria.put(ObjectTable.KEY_PJ_ID, project_id);
        if (valid != null)
            objCriteria.put(Const.TABLE_KEY_NAME_VALID, valid);
        if (createTime != null)
            objCriteria.put(ObjectTable.KEY_CREATE_TIME, createTime);
        String obj_id_prefix = id.substring(12);
        if (type.equals(Const.OBJ_TYPE_SPACE) || type.equals(Const.OBJ_TYPE_ISPACE)) {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, type);
            range_objId.put("$gte", obj_id_prefix);
            range_objId.put("$lte", obj_id_prefix + "zzzzzz");
            objCriteria.put(ObjectTable.KEY_OBJ_ID, range_objId);
        } else if (type.equals(Const.OBJ_TYPE_FLOOR)) {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, type);
            objCriteria.put(ObjectTable.KEY_OBJ_ID, obj_id_prefix);
        } else
            throw new Exception(type + "类型不允许!");
        return objCriteria;
    }

    public static JSONObject generateBuildingCriteria(String id, String project_id, String type, Boolean valid, JSONObject createTime) throws Exception {
        JSONObject objCriteria = new JSONObject();
        JSONObject range_objType = new JSONObject();
        JSONObject range_objId = new JSONObject();
        objCriteria.put(ObjectTable.KEY_PJ_ID, project_id);
        if (valid != null)
            objCriteria.put(Const.TABLE_KEY_NAME_VALID, valid);
        if (createTime != null)
            objCriteria.put(ObjectTable.KEY_CREATE_TIME, createTime);
        String obj_id_prefix = id.substring(12);
        EqStaticInfo eqStaticInfo = new EqStaticInfo(project_id);
        if (eqStaticInfo.getEqSet().contains(type)) // 建筑下的设备
        {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_EQUIPMENT + eqStaticInfo.getCateToMajorMap().get(type) + type);
            range_objId.put("$gte", obj_id_prefix);
            range_objId.put("$lte", obj_id_prefix + "zzz");
            objCriteria.put(ObjectTable.KEY_OBJ_ID, range_objId);
        } else if (eqStaticInfo.getSysSet().contains(type)) // 建筑下的系统
        {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_SYSTEM + eqStaticInfo.getCateToMajorMap().get(type) + type);
            range_objId.put("$gte", obj_id_prefix);
            range_objId.put("$lte", obj_id_prefix + "zzz");
            objCriteria.put(ObjectTable.KEY_OBJ_ID, range_objId);
        } else if (eqStaticInfo.getEcSet().contains(type)) {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_EQUIPMENT_COMPONENT + eqStaticInfo.getCateToMajorMap().get(type) + type);
            range_objId.put("$gte", obj_id_prefix);
            range_objId.put("$lte", obj_id_prefix + "zzz");
            objCriteria.put(ObjectTable.KEY_OBJ_ID, range_objId);
        } else {
            switch (type) // 查询building下的Object
            {
                case Const.OBJ_TYPE_EQUIPMENT:
                case Const.OBJ_TYPE_SYSTEM:
                case Const.OBJ_TYPE_EQUIPMENT_COMPONENT:
                    range_objType.put("$gte", type);
                    range_objType.put("$lte", type + "zzzzzz");
                    range_objId.put("$gte", obj_id_prefix);
                    range_objId.put("$lte", obj_id_prefix + "zzz");
                    objCriteria.put(ObjectTable.KEY_OBJ_TYPE, range_objType);
                    objCriteria.put(ObjectTable.KEY_OBJ_ID, range_objId);
                    break;
                case Const.OBJ_TYPE_FLOOR:
                case Const.OBJ_TYPE_SPACE:
                case Const.OBJ_TYPE_ISPACE:
                    objCriteria.put(ObjectTable.KEY_OBJ_TYPE, type);
                    range_objId.put("$gte", obj_id_prefix);
                    range_objId.put("$lte", obj_id_prefix + "zzzzzz");
                    objCriteria.put(ObjectTable.KEY_OBJ_ID, range_objId);
                    break;
                case Const.OBJ_TYPE_BUILDING:
                    objCriteria.put(ObjectTable.KEY_OBJ_TYPE, type);
                    objCriteria.put(ObjectTable.KEY_OBJ_ID, obj_id_prefix);
                    break;
                default:
                    throw new Exception(type + "类型不允许!");
            }
        }
        return objCriteria;
    }

    public static JSONObject generateProjectTypeCriteria(String project_id, String type, Boolean valid, JSONObject createTime, EqStaticInfo eqStaticInfo) throws Exception {
        JSONObject objCriteria = new JSONObject();
        objCriteria.put(ObjectTable.KEY_PJ_ID, project_id);
        if (valid != null)
            objCriteria.put(Const.TABLE_KEY_NAME_VALID, valid);
        if (createTime != null)
            objCriteria.put(ObjectTable.KEY_CREATE_TIME, createTime);
        if (eqStaticInfo.getEqSet().contains(type)) // 项目下的设备
        {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_EQUIPMENT);
            objCriteria.put(ObjectTable.COL_SUBTYPE, type);
        } else if (eqStaticInfo.getSysSet().contains(type)) // 项目下的系统
        {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_SYSTEM);
            objCriteria.put(ObjectTable.COL_SUBTYPE, type);
        } else if (eqStaticInfo.getEcSet().contains(type)) // 项目下的部件
        {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_EQUIPMENT_COMPONENT);
            objCriteria.put(ObjectTable.COL_SUBTYPE, type);
        } else if (PhysicalObject.bussinessSpaceTypeMap.containsKey(type)) {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_SPACE);
            objCriteria.put(ObjectTable.COL_SUBTYPE, type);
        }else if (CsStaticInfo.getCode2name().containsKey(type)) {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_CONSUMABLE);
            objCriteria.put(ObjectTable.COL_SUBTYPE, type);
        }else if (TlStaticInfo.getCode2name().containsKey(type)) {
            objCriteria.put(ObjectTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_TOOL);
            objCriteria.put(ObjectTable.COL_SUBTYPE, type);
        } else {
            if (PhysicalObject.allTypes.contains(type)) {
                objCriteria.put(ObjectTable.KEY_OBJ_TYPE, type);
            } else {
                throw new Exception(type + "类型不允许!");
            }
//            switch (type) // 查询项目下的Object
//            {
//                case Const.OBJ_TYPE_EQUIPMENT:
//                case Const.OBJ_TYPE_SYSTEM:
//                case Const.OBJ_TYPE_EQUIPMENT_COMPONENT:
//                case Const.OBJ_TYPE_FLOOR:
//                case Const.OBJ_TYPE_SPACE:
//                case Const.OBJ_TYPE_ISPACE:
//                case Const.OBJ_TYPE_BUILDING:
//                case Const.OBJ_TYPE_VOBD:
//                case Const.OBJ_TYPE_VOCU:
//                case Const.OBJ_TYPE_VOEI:
//                case Const.OBJ_TYPE_VOTn:
//                case Const.OBJ_TYPE_VOBc:
//                case Const.OBJ_TYPE_VOCt:
//                case Const.OBJ_TYPE_VOGp:
//                case Const.OBJ_TYPE_VOSe:
//                case Const.OBJ_TYPE_VOZn:
//                    objCriteria.put(ObjectTable.KEY_OBJ_TYPE, type);
//                    break;
//                default:
//                    throw new Exception(type + "类型不允许!");
//            }
        }
        return objCriteria;
    }

    private static void filterMajor(String pjId, JSONArray criteriasNode, ArrayList<String> ids, String system_id) throws Exception {
        JSONArray arr = new JSONArray();
        JSONObject obj = new JSONObject();
        obj.put("id", system_id);
        CommonUtil.rewriteObjectTableCriteria(pjId, obj, "id", true);
        arr.add(obj);
        for (String id : ids) {
            obj = new JSONObject();
            obj.put("id", id);
            CommonUtil.rewriteObjectTableCriteria(pjId, obj, "id", true);
            arr.add(obj);
        }
        JSONObject result = CommonUtil.combine_query(HBaseTable.objects, arr);
        JSONArray content = (JSONArray) result.get("Content");
        HashMap<String, String> idType = new HashMap<>();
        for (int i = 0; i < content.size(); ++i) {
            JSONObject single = (JSONObject) content.get(i);
            String id = CommonUtil.combineId(Strings.nullToEmpty((String) single.get(ObjectTable.KEY_PJ_ID)),
                    Strings.nullToEmpty((String) single.get(ObjectTable.KEY_OBJ_TYPE)), Strings.nullToEmpty((String) single.get(ObjectTable.KEY_OBJ_ID)));
            String detailType = (String) single.get(ObjectTable.COL_SUBTYPE);
            if (!idType.containsKey(id))
                idType.put(id, detailType);
        }
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        String systemMajor = eqStaticInfo.getCateToMajorMap().get(idType.get(system_id));
        Set<String> detailTypeSet = eqStaticInfo.getMajorToEqMap().get(systemMajor);

        for (int i = 0; i < ids.size(); ++i) {
            String id = ids.get(i);
            String detaiType = idType.get(id);
            if (!detailTypeSet.contains(detaiType))
                continue;
            JSONObject objId = new JSONObject();
            objId.put("id", id);
            criteriasNode.add(objId);
        }
    }


    public static void filterMatch(JSONArray result, String match, ArrayList<String> matchKey) {
        for (int i = result.size() - 1; i > -1; --i) {
            JSONObject obj = (JSONObject) result.get(i);
            JSONObject infos = (JSONObject) obj.get(Const.JSON_FIELD_JSON_DATA_INFOS);
            boolean retain = false;
            for (int j = 0; j < matchKey.size(); ++j) {
                if (infos.containsKey(matchKey.get(j)) && infos.get(matchKey.get(j)).toString().contains(match)) {
                    retain = true;
                    break;
                }
            }
            if (!retain)
                result.remove(i);
        }
    }

    static ArrayList<String> keys = CommonUtil.createArrayList("EquipLocalID", "EquipLocalName");

    public static void pagingMatchContent(JSONArray result, CommonQueryCriteria cqc) throws Exception {
        if (cqc.isFilter()) {
//            filterMatch(result, null, keys);
            filterMatch(result, cqc);
        }
        JSONObject[] arr = new JSONObject[result.size()];
        for (int i = 0; i < result.size(); ++i)
            arr[i] = (JSONObject) result.get(i);
        ObjectComparator cmp = new ObjectComparator("create_time");
        Arrays.sort(arr, cmp);
        result.clear();
        Long from = 0L;
        int count = arr.length;
        if (cqc.getSkip() != null) {
            from = cqc.getSkip();
            count = cqc.getSkip_count();
        }
        cqc.setSkip_totalCount((long) arr.length);
        long cnt = 0L;
        for (long i = from; i < arr.length && (i - from) < count; ++i) {
            if (cqc.getNodata())
                ++cnt;
            else
                result.add(arr[(int) i]);
        }
        cqc.setCount(cnt);
    }

    private static void filterMatch(JSONArray result, CommonQueryCriteria cqc) {
        String infoCode = cqc.getFilterInfoCode();
        Object value = cqc.getFilterValue();
        for (int i = result.size() - 1; i > -1; --i) {
            JSONObject obj = (JSONObject) result.get(i);
            JSONObject infos = (JSONObject) obj.get(Const.JSON_FIELD_JSON_DATA_INFOS);
            boolean retain = false;
            if (value == null) {
                if (infos.get(infoCode) == null)
                    retain = true;
            } else if (value instanceof String) {
                if (infos.getString(infoCode) != null && infos.getString(infoCode).contains((String) value)) {
                    retain = true;
                }
            } else if (value.equals(infos.get(infoCode))) {
                retain = true;
            }
            if (!retain)
                result.remove(i);
        }
    }

//    public static JSONArray complexQueryBySystemId(String pjId, String system_id, String graph_id, String rel_type, String match, CommonQueryCriteria cqc) throws Exception {
//        ArrayList<String> ids = RelationUtil.getEqUnderSys(pjId, system_id, graph_id, rel_type);
//        JSONArray criteriasNode = new JSONArray();
//        filterMajor(pjId, criteriasNode, ids, system_id);
//        Boolean noData = cqc.getNodata();
//        cqc.setNodata(false);
//        JSONArray result = CommonUtil.batchQuerySelfInfo(pjId, criteriasNode, cqc);
//        cqc.setNodata(noData);
//        pagingMatchContent(result, match, cqc);
//        return result;
//    }
//
//    public static JSONArray complexQueryByCategory(String pjId, String category, String buildingId, String match, CommonQueryCriteria cqc) throws Exception {
//        ArrayList<String> types = new ArrayList<>();
//        types.add(category);
//        Boolean noData = cqc.getNodata();
//        cqc.setNodata(false);
//        JSONArray result = queryEquipmentByCategory(pjId, types, cqc, buildingId);
//        cqc.setNodata(noData);
//        pagingMatchContent(result, match, cqc);
//        return result;
//    }

    public static ObjectType getObjectTypeById(String id) {
        if (id.startsWith("Pj"))
            return ObjectType.project;
        if (id.startsWith("Eq"))
            return ObjectType.equipment;
        if (id.startsWith("Sy"))
            return ObjectType.system;
        if (id.startsWith("Sp"))
            return ObjectType.space;
        if (id.startsWith("Si"))
            return ObjectType.ispace;
        if (id.startsWith("Fl"))
            return ObjectType.floor;
        if (id.startsWith("Sh"))
            return ObjectType.shaft;
        if (id.startsWith("Bd"))
            return ObjectType.building;
        if (id.startsWith("VOBd"))
            return ObjectType.VOBd;
        if (id.startsWith("VO"))
            return ObjectType.VO;
        if (id.startsWith("Ec"))
            return ObjectType.component;
        if (id.startsWith("Cs"))
            return ObjectType.consumable;
        if (id.startsWith("Tl"))
            return ObjectType.tool;
        if (id.startsWith(Const.OBJ_TYPE_PROPERTY))
            return ObjectType.property;
        return null;
    }

    public static ArrayList<String> getSubIds(ArrayList<String> types, String id, String pjId, CommonQueryCriteria cqc, EqStaticInfo eqStaticInfo) throws Exception {
        JSONArray criteriasObj = new JSONArray();
        JSONArray criteriasProj = new JSONArray();
        ArrayList<String> subIds = new ArrayList<>();
        if (id.startsWith(Const.OBJ_TYPE_PROJECT)) {
            if (types.size() == 0) {
                JSONObject objCriteria = new JSONObject();
                objCriteria.put(ObjectTable.KEY_PJ_ID, pjId);
                if (cqc.getCtime() != null)
                    objCriteria.put(ObjectTable.KEY_CREATE_TIME, cqc.getCount());
                if (cqc.getValid() != null)
                    objCriteria.put(Const.TABLE_KEY_NAME_VALID, cqc.getValid());
                criteriasObj.add(objCriteria);
            } else {
                for (int i = 0; i < types.size(); ++i) {
                    if (types.get(i).equals(Const.OBJ_TYPE_PROJECT)) {
                        JSONObject proj = new JSONObject();
                        proj.put(ProjectTable.KEY_PJ_ID, pjId);
                        if (cqc.getValid() != null)
                            proj.put(Const.TABLE_KEY_NAME_VALID, cqc.getValid());
                        if (cqc.getCtime() != null)
                            proj.put(ProjectTable.KEY_CREATE_TIME, cqc.getCtime());
                        criteriasProj.add(proj);
                    } else {
                        criteriasObj.add(generateProjectTypeCriteria(pjId, types.get(i), cqc.getValid(), cqc.getCtime(), eqStaticInfo));
                    }
                }
            }
        } else if (id.startsWith(Const.OBJ_TYPE_BUILDING) || id.startsWith(Const.OBJ_TYPE_FLOOR) || id.startsWith(Const.OBJ_TYPE_EQUIPMENT)) {
            Set<String> typeSet = new HashSet<>(types);
            subIds = SubsetUtil.getSubset(pjId, id, typeSet, cqc, eqStaticInfo);
            return subIds;
        } else
            throw new Exception("id: " + id + " 错误");
        JSONArray criteriasInfo = new JSONArray();
        if (id.startsWith(Const.OBJ_TYPE_PROJECT)) { // 查询项目下的对象
            JSONObject objResult = null;
            JSONObject projResult = null;
            JSONArray objArray = new JSONArray();
            JSONArray projArray = new JSONArray();
            if (criteriasObj.size() > 0) {
                objResult = CommonUtil.query(true, HBaseTable.objects, criteriasObj);
                objArray = (JSONArray) objResult.get("Content");
            }
            if (criteriasProj.size() > 0) {
                projResult = CommonUtil.query(true, HBaseTable.projects, criteriasProj);
                projArray = (JSONArray) projResult.get("Content");
            }
            for (int i = 0; i < objArray.size(); ++i) {
                JSONArray perResult = (JSONArray) ((JSONObject) objArray.get(i)).get("Content");
                for (int j = 0; j < perResult.size(); ++j) {
                    criteriasInfo.add(perResult.get(j));
                }
            }
            for (int i = 0; i < projArray.size(); ++i) {
                JSONArray perResult = (JSONArray) ((JSONObject) projArray.get(i)).get("Content");
                for (int j = 0; j < perResult.size(); ++j) {
                    criteriasInfo.add(perResult.get(j));
                    ((JSONObject) perResult.get(j)).put(ObjInfosTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_PROJECT);
                    ((JSONObject) perResult.get(j)).put(ObjInfosTable.KEY_OBJ_ID, null);
                }
            }
            if (criteriasInfo.size() > 0) {
                return fromObjectToIdList(criteriasInfo);
            }
        }
        return new ArrayList<>();
    }

    // 查询id(Object表主键)下面的所有类型为type的对象, project_id为不带Pj的项目id
    public static JSONArray subsetQuery(String pjId, ArrayList<String> types, String id, String project_id, CommonQueryCriteria cqc, EqStaticInfo eqStaticInfo) throws Exception {
        JSONArray criteriasObj = new JSONArray();
        JSONArray criteriasProj = new JSONArray();
        ArrayList<String> subIds = new ArrayList<>();
        if (id.startsWith(Const.OBJ_TYPE_PROJECT)) {
            for (int i = 0; i < types.size(); ++i) {
                if (types.get(i).equals(Const.OBJ_TYPE_PROJECT)) {
                    JSONObject proj = new JSONObject();
                    proj.put(ProjectTable.KEY_PJ_ID, project_id);
                    if (cqc.getValid() != null)
                        proj.put(Const.TABLE_KEY_NAME_VALID, cqc.getValid());
                    if (cqc.getCtime() != null)
                        proj.put(ProjectTable.KEY_CREATE_TIME, cqc.getCtime());
                    criteriasProj.add(proj);
                } else {
                    criteriasObj.add(generateProjectTypeCriteria(project_id, types.get(i), cqc.getValid(), cqc.getCtime(), eqStaticInfo));
                }
            }
        } else if (id.startsWith(Const.OBJ_TYPE_BUILDING) || id.startsWith(Const.OBJ_TYPE_FLOOR) || id.startsWith(Const.OBJ_TYPE_EQUIPMENT)) {
            Set<String> typeSet = new HashSet<>(types);
            subIds = SubsetUtil.getSubset(pjId, id, typeSet, cqc, eqStaticInfo);
        } else
            throw new Exception("id: " + id + " 错误");
        if (cqc.getNodata()) {
            if (id.startsWith(Const.OBJ_TYPE_PROJECT)) {
                JSONObject objCount = null, projCount = null;
                Long total = 0L;
                if (criteriasObj.size() > 0) {
                    objCount = CommonUtil.getCount(true, HBaseTable.objects, criteriasObj);
                    JSONArray content = (JSONArray) objCount.get("Content");
                    for (int i = 0; i < content.size(); ++i)
                        total += (((JSONObject) content.get(i)).getLongValue("Count"));
                }
                if (criteriasProj.size() > 0) {
                    projCount = CommonUtil.getCount(true, HBaseTable.projects, criteriasProj);
                    JSONArray content = (JSONArray) projCount.get("Content");
                    for (int i = 0; i < content.size(); ++i)
                        total += (((JSONObject) content.get(i)).getLongValue("Count"));
                }
                cqc.setCount(total);
            } else {
                cqc.setCount((long) subIds.size());
            }
            return new JSONArray();
        }
        ArrayList<String> ctime = new ArrayList<>();
        JSONArray criteriasInfo = new JSONArray();
        if (id.startsWith(Const.OBJ_TYPE_PROJECT)) { // 查询项目下的对象
            JSONObject objResult = null;
            JSONObject projResult = null;
            JSONArray objArray = new JSONArray();
            JSONArray projArray = new JSONArray();
            if (criteriasObj.size() > 0) {
                objResult = CommonUtil.query(true, HBaseTable.objects, criteriasObj);
                objArray = (JSONArray) objResult.get("Content");
            }
            if (criteriasProj.size() > 0) {
                projResult = CommonUtil.query(true, HBaseTable.projects, criteriasProj);
                projArray = (JSONArray) projResult.get("Content");
            }
            for (int i = 0; i < objArray.size(); ++i) {
                JSONArray perResult = (JSONArray) ((JSONObject) objArray.get(i)).get("Content");
                for (int j = 0; j < perResult.size(); ++j) {
                    ctime.add(((JSONObject) perResult.get(j)).get(ObjectTable.KEY_CREATE_TIME).toString());
                    criteriasInfo.add(perResult.get(j));
                    ((JSONObject) perResult.get(j)).remove(ObjectTable.KEY_CREATE_TIME);
                    ((JSONObject) perResult.get(j)).remove(ObjectTable.KEY_DEL_TIME);
                    ((JSONObject) perResult.get(j)).remove(Const.TABLE_KEY_NAME_VALID);
                }
            }
            for (int i = 0; i < projArray.size(); ++i) {
                JSONArray perResult = (JSONArray) ((JSONObject) projArray.get(i)).get("Content");
                for (int j = 0; j < perResult.size(); ++j) {
                    ctime.add(((JSONObject) perResult.get(j)).get(ProjectTable.KEY_CREATE_TIME).toString());
                    criteriasInfo.add(perResult.get(j));
                    ((JSONObject) perResult.get(j)).remove(ProjectTable.KEY_CREATE_TIME);
                    ((JSONObject) perResult.get(j)).remove(ProjectTable.KEY_DEL_TIME);
                    ((JSONObject) perResult.get(j)).remove(Const.TABLE_KEY_NAME_VALID);
                    ((JSONObject) perResult.get(j)).remove(ProjectTable.KEY_PWD);
                    ((JSONObject) perResult.get(j)).put(ObjInfosTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_PROJECT);
                    ((JSONObject) perResult.get(j)).put(ObjInfosTable.KEY_OBJ_ID, null);
                }
            }
            if (criteriasInfo.size() > 0) {
                return CommonUtil.batchQuerySelfInfoQueryGetData(pjId, fromObjectToIdList(criteriasInfo), criteriasInfo, ctime, cqc, eqStaticInfo);
            }
        } else { // 查询关系
            if (subIds.size() > 0) {
                for (String objId : subIds) {
                    JSONObject single = new JSONObject();
                    single.put("id", objId);
                    criteriasInfo.add(single);
                }
                return CommonUtil.batchQuerySelfInfo(pjId, criteriasInfo, cqc, eqStaticInfo);
            }
        }
        return new JSONArray();
    }

    public static JSONArray queryEquipmentByCategory(String projectId, ArrayList<String> types, CommonQueryCriteria cqc, String buildingOrPjId) throws Exception {
        // 查询项目内系统
        if (buildingOrPjId == null || buildingOrPjId.startsWith(Const.OBJ_TYPE_PROJECT))
            return querySystemByCategory(projectId, types, cqc, Const.OBJ_TYPE_EQUIPMENT);
        JSONArray criterias = new JSONArray();
        Set<String> typeSet = new HashSet<>();
        EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
        for (int i = 0; i < types.size(); ++i) {
            Set<String> systemTypeSet = eqStaticInfo.getMajorToEqMap().get(types.get(i));
            if (systemTypeSet == null || systemTypeSet.size() == 0)
                continue;
            typeSet.addAll(systemTypeSet);
        }
        ArrayList<String> idList = SubsetUtil.getSubset(projectId, buildingOrPjId, typeSet, cqc, eqStaticInfo);
        if (idList.size() == 0)
            return new JSONArray();
        if (cqc.getNodata()) {
            cqc.setCount((long) idList.size());
            return new JSONArray();
        }
        ArrayList<String> ctime = SubsetUtil.getCtime(projectId, idList);
        JSONArray content = new JSONArray();
        for (String id : idList) {
            JSONObject obj = new JSONObject();
            obj.put("id", id);
            DpUtils.rewriteCriteria(obj, "id", true);
            content.add(obj);
        }
        return CommonUtil.batchQuerySelfInfoQueryGetData(projectId, idList, content, ctime, cqc, eqStaticInfo);
    }

    public static JSONArray querySystemByCategory(String projectId, ArrayList<String> types, CommonQueryCriteria cqc, String obj_type) throws Exception {
        JSONArray criterias = new JSONArray();
        EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
        for (int i = 0; i < types.size(); ++i) {
            Set<String> systemTypeSet = obj_type.equals(Const.OBJ_TYPE_SYSTEM) ? eqStaticInfo.getMajorToSysMap().get(types.get(i)) : eqStaticInfo.getMajorToEqMap().get(types.get(i));
            if (systemTypeSet == null || systemTypeSet.size() == 0)
                continue;
            for (String systemType : systemTypeSet) {
                JSONObject criteria = new JSONObject();
                criteria.put(ObjectTable.KEY_PJ_ID, projectId);
                criteria.put(ObjectTable.KEY_OBJ_TYPE, obj_type);
                criteria.put(ObjectTable.COL_SUBTYPE, systemType);
                criterias.add(criteria);
            }
        }
        if (criterias.size() == 0)
            return new JSONArray();
        JSONObject objResult = CommonUtil.combine_query(HBaseTable.objects, criterias);
        JSONArray objContent = (JSONArray) objResult.get("Content");
        if (cqc.getNodata()) {
            Long cnt = 0L;
            for (int i = 0; i < objContent.size(); ++i) {
                JSONObject single = (JSONObject) objContent.get(i);
                if (single.get(Const.TABLE_KEY_NAME_VALID) != null && single.get(Const.TABLE_KEY_NAME_VALID).equals(true))
                    ++cnt;
            }
            cqc.setCount(cnt);
            return new JSONArray();
        }
        ArrayList<String> ctime = new ArrayList<>();
        JSONArray content = new JSONArray();
        for (int i = 0; i < objContent.size(); ++i) {
            JSONObject single = (JSONObject) objContent.get(i);
            if (single.get(Const.TABLE_KEY_NAME_VALID) == null || single.get(Const.TABLE_KEY_NAME_VALID).equals(false))
                continue;
            content.add(single);
            ctime.add(single.get(ObjectTable.KEY_CREATE_TIME).toString());
            single.remove(ObjectTable.KEY_CREATE_TIME);
            single.remove(ObjectTable.KEY_DEL_TIME);
            single.remove(ObjectTable.COL_SUBTYPE);
            single.remove(ObjectTable.COL_VALID);
        }
        ArrayList<String> ids = fromObjectToIdList(content);
        return CommonUtil.batchQuerySelfInfoQueryGetData(projectId, ids, content, ctime, cqc, eqStaticInfo);
    }

    // 输入参数是object表的实例
    private static ArrayList<String> fromObjectToIdList(JSONArray objArray) {
        ArrayList<String> arr = new ArrayList<>();
        for (int i = 0; i < objArray.size(); ++i) {
            JSONObject obj = (JSONObject) objArray.get(i);
            arr.add(CommonUtil.combineId(obj.get(ObjectTable.KEY_PJ_ID).toString(), obj.get(ObjectTable.KEY_OBJ_TYPE).toString(),
                    obj.get(ObjectTable.KEY_OBJ_ID) == null ? "" : obj.get(ObjectTable.KEY_OBJ_ID).toString()));
        }
        return arr;
    }

    // obj 是完整的infos表中的一行数据, 返回update中的set数据
    private static JSONObject splitInsertToUpdate(JSONObject obj) {
        JSONObject set = new JSONObject();
        set.put(ObjInfosTable.COL_D_VALUE, obj.get(ObjInfosTable.COL_D_VALUE));
        obj.remove(ObjInfosTable.COL_D_VALUE);
        set.put(ObjInfosTable.COL_L_VALUE, obj.get(ObjInfosTable.COL_L_VALUE));
        obj.remove(ObjInfosTable.COL_L_VALUE);
        set.put(ObjInfosTable.COL_S_VALUE, obj.get(ObjInfosTable.COL_S_VALUE));
        obj.remove(ObjInfosTable.COL_S_VALUE);
        set.put(ObjInfosTable.COL_B_VALUE, obj.get(ObjInfosTable.COL_B_VALUE));
        obj.remove(ObjInfosTable.COL_B_VALUE);
        set.put(ObjInfosTable.COL_JSON_VALUE, obj.get(ObjInfosTable.COL_JSON_VALUE));
        obj.remove(ObjInfosTable.COL_JSON_VALUE);
        return set;
    }

    private static JSONObject generateInfoSet(Object value) throws Exception {
        JSONObject set = new JSONObject();
        set.put(ObjInfosTable.COL_L_VALUE, null);
        set.put(ObjInfosTable.COL_D_VALUE, null);
        set.put(ObjInfosTable.COL_S_VALUE, null);
        set.put(ObjInfosTable.COL_B_VALUE, null);
        set.put(ObjInfosTable.COL_JSON_VALUE, null);
        if (value instanceof String) {
            set.put(ObjInfosTable.COL_S_VALUE, value);
        } else if (value instanceof Long || value instanceof Integer) {
            set.put(ObjInfosTable.COL_L_VALUE, value);
        } else if (value instanceof Boolean) {
            set.put(ObjInfosTable.COL_B_VALUE, value);
        } else if (value instanceof BigDecimal) {
            set.put(ObjInfosTable.COL_D_VALUE, value);
        } else if (value instanceof JSONArray || value instanceof JSONObject) {
            set.put(ObjInfosTable.COL_JSON_VALUE, value.toString());
        } else
            throw new Exception("不支持的类型!");
        return set;
    }

    private static JSONObject generateInfoRow(JSONObject idJSON, String infoId, Object value, String time) throws Exception {
        JSONObject obj = new JSONObject();
        obj.put(ObjInfosTable.KEY_PJ_ID, idJSON.get(ObjInfosTable.KEY_PJ_ID));
        obj.put(ObjInfosTable.KEY_OBJ_TYPE, idJSON.get(ObjInfosTable.KEY_OBJ_TYPE));
        if (idJSON.get(ObjInfosTable.KEY_OBJ_ID) != null && idJSON.get(ObjInfosTable.KEY_OBJ_ID).toString().trim().equals("")) {
            obj.put(ObjInfosTable.KEY_OBJ_ID, null);
            //obj.put(Const.TABLE_KEY_NAME_VALID, true);
        } else
            obj.put(ObjInfosTable.KEY_OBJ_ID, idJSON.get(ObjInfosTable.KEY_OBJ_ID));
        obj.put(ObjInfosTable.KEY_INFO_ID, infoId);
        obj.put(ObjInfosTable.KEY_TIME, time);
        obj.put(ObjInfosTable.COL_L_VALUE, null);
        obj.put(ObjInfosTable.COL_D_VALUE, null);
        obj.put(ObjInfosTable.COL_S_VALUE, null);
        obj.put(ObjInfosTable.COL_B_VALUE, null);
        obj.put(ObjInfosTable.COL_JSON_VALUE, null);
//        if (value instanceof Long) {
//            obj.put(ObjInfosTable.COL_L_VALUE, value);
//        } else if (value instanceof Boolean) {
//            obj.put(ObjInfosTable.COL_B_VALUE, value);
//        } else if (value instanceof Double) {
//            obj.put(ObjInfosTable.COL_D_VALUE, value);
//        } else if (value instanceof String) {
//            obj.put(ObjInfosTable.COL_S_VALUE, value.toString());
//        } else if (value instanceof JSONObject || value instanceof JSONArray) {
//            obj.put(ObjInfosTable.COL_JSON_VALUE, value.toString());
//        } else
//            throw new Exception(infoId + "的值类型未知!");
        if (value instanceof Integer || value instanceof Long) {
            obj.put(ObjInfosTable.COL_L_VALUE, value);
        } else if (value instanceof BigDecimal) {
            obj.put(ObjInfosTable.COL_D_VALUE, value);
        } else if (value instanceof Boolean) {
            obj.put(ObjInfosTable.COL_B_VALUE, value);
        } else if (value instanceof String) {
            obj.put(ObjInfosTable.COL_S_VALUE, value.toString());
        } else if (value instanceof JSONObject || value instanceof JSONArray) {
            obj.put(ObjInfosTable.COL_JSON_VALUE, value.toString());
        } else
            throw new Exception(infoId + "的值类型未知!");

        return obj;
    }

    // 返回错误信息数组  当作为添加信息点时候, isCheckValid 为false, insert表示是否是插入( 资产应使用isCheckValid = false, 添加的时候insert为true, 修改时候 insert为false)
    public static ArrayList<String> batchUpdate(String projectId, JSONArray criterias, boolean isCheckValid, boolean insert, boolean MQLog, CommonQueryCriteria cqc) throws Exception {
        ArrayList<String> error = new ArrayList<>();
        JSONArray selectObjectsCriterias = new JSONArray(); // 用来查询Object表的valid
        JSONObject selectProjectCriteria = null; // 用来查询Projects表的valid
        JSONObject selectObjectsResult = new JSONObject();
        JSONObject selectProjectResult = new JSONObject();
        HashSet<String> validId = new HashSet<>(); // 存所有valid = true的id
        HashMap<String, String> idToTypeMap = new HashMap<>();//如果存在sub_type,存储id->sub_type;否则存储id->type
        JSONArray deleteCriterias = new JSONArray();
        JSONArray insertObjects = new JSONArray();
        JSONArray selectCriterias = new JSONArray(); // 查询将要被操作的信息点的时间
        JSONArray correspondingOp = new JSONArray(); // 将查询到的主键所要做的操作, 如果第i个JSONObject 的value = null, 则删除查询出来的历史, 否则更新
        JSONArray updateCriterias = new JSONArray();
        JSONArray updateSets = new JSONArray();
        String time = CommonUtil.getTime();
        // 首先筛选Object的valid
        if (isCheckValid) {
            for (int i = 0; i < criterias.size(); ++i) {
                JSONObject object = (JSONObject) criterias.get(i);
                DpUtils.rewriteCriteria(object, "id", false);
                JSONObject singleObject = new JSONObject();
                if (object.get(ObjectTable.KEY_OBJ_TYPE).equals(Const.OBJ_TYPE_PROJECT)) {
                    singleObject.put(ObjectTable.KEY_PJ_ID, object.get(ObjectTable.KEY_PJ_ID));
                    singleObject.put(Const.TABLE_KEY_NAME_VALID, true);
                    selectProjectCriteria = singleObject;
                } else {
                    singleObject.put(ObjectTable.KEY_OBJ_TYPE, object.get(ObjectTable.KEY_OBJ_TYPE));
                    singleObject.put(ObjectTable.KEY_PJ_ID, object.get(ObjectTable.KEY_PJ_ID));
                    singleObject.put(ObjectTable.KEY_OBJ_ID, object.get(ObjectTable.KEY_OBJ_ID));
                    singleObject.put(Const.TABLE_KEY_NAME_VALID, true);
                    selectObjectsCriterias.add(singleObject);
                }
            }
            if (selectObjectsCriterias.size() > 0)
                selectObjectsResult = CommonUtil.batch_select_merge(HBaseTable.objects, selectObjectsCriterias);
            if (selectProjectCriteria != null)
                selectProjectResult = CommonUtil.query(false, HBaseTable.projects, selectProjectCriteria);


            if (selectObjectsResult.containsKey("Content")) {
                CommonUtil.addIdToHashSet((JSONArray) selectObjectsResult.get("Content"), validId);
                CommonUtil.buildIdToTypeMap((JSONArray) selectObjectsResult.get("Content"), idToTypeMap);
            }
            if (selectProjectResult.containsKey("Content")) {
                CommonUtil.addIdToHashSet((JSONArray) selectProjectResult.get("Content"), validId);
                CommonUtil.buildIdToTypeMap((JSONArray) selectProjectResult.get("Content"), idToTypeMap);
            }
        }
        // 将valid 不为true的Object在执行下面的操作的时候跳过.
        for (int i = 0; i < criterias.size(); ++i) {
            JSONObject object = (JSONObject) criterias.get(i);
            if (isCheckValid && !validId.contains(object.get("id").toString()))
                continue;
            if (object.get("id") != null && object.get(ObjectTable.KEY_OBJ_TYPE) == null)
                DpUtils.rewriteCriteria(object, "id", false);
            JSONObject infos = (JSONObject) object.get(Const.JSON_FIELD_JSON_DATA_INFOS);
            // 检测信息点
            if (isCheckValid) {
                String type = object.get(ObjectTable.KEY_OBJ_TYPE).toString(), VO = null;
                if (type.startsWith("Sp")) {
                    type = idToTypeMap.get(object.get("id").toString());
                }
                if (type.startsWith("Sy") || type.startsWith("Eq") || type.startsWith("Ec") || type.startsWith("Cs") || type.startsWith("Tl"))
                    type = idToTypeMap.get(object.get("id").toString());
                if (type.startsWith("VO"))
                    VO = type;
                if (type.startsWith(Const.OBJ_TYPE_PROPERTY))
                    type = object.get("family").toString();
                String missingInfo = InfosUtil.checkIntegrity(object.get(ObjectTable.KEY_PJ_ID).toString(), getObjectTypeById(object.get("id").toString()), VO == null ? type : VO, infos, cqc);
                if (missingInfo != null)
                    throw new WrongInfosException("信息点名称错误!" + missingInfo);
            }

            // 检测完毕

            for (String info : infos.keySet()) // info 是单个信息点的名称, infos 是 infos节点
            {
                JSONArray singleInfo = (JSONArray) infos.get(info);
                for (int j = 0; j < singleInfo.size(); ++j) {
                    JSONObject pair = (JSONObject) singleInfo.get(j);
                    if (pair.containsKey("value")) {
                        if (pair.get("time") == null) // 如果节点中没有time, 或者time = null, 则需要查询当前信息点time最大的一条数据, 并且记录下当前的value
                        {
                            if (insert && pair.get("value") != null) {  // 如果是插入时没有指定时间, 则添加一个默认时间.
                                insertObjects.add(generateInfoRow(object, info, pair.get("value"), time));
                            } else {
                                JSONObject selectOne = new JSONObject();
                                selectOne.put(ObjInfosTable.KEY_PJ_ID, object.get(ObjInfosTable.KEY_PJ_ID));
                                selectOne.put(ObjInfosTable.KEY_OBJ_TYPE, object.get(ObjInfosTable.KEY_OBJ_TYPE));
                                selectOne.put(ObjInfosTable.KEY_OBJ_ID, object.get(ObjInfosTable.KEY_OBJ_ID));
                                selectOne.put(ObjInfosTable.KEY_INFO_ID, info);
                                selectCriterias.add(selectOne);
                                correspondingOp.add(pair);
                            }
                        } else if (pair.get("value") == null) // 当time指定时, value == null, 删除时间是time的一行数据.
                        {
                            JSONObject deleteOne = new JSONObject();
                            deleteOne.put(ObjInfosTable.KEY_PJ_ID, object.get(ObjInfosTable.KEY_PJ_ID));
                            deleteOne.put(ObjInfosTable.KEY_OBJ_TYPE, object.get(ObjInfosTable.KEY_OBJ_TYPE));
                            deleteOne.put(ObjInfosTable.KEY_OBJ_ID, object.get(ObjInfosTable.KEY_OBJ_ID));
                            deleteOne.put(ObjInfosTable.KEY_INFO_ID, info);
                            deleteOne.put(ObjInfosTable.KEY_TIME, pair.get("time"));
                            deleteCriterias.add(deleteOne);
                        } else // 当time 指定时候, 并且value != null, 插入此条数据, 失败则更新.
                        {
                            insertObjects.add(generateInfoRow(object, info, pair.get("value"), pair.get("time").toString()));
                        }
                    }
                } // end for
            } // end for
        } // end for

        if (selectCriterias.size() > 0) // 先执行查询操作.
        {
            JSONObject selectResult = CommonUtil.query(true, HBaseTable.obj_infos, selectCriterias);
            JSONArray content = (JSONArray) selectResult.get("Content");
            for (int i = 0; i < content.size(); ++i) {
                JSONObject infoAllTime = (JSONObject) content.get(i);
                JSONArray arr = (JSONArray) infoAllTime.get("Content");
                if (arr.size() > 0) // 查到有值, 添加到更新集合里
                {
                    JSONObject latest = (JSONObject) arr.get(arr.size() - 1);
                    JSONObject value = (JSONObject) correspondingOp.get(i);
                    JSONObject op = new JSONObject();
                    op.put(ObjInfosTable.KEY_PJ_ID, latest.get(ObjInfosTable.KEY_PJ_ID));
                    op.put(ObjInfosTable.KEY_OBJ_TYPE, latest.get(ObjInfosTable.KEY_OBJ_TYPE));
                    op.put(ObjInfosTable.KEY_OBJ_ID, latest.get(ObjInfosTable.KEY_OBJ_ID));
                    op.put(ObjInfosTable.KEY_INFO_ID, latest.get(ObjInfosTable.KEY_INFO_ID));
                    op.put(ObjInfosTable.KEY_TIME, latest.get(ObjInfosTable.KEY_TIME));
                    if (value.get("value") == null) {
                        deleteCriterias.add(op);
                    } else {
                        updateCriterias.add(op);
                        updateSets.add(generateInfoSet(value.get("value")));
                    }
                } else  // 没有查到值, 则添加上当前时间, 添加到信息点里面. 如果要修改的信息点的值为null, 则忽略.
                {
                    JSONObject value = (JSONObject) correspondingOp.get(i);
                    if (value.get("value") == null)
                        continue;
                    JSONObject obj = (JSONObject) selectCriterias.get(i);
                    obj.put(ObjInfosTable.KEY_TIME, time);
                    insertObjects.add(generateInfoRow(obj, obj.get(ObjInfosTable.KEY_INFO_ID).toString(), value.get("value"), time));
                }
            }
        }
        JSONArray infos_MQLog = new JSONArray(); // send to message queue and write to log.
        // 开始执行删除操作
        if (deleteCriterias.size() > 0) {
            JSONObject deleteResult = CommonUtil.delete(true, HBaseTable.obj_infos, deleteCriterias);
            JSONArray deleteResultContent = (JSONArray) deleteResult.get("Content");
            for (int i = 0; i < deleteResultContent.size(); ++i) {
                JSONObject one = (JSONObject) deleteResultContent.get(i);
                if ((one.getLongValue("Count")) <= 0) {
                    JSONObject deleteInfo = (JSONObject) deleteCriterias.get(i);
                    String id = CommonUtil.combineId(deleteInfo.get(ObjInfosTable.KEY_PJ_ID).toString(), deleteInfo.get(ObjInfosTable.KEY_OBJ_TYPE).toString()
                            , deleteInfo.get(ObjInfosTable.KEY_OBJ_ID).toString());
                    StringBuilder sb = new StringBuilder();
                    sb.append("ID:").append(id).append("在删除起效时间为").append(deleteInfo.get("time").toString()).append("的").append(deleteInfo.get(ObjInfosTable.KEY_INFO_ID)).append("时失败");
                    error.add(sb.toString());
                } else if (MQLog) {
                    JSONObject deleteInfo = (JSONObject) deleteCriterias.get(i);
                    JSONObject arr = new JSONObject();
                    arr.put(ObjInfosTable.KEY_PJ_ID, deleteInfo.get(ObjInfosTable.KEY_PJ_ID));
                    if (deleteInfo.get(ObjInfosTable.KEY_OBJ_TYPE).toString().startsWith("VO") || deleteInfo.get(ObjInfosTable.KEY_OBJ_TYPE).toString().startsWith("Ec"))// 虚拟对象和部件 不记录行为日志
                        continue;
                    arr.put(ObjInfosTable.KEY_OBJ_TYPE, deleteInfo.get(ObjInfosTable.KEY_OBJ_TYPE));
                    arr.put(ObjInfosTable.KEY_OBJ_ID, deleteInfo.get(ObjInfosTable.KEY_OBJ_ID));
                    arr.put(ObjInfosTable.KEY_INFO_ID, deleteInfo.get(ObjInfosTable.KEY_INFO_ID));
                    arr.put(ObjInfosTable.KEY_TIME, deleteInfo.get(ObjInfosTable.KEY_TIME).toString());
                    arr.put("info_value", null);
                    arr.put("description", "信息点删除, 删除起效时间");
                    infos_MQLog.add(arr);
                }
            }
        }
        // 开始执行插入操作
        if (insertObjects.size() > 0) {
            HashMap<String, JSONObject> idToObject = new HashMap<>(); // id + time -->  一行数据组成的JSONObject
            for (int i = 0; i < insertObjects.size(); ++i) {
                JSONObject obj = (JSONObject) insertObjects.get(i);
                StringBuilder sb = new StringBuilder();
                sb.append(obj.get(ObjInfosTable.KEY_PJ_ID)).append(obj.get(ObjInfosTable.KEY_OBJ_TYPE))
                        .append(obj.get(ObjInfosTable.KEY_OBJ_ID)).append(obj.get(ObjInfosTable.KEY_INFO_ID))
                        .append(obj.get(ObjInfosTable.KEY_TIME));
                idToObject.put(sb.toString(), obj);
            }
            JSONObject insertResult = CommonUtil.insert(true, HBaseTable.obj_infos, insertObjects);
            JSONArray insertResultContent = (JSONArray) insertResult.get("Content");
            //找出插入失败的值, 添加进更新操作里
            for (int i = 0; i < insertResultContent.size(); ++i) {
                JSONObject originalData = (JSONObject) insertResultContent.get(i);
                StringBuilder sb = new StringBuilder();
                sb.append(originalData.get(ObjInfosTable.KEY_PJ_ID)).append(originalData.get(ObjInfosTable.KEY_OBJ_TYPE))
                        .append(originalData.get(ObjInfosTable.KEY_OBJ_ID)).append(originalData.get(ObjInfosTable.KEY_INFO_ID))
                        .append(originalData.get(ObjInfosTable.KEY_TIME));
                if (idToObject.containsKey(sb.toString())) {
                    JSONObject failure = idToObject.get(sb.toString());
                    failure.remove(Const.TABLE_KEY_NAME_VALID);
                    JSONObject set = splitInsertToUpdate(failure);
                    updateCriterias.add(failure);
                    updateSets.add(set);
                    idToObject.remove(sb.toString());
                }
            }
            if (MQLog) {
                for (String key : idToObject.keySet()) {
                    JSONObject inserted = idToObject.get(key);
                    JSONObject arr = new JSONObject();
                    arr.put(ObjInfosTable.KEY_PJ_ID, inserted.get(ObjInfosTable.KEY_PJ_ID));
//                    if (inserted.get(ObjInfosTable.KEY_OBJ_TYPE).toString().startsWith("VO") || inserted.get(ObjInfosTable.KEY_OBJ_TYPE).toString().startsWith("Ec"))// 虚拟对象和部件 不记录行为日志
//                        continue;
                    if (inserted.get(ObjInfosTable.KEY_OBJ_TYPE).toString().startsWith("VO"))// 虚拟对象 不记录行为日志
                        continue;
                    arr.put(ObjInfosTable.KEY_OBJ_TYPE, inserted.get(ObjInfosTable.KEY_OBJ_TYPE));
                    arr.put(ObjInfosTable.KEY_OBJ_ID, inserted.get(ObjInfosTable.KEY_OBJ_ID));
                    arr.put(ObjInfosTable.KEY_INFO_ID, inserted.get(ObjInfosTable.KEY_INFO_ID));
                    arr.put(ObjInfosTable.KEY_TIME, inserted.get(ObjInfosTable.KEY_TIME).toString());
                    arr.put("info_value", CommonUtil.getValue(inserted).toString());
                    arr.put("description", "信息点添加, 添加起效时间");
                    infos_MQLog.add(arr);
                }
            }
        }
        // 开始执行更新操作
        if (updateCriterias.size() > 0) {
            JSONObject updateResult = CommonUtil.update(true, HBaseTable.obj_infos, updateCriterias, updateSets);
            JSONArray updateResultArray = (JSONArray) updateResult.get("Content");
            for (int i = 0; i < updateResultArray.size(); ++i) {
                JSONObject oneResult = (JSONObject) updateResultArray.get(i);
                if ((oneResult.getLongValue("Count")) <= 0L) {
                    JSONObject updateInfo = (JSONObject) updateCriterias.get(i);
                    String id = CommonUtil.combineId(updateInfo.get(ObjInfosTable.KEY_PJ_ID).toString(), updateInfo.get(ObjInfosTable.KEY_OBJ_TYPE).toString()
                            , updateInfo.get(ObjInfosTable.KEY_OBJ_ID).toString());
                    StringBuilder sb = new StringBuilder();
                    sb.append("ID:").append(id).append("在更新起效时间为").append(updateInfo.get("time").toString()).append("的").append(updateInfo.get(ObjInfosTable.KEY_INFO_ID)).append("时失败");
                    error.add(sb.toString());
                } else if (MQLog) {
                    JSONObject updateInfo = (JSONObject) updateCriterias.get(i);
                    JSONObject value = (JSONObject) updateSets.get(i);
                    JSONObject arr = new JSONObject();
                    arr.put(ObjInfosTable.KEY_PJ_ID, updateInfo.get(ObjInfosTable.KEY_PJ_ID));
//                    if (updateInfo.get(ObjInfosTable.KEY_OBJ_TYPE).toString().startsWith("VO") || updateInfo.get(ObjInfosTable.KEY_OBJ_TYPE).toString().startsWith("Ec"))      // 虚拟对象和部件 不记录行为日志
//                        continue;
//                    if (updateInfo.get(ObjInfosTable.KEY_OBJ_TYPE).toString().startsWith("VO"))      // 虚拟对象 不记录行为日志
//                        continue;
                    arr.put(ObjInfosTable.KEY_OBJ_TYPE, updateInfo.get(ObjInfosTable.KEY_OBJ_TYPE));
                    arr.put(ObjInfosTable.KEY_OBJ_ID, updateInfo.get(ObjInfosTable.KEY_OBJ_ID));
                    arr.put(ObjInfosTable.KEY_INFO_ID, updateInfo.get(ObjInfosTable.KEY_INFO_ID));
                    arr.put(ObjInfosTable.KEY_TIME, updateInfo.get(ObjInfosTable.KEY_TIME).toString());
                    arr.put("info_value", CommonUtil.getValue(value).toString());
                    arr.put("description", "信息点值发生变化, 更新起效时间");
                    infos_MQLog.add(arr);
                }
            }
        }
        if (MQLog)
            ActivityLogUtil.objectInfoChange(projectId, infos_MQLog, MQType.infoValueChange, time);
        return error;
    }

    public static JSONObject genLocationNode(String sonId, ArrayList<String> superSet) {
        JSONObject json = new JSONObject();
        for (String father : superSet) {
            if (father.startsWith(Const.OBJ_TYPE_BUILDING)) {
                json.put("building", father);
                if(sonId.startsWith("Sy")){
                    json.put("buildings", superSet.stream().filter(id -> id.startsWith("Bd")).toArray());
                }
            } else if (father.startsWith(Const.OBJ_TYPE_FLOOR)) {
                json.put("floor", father);
            } else if (father.startsWith(Const.OBJ_TYPE_EQUIPMENT)) {
                json.put("equipment", father);
            }
        }
        return json;
    }

    public static boolean checkMoveType(String moveId, String toId) {
        if (!DpUtils.checkId(moveId) || (toId.length() != 0 && !DpUtils.checkId(toId)))
            return false;
        // toId 为空字符时, 即取消moveId的subset关系
        if(toId.length() == 0){
            if(moveId.startsWith(Const.OBJ_TYPE_SPACE) || moveId.startsWith(Const.OBJ_TYPE_FLOOR) || moveId.startsWith(Const.OBJ_TYPE_SYSTEM) ||
                    moveId.startsWith(Const.OBJ_TYPE_EQUIPMENT)){
                return true;
            }else
                return false;
        }
        if (moveId.startsWith(Const.OBJ_TYPE_SPACE) && (toId.startsWith(Const.OBJ_TYPE_FLOOR) || toId.startsWith(Const.OBJ_TYPE_BUILDING)))
            return true;
        if (moveId.startsWith(Const.OBJ_TYPE_FLOOR) && toId.startsWith(Const.OBJ_TYPE_BUILDING))
            return true;
        if (moveId.startsWith(Const.OBJ_TYPE_SYSTEM) && toId.startsWith(Const.OBJ_TYPE_BUILDING))
            return true;
        if (moveId.startsWith(Const.OBJ_TYPE_EQUIPMENT) && toId.startsWith(Const.OBJ_TYPE_BUILDING))
            return true;
//        if(moveId.startsWith(Const.OBJ_TYPE_VERTICAL_SHAFT) && toId.startsWith(Const.OBJ_TYPE_BUILDING))
//            return true;
        return false;
    }

    /**
     * 过滤对象的valid
     * @param pjId 项目id, 不带Pj
     * @param ids 对象id的集合
     * @param valid 保留集合中对象id的条件
     * @param idSubTypeMap 作为返回, 传一个空map, 返回key-->对象id, value-->subtype
     * @return  数据库出错时返回false. 其他返回true
     */
    public static boolean filterValid(String pjId, Set<String> ids, Boolean valid, HashMap<String, String> idSubTypeMap) {
        if (ids.size() == 0)
            return true;
        JSONArray arr = new JSONArray();
        for (String id : ids) {
            JSONObject object = new JSONObject();
            object.put("id", id);
            try {
                CommonUtil.rewriteObjectTableCriteria(pjId, object, "id", true);
                object.put(ObjectTable.KEY_PJ_ID, pjId);
                arr.add(object);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            Set<String> validIds = new HashSet<>();
            JSONObject result = CommonUtil.combine_query(HBaseTable.objects, arr);
            JSONArray content = (JSONArray) result.get("Content");
            for (int i = 0; i < content.size(); ++i) {
                JSONObject single = (JSONObject) content.get(i);
                if (valid != null) {
                    if (single.get(ObjectTable.COL_VALID) == null || !single.get(ObjectTable.COL_VALID).equals(valid)) {
                        continue;
                    }
                }
                String id = CommonUtil.combineId(pjId, Strings.nullToEmpty((String) single.get(ObjectTable.KEY_OBJ_TYPE)), Strings.nullToEmpty((String) single.get(ObjectTable.KEY_OBJ_ID)));
                if (!validIds.contains(id)) {
                    validIds.add(id);
                    if (idSubTypeMap != null)
                        idSubTypeMap.put(id, Strings.nullToEmpty((String) single.get(ObjectTable.COL_SUBTYPE)));
                }
            }
            ids.retainAll(validIds);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static void deleteAllRelation(String pjId, ArrayList<String> validIdArr) {
        if(validIdArr.size() == 0)
            return;
        JSONArray criterias = new JSONArray();
        for (int i = 0; i < validIdArr.size(); ++i) {
            JSONObject fromJson = new JSONObject();
            JSONObject toJson = new JSONObject();
            String id = validIdArr.get(i);
            try {
                fromJson.put(Const.JSON_FIELD_FROM_ID, id);
                RelationUtil.rewriteCriteria(fromJson, Const.JSON_FIELD_FROM_ID);
                fromJson.put(RelTable.KEY_PJ_ID, pjId);
                toJson.put(Const.JSON_FIELD_TO_ID, id);
                RelationUtil.rewriteCriteria(toJson, Const.JSON_FIELD_TO_ID);
                toJson.put(RelTable.KEY_PJ_ID, pjId);
                criterias.add(fromJson);
                criterias.add(toJson);
            } catch (Exception e) {
                log.error("", e);
            }
        }
        try {
            Set<String> graphIds = queryAffectedGraphIds(criterias);
            CommonUtil.combine_delete(HBaseTable.rel_btw_objs, criterias);
            graphIds.forEach(gId ->
                    MessageHandler.publish(String.format("{\"type\":14,\"projectId\":\"%s\",\"graphId\":\"%s\",\"description\":\"\"}", CommonMethods.getProject(pjId, true), gId)));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查询受影响的图实例id
     * @param criterias
     * @return
     */
    public static Set<String> queryAffectedGraphIds(JSONArray criterias){
        Set<String> graphIds = new HashSet<>();
        try {
            JSONArray arr = CommonUtil.combine_query(HBaseTable.rel_btw_objs, criterias).getJSONArray("Content");
            for (int i = 0; i < arr.size(); i++) {
                graphIds.add(arr.getJSONObject(i).getString(RelTable.KEY_GRAPH_ID));
            }
        } catch (Exception e) {
            log.error("", e);
        }
        return graphIds;
    }

    public static void deleteEcUnderEquip(String pjId, ArrayList<String> disableObjs, ArrayList<String> deleteObjs) {
        JSONArray arr = new JSONArray();
        Set<String> disableSet = new HashSet<>();
        Set<String> deleteSet = new HashSet<>();
        putArrToSet(deleteObjs, arr, deleteSet);
        putArrToSet(disableObjs, arr, disableSet);
        Set<String> tmpSet = new HashSet<>();
        tmpSet.addAll(disableSet);
        tmpSet.addAll(deleteSet);
        if (tmpSet.size() == 0)
            return;
        try {
            // equipId --> set<EcId>
            Map<String, Set<String>> equipEcMap = RelationUtil.getRelations(pjId, "Subset", "5", tmpSet, true);
            Set<String> disableEcId = new HashSet<>();
            Set<String> deleteEcId = new HashSet<>();
            for (String equipId : equipEcMap.keySet()) {
                if (equipEcMap.get(equipId) == null)
                    continue;
                if (disableSet.contains(equipId)) {
                    disableEcId.addAll(equipEcMap.get(equipId));
                } else
                    deleteEcId.addAll(equipEcMap.get(equipId));
            }
            if (disableEcId.size() > 0)
                CommonUtil.batchDeleteObject(pjId, disableEcId, true, false);
            if (deleteEcId.size() > 0)
                CommonUtil.batchDeleteObject(pjId, deleteEcId, true, true);
        } catch (Exception ex) {
            return;
        }
    }

    private static void putArrToSet(ArrayList<String> deleteObjs, JSONArray arr, Set<String> deleteSet) {
        for (int i = 0; i < deleteObjs.size(); ++i) {
            String id = deleteObjs.get(i);
            if (!id.startsWith(Const.OBJ_TYPE_EQUIPMENT))
                continue;
            JSONObject obj = new JSONObject();
            obj.put(Const.JSON_FIELD_FROM_ID, id);
            try {
                RelationUtil.rewriteCriteria(obj, Const.JSON_FIELD_FROM_ID);
                arr.add(obj);
                deleteSet.add(id);
            } catch (Exception e) {
            }
        }
    }

    public static void batchAddVirtualObj(String pjId, JSONArray criterias, JSONArray success, JSONArray errors) throws Exception {
        Map<String, ObjectIdName> nameMap = new HashMap<>();
        // 1. 检查每个节点是否都存在, 指定的id, 或者生成id
        checkVOIds(pjId, criterias, errors);
        // 2. 检查信息点
        checkVOInfos(pjId, criterias, errors, nameMap);
        // 3. 添加进对象表
        writeVOObjects(pjId, criterias, errors, nameMap);
        ArrayList<ActivityLogObject> logList = new ArrayList<>();
        for(int i = 0; i < criterias.size(); ++i) {
            JSONObject single = criterias.getJSONObject(i);
            String id = single.getString("id");
            ObjectType ot = VirtualObject.getObjectType(id.substring(0, 4));
            // 添加要发送到activeMQ的消息
            ActivityLogUtil.addMessageToQueue(pjId, nameMap.get(id).getCreateTime(), logList, id, ot);
            JSONObject singleSuccess = new JSONObject();
            singleSuccess.put("id", id);
            success.add(singleSuccess);
        }
        // 4. 添加信息点
        batchUpdate(pjId, criterias, false, true, false, new CommonQueryCriteria());
        // 5. 发送创建消息
        ActivityLogRunnable activityLog = new ActivityLogRunnable(logList);
        ActivityLogUtil.pool.submit(activityLog);
    }

    private static void writeVOObjects(String pjId, JSONArray criterias, JSONArray errors, Map<String, ObjectIdName> nameMap) throws Exception {
        JSONArray arr = new JSONArray();
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject single = criterias.getJSONObject(i);
            String id = single.getString("id");
            JSONObject writeObject = new JSONObject();
            writeObject.put(ObjectTable.KEY_PJ_ID, pjId);
            writeObject.put(ObjectTable.KEY_OBJ_TYPE, single.getString("type"));
            writeObject.put(ObjectTable.KEY_OBJ_ID, id.substring(14));
            writeObject.put(ObjectTable.KEY_CREATE_TIME, nameMap.get(id).getCreateTime());
            writeObject.put(ObjectTable.COL_VALID, true);
            arr.add(writeObject);
        }
        JSONObject result = CommonUtil.insert(true, HBaseTable.objects, arr);
        if(result.getString("Result").equals("failure")) {
            JSONArray insertResultContent = result.getJSONArray("Content");
            if(insertResultContent.size() == 0)
                return ;
            Set<String> duplicateIds = new HashSet<>();
            //找出插入失败的对象
            for (int i = 0; i < insertResultContent.size(); ++i) {
                JSONObject originalData = (JSONObject) insertResultContent.get(i);
                StringBuilder id = new StringBuilder();
                id.append(originalData.get(ObjectTable.KEY_OBJ_TYPE)).append(originalData.get(ObjectTable.KEY_PJ_ID))
                        .append(originalData.get(ObjectTable.KEY_OBJ_ID));
                duplicateIds.add(id.toString());
            }
            for(int i = criterias.size() - 1; i > -1; --i){
                JSONObject single = criterias.getJSONObject(i);
                String id = single.getString("id");
                if(duplicateIds.contains(id)){
                    PropertyUtil.moveToError(criterias, i, errors, "id已存在");
                    continue;
                }
            }
        }
    }

    private static void checkVOInfos(String pjId, JSONArray criterias, JSONArray errors, Map<String, ObjectIdName> nameMap) throws Exception {
        Map<String, HashMap<String, InfoPoint>> cache_VO = InfosUtil.getVOCache();
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject single = criterias.getJSONObject(i);
            JSONObject infos = single.getJSONObject("infos");
            ObjectIdName objectName = new ObjectIdName();
            String missingInfo = InfosUtil.CheckIntegrityAtCreation(pjId, VirtualObject.getObjectType(single.get("type").toString()),
                    single.getString("type"), infos, single.getString("id"), objectName);
            if(missingInfo != null){
                PropertyUtil.moveToError(criterias, i, errors, "不存在信息点:" + missingInfo);
                continue;
            }
            nameMap.put(single.getString("id"), objectName);
        }
    }

    private static void checkVOIds(String pjId, JSONArray criterias, JSONArray errors) {
        Set<String> idSet = new HashSet<>();
        for(int i = criterias.size() - 1; i > -1; --i){
            JSONObject obj = criterias.getJSONObject(i);
            if(obj == null || !obj.containsKey("type") || !obj.containsKey(Const.JSON_FIELD_JSON_DATA_INFOS)){
                PropertyUtil.moveToError(criterias, i, errors, "格式不正确");
                continue;
            }
            String type = Strings.nullToEmpty(obj.getString("type"));
            if(!VirtualObject.allowedVO.contains(type)){
                PropertyUtil.moveToError(criterias, i, errors, "类型不正确");
                continue;
            }
            String id = Strings.nullToEmpty(obj.getString("id"));
            if(id.length() > 0){
                if(!DpUtils.checkId(pjId, id)){
                    PropertyUtil.moveToError(criterias, i, errors, "指定id错误");
                    continue;
                }
                if(!id.startsWith(type)){
                    PropertyUtil.moveToError(criterias, i, errors, "指定id和类型不匹配");
                    continue;
                }
                if(idSet.contains(id)){
                    PropertyUtil.moveToError(criterias, i, errors, "指定id出现重复");
                    continue;
                }else
                    idSet.add(id);
            }else{
                id = DpUtils.generateUUID(type + pjId, true);       // 生成id
                obj.put("id", id);
            }
        }
    }


}
