package com.sagacloud.utils.relationUtils;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.base.Strings;
import com.sagacloud.broadcast.MessageHandler;
import com.sagacloud.dict.EqStaticInfo;
import com.sagacloud.dict.RelStaticInfo;
import com.sagacloud.exception.IdGenException;
//import com.sagacloud.json.JSONArray;
//import com.sagacloud.json.JSONObject;
//import com.sagacloud.json.JSONValue;
import com.alibaba.fastjson.*;
import com.sagacloud.utils.*;
import com.sagacloud.utils.jsonHelper.property.PropertyGraphEnum;
import com.sagacloud.utils.objects.CommonQueryCriteria;
import com.sagacloud.utils.objects.IncludeExclude;
import com.sagacloud.utils.objects.RelationCriteria;
import com.sagacloud.utils.objects.RelationSide;
import com.sagacloud.utils.tables.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

import static com.sagacloud.utils.relationUtils.PropertyRelUtil.createGraph;

public class RelationUtil {
    private static final Logger log = LoggerFactory.getLogger(RelationUtil.class);

    //pjId=1101080001,jsonStr 需包含 from_id,to_id,graph_id,rel_type,"infos":{}
    public static String createRelation(String pjId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            log.info("createRelation : {}", json.toString().length() > 400 ? json.toString().substring(0, 400) : json.toString());
            json.put(RelTable.KEY_PJ_ID, pjId);
            if (!json.containsKey(Const.JSON_FIELD_JSON_DATA_INFOS) || json.get(Const.JSON_FIELD_JSON_DATA_INFOS) == null)
                json.put(Const.JSON_FIELD_JSON_DATA_INFOS, new JSONObject());
            rewriteCriteria(json, Const.JSON_FIELD_FROM_ID);
            rewriteCriteria(json, Const.JSON_FIELD_TO_ID);


            //插入关系
            JSONObject re = CommonUtil.insert(false, HBaseTable.rel_btw_objs, json);
            if (re.get(Const.JSON_FIELD_RESULT) != "success") {
                return DpUtils.errorJsonMsg("已存在");
            }
            //批量插入信息点
            JSONArray insertObjs = CommonUtil.processJSONDataToInfoPointsWithId(json);
            CommonUtil.insert(true, HBaseTable.rel_infos, insertObjs);
            return DpUtils.successJsonMsg("");
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    public static String batchCreateRelation(String pjId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            if (!json.containsKey("criterias")) {//单条操作按批量进行处理
                JSONArray criterias = new JSONArray();
                criterias.add(JSONObject.parseObject(json.toString()));
                json.clear();
                json.put("criterias", criterias);
            }
            JSONArray criterias = json.getJSONArray("criterias");
            //过滤重复的关系
            Set<String> relNodeSet = new HashSet<>();
            for (int i = criterias.size() - 1; i >= 0; --i) {
                JSONObject node = criterias.getJSONObject(i);
                String key = String.join("|", node.getString(RelTable.KEY_GRAPH_ID), node.getString(RelTable.KEY_REL_TYPE), node.getString(Const.JSON_FIELD_FROM_ID), node.getString(Const.JSON_FIELD_TO_ID)).trim();
                if (relNodeSet.contains(key)) {
                    criterias.remove(i);
                } else {
                    relNodeSet.add(key);
                }
            }

            for (int i = 0; i < criterias.size(); ++i) {
                criterias.getJSONObject(i).put(RelTable.KEY_PJ_ID, pjId);
                rewriteCriteria((JSONObject) criterias.get(i), Const.JSON_FIELD_FROM_ID);
                rewriteCriteria((JSONObject) criterias.get(i), Const.JSON_FIELD_TO_ID);
            }
            JSONArray criteriasWithoutInfos = JSONArray.parseArray(criterias.toString());
            JSONArray faliureContent = new JSONArray();
            CommonUtil.removeField(criteriasWithoutInfos, Const.JSON_FIELD_JSON_DATA_INFOS);

            JSONObject re = CommonUtil.getCount(true, HBaseTable.rel_btw_objs, criteriasWithoutInfos);
            JSONArray existedContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < existedContent.size(); ++i) {
                if (((JSONObject) existedContent.get(i)).getLongValue("Count") > 0) {
                    faliureContent.add(criterias.get(i));
                    criterias.remove(i);
                    existedContent.remove(i);
                    --i;
                }
            }
            for (int i = 0; i < criterias.size(); ++i) {
                if (((JSONObject) criterias.get(i)).get(Const.JSON_FIELD_JSON_DATA_INFOS) == null) {
                    ((JSONObject) criterias.get(i)).put(Const.JSON_FIELD_JSON_DATA_INFOS, new JSONObject());
                }
            }
            if (criterias.size() > 0) {
                CommonUtil.insert(true, HBaseTable.rel_btw_objs, criterias);
                JSONArray insertObjs = new JSONArray();
                for (int i = 0; i < criterias.size(); ++i) {
                    JSONObject insertObj = (JSONObject) criterias.get(i);
                    insertObjs.addAll(CommonUtil.processJSONDataToInfoPointsWithId(insertObj));
                }
                CommonUtil.insert(true, HBaseTable.rel_infos, insertObjs);
            }

            for (int i = 0; i < faliureContent.size(); ++i) {
                combineId((JSONObject) faliureContent.get(i));
            }
            MessageHandler.publish(String.format("{\"type\":8,\"projectId\":\"%s\",\"name\":\"relationChange\",\"description\":\"\"}", CommonMethods.getProject(pjId, true)));
            Set<String> ids = new HashSet<>();
            relNodeSet.forEach(str -> ids.add(str.split("|")[0]));
            ids.forEach(id ->
                    MessageHandler.publish(String.format("{\"type\":14,\"projectId\":\"%s\",\"graphId\":\"%s\",\"description\":\"\"}", CommonMethods.getProject(pjId, true), id))
            );
            return DpUtils.returnJSONArray(faliureContent, "");
        } catch (Exception e) {
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    //doFlatten 为 true时，批量查询返回结果只有一层Content，并且去重
    public static String queryRelation(String pjId, String jsonStr, Boolean doFlatten) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            log.info("queryRelation : {}", json.toString().length() > 400 ? json.toString().substring(0, 400) : json.toString());
            Boolean isBatchquery = json.containsKey("criterias");
            JSONArray criteriasNode;
            if (isBatchquery) {
                criteriasNode = (JSONArray) json.get("criterias");
            } else {//单条查询按照批量查询来处理
                criteriasNode = new JSONArray();
                criteriasNode.add(json.get("criteria"));
            }
            for (int i = 0; i < criteriasNode.size(); ++i) {
                rewriteCriteria((JSONObject) criteriasNode.get(i), Const.JSON_FIELD_FROM_ID);
                rewriteCriteria((JSONObject) criteriasNode.get(i), Const.JSON_FIELD_TO_ID);
                ((JSONObject) criteriasNode.get(i)).put(RelTable.KEY_PJ_ID, pjId);
            }

            JSONObject re = CommonUtil.query(true, HBaseTable.rel_btw_objs, criteriasNode);
            JSONArray outterContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
//            for (int i = 0; i < outterContent.size(); ++i) {
//                JSONArray innerContent = (JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content);
//                batchQueryRelInfos(innerContent);
//            }
            queryRelInfos(outterContent);
            if (!isBatchquery)//单条查询时将结果平铺
                flatten(re);
            else if (doFlatten)//批量查询并且需要doFlatten
                flatten(re);
            return re.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    public static JSONObject queryRelationWithBidirection(String pjId, String jsonStr, Boolean doFlatten) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        log.info("queryRelationWithBidirection : {}", json.toString().length() > 400 ? json.toString().substring(0, 400) : json.toString());
        Boolean isBatchquery = json.containsKey("criterias");
        JSONArray criteriasNode;
        if (isBatchquery) {
            criteriasNode = (JSONArray) json.get("criterias");
        } else {//单条查询按照批量查询来处理
            criteriasNode = new JSONArray();
            criteriasNode.add(json.get("criteria"));
        }
        try {
            Hashtable directionalMap = buildDirectionalMap(pjId);
            Hashtable<Integer, Integer> needToChangeIndex = new Hashtable<>();
            int oriSize = criteriasNode.size();
            //1.将 无向关系 颠倒写入查询条件
            for (int i = 0; i < oriSize; ++i) {
                JSONObject obj = (JSONObject) criteriasNode.get(i);
                boolean xor = obj.containsKey(Const.JSON_FIELD_FROM_ID) ^ obj.containsKey(Const.JSON_FIELD_TO_ID);
                if (obj.containsKey(RelTable.KEY_GRAPH_ID) && obj.containsKey(RelTable.KEY_REL_TYPE) && xor) {
                    //含有graph_id,rel_type,只含有from_id和to_id中的一个
                    String graphId = obj.get(RelTable.KEY_GRAPH_ID).toString();
                    if (graphId.length() < 5) {
                        throw new Exception("illegal graph_id : " + graphId);
                    }
                    String graphType = graphId.substring(2, graphId.length() - 3);
                    String relType = obj.get(RelTable.KEY_REL_TYPE).toString();
                    Boolean directional = (Boolean) directionalMap.get(graphType + "," + relType);
                    if (directional == null) {
                        return DpUtils.errorJsonObjectMsg("未识别的graph_id和rel_type");
                    }
                    if (directional != true) {//无向
                        JSONObject reObj = JSONObject.parseObject(obj.toString());
                        //交换from和to的位置
                        if (reObj.containsKey(Const.JSON_FIELD_FROM_ID)) {
                            reObj.put(Const.JSON_FIELD_TO_ID, reObj.get(Const.JSON_FIELD_FROM_ID));
                            reObj.remove(Const.JSON_FIELD_FROM_ID);
                        } else {
                            reObj.put(Const.JSON_FIELD_FROM_ID, reObj.get(Const.JSON_FIELD_TO_ID));
                            reObj.remove(Const.JSON_FIELD_TO_ID);
                        }
                        criteriasNode.add(reObj);
                        needToChangeIndex.put(i, criteriasNode.size() - 1);
                    }
                }
            }
            //1.end
            //2.查询
            for (int i = 0; i < criteriasNode.size(); ++i) {
                rewriteCriteria((JSONObject) criteriasNode.get(i), Const.JSON_FIELD_FROM_ID);
                rewriteCriteria((JSONObject) criteriasNode.get(i), Const.JSON_FIELD_TO_ID);
                ((JSONObject) criteriasNode.get(i)).put(RelTable.KEY_PJ_ID, pjId);
            }
            JSONObject re = CommonUtil.query(true, HBaseTable.rel_btw_objs, criteriasNode);
            JSONArray outterContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
//            for (int i = 0; i < outterContent.size(); ++i) {
//                JSONArray innerContent = (JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content);
//                batchQueryRelInfos(innerContent);
//            }
            queryRelInfos(outterContent);
            //2.end
            //3.整理查询结果
            outterContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < oriSize; ++i) {
                if (needToChangeIndex.containsKey(i)) {
                    JSONObject obj = (JSONObject) outterContent.get(i);
                    JSONObject additionalObj = (JSONObject) outterContent.get(needToChangeIndex.get(i));
                    obj.put("Count", obj.getLongValue("Count") + additionalObj.getLongValue("Count"));
                    ((JSONArray) obj.get("Content")).addAll((JSONArray) additionalObj.get("Content"));
                }
            }
            for (int j = outterContent.size() - 1; j >= oriSize; --j) {
                outterContent.remove(j);
            }
            re.put("Count", outterContent.size());
            //3.end
            if (!isBatchquery)//单条查询时将结果平铺
                flatten(re);
            else if (doFlatten)//批量查询并且需要doFlatten
                flatten(re);
            return re;
        } catch (Exception e) {
            return DpUtils.errorJsonObjectMsg(e.getMessage());
        }
    }

    public static String updateRelation(String pjId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        log.info("updateRelation : {}", json.toString().length() > 400 ? json.toString().substring(0, 400) : json.toString());
        if (!json.containsKey("criterias")) {//单条操作按照批量来处理
            JSONArray criteriasNode = new JSONArray();
            JSONArray setsNode = new JSONArray();
            criteriasNode.add(json.get("criteria"));
            setsNode.add(json.get("set"));
            json.remove("criteria");
            json.remove("set");
            json.put("criterias", criteriasNode);
            json.put("sets", setsNode);
        }
        JSONArray criteriasNode = (JSONArray) json.get("criterias");
        //判断json格式
        String errMsg = validateUpdateCriterias(criteriasNode);
        if (errMsg != null)
            return DpUtils.errorJsonMsg(errMsg);
        //end
        JSONObject queryJson = new JSONObject();
        queryJson.put("criterias", criteriasNode);
        JSONArray setsNode = (JSONArray) json.get("sets");
        String historyData = queryRelation(pjId, queryJson.toString(), false);//更新失败时，记录日志
        JSONObject re = JSONObject.parseObject(historyData);//查询出已存在内容

        if (!re.get(Const.JSON_FIELD_RESULT).toString().equals("success"))
            return DpUtils.errorJsonMsg("查询已有数据时失败");

        JSONArray outterContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
        JSONArray insertArr = new JSONArray();
        JSONArray updateArr = new JSONArray();
        JSONArray deleteArr = new JSONArray();
        for (int i = 0; i < outterContent.size(); ++i) {
            JSONObject targetSetNode = (JSONObject) setsNode.get(i);
            JSONArray innerContent = (JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content);
            classify(targetSetNode, innerContent, insertArr, updateArr, deleteArr);
        }
        try {
            batchInsert(HBaseTable.rel_infos, insertArr);
            batchDelete(HBaseTable.rel_infos, deleteArr);
            batchUpdate(HBaseTable.rel_infos, updateArr);
            MessageHandler.publish(String.format("{\"type\":8,\"projectId\":\"%s\",\"name\":\"relationChange\",\"description\":\"\"}", CommonMethods.getProject(pjId, true)));

            //发图实例关系变更广播
            Set<String> gids = new HashSet<>();
            for (int i = 0; i < criteriasNode.size(); i++) {
                JSONObject obj = (JSONObject) criteriasNode.get(i);
                gids.add(obj.getString(RelTable.KEY_GRAPH_ID));
            }
            gids.forEach(id ->
                    MessageHandler.publish(String.format("{\"type\":14,\"projectId\":\"%s\",\"graphId\":\"%s\",\"description\":\"\"}", CommonMethods.getProject(pjId, true), id))
            );

            return DpUtils.successJsonMsg("更新成功");
        } catch (Exception e) {
            e.printStackTrace();
            log.info("更新出错，更新前数据为: {}", historyData);
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }


    public static String validateUpdateCriterias(JSONArray criterias) {
        String[] keys = new String[]{Const.JSON_FIELD_FROM_ID, Const.JSON_FIELD_TO_ID, RelTable.KEY_GRAPH_ID, RelTable.KEY_REL_TYPE};
        for (int i = 0; i < criterias.size(); ++i) {
            JSONObject obj = (JSONObject) criterias.get(i);
            for (String key : keys) {
                if (!obj.containsKey(key))
                    return "missing key : " + key;
            }
        }
        return null;
    }

    public static String deleteRelation(String pjId, String jsonStr) {

        JSONObject json = JSONObject.parseObject(jsonStr);
        log.info("deleteRelation : {}", json.toString().length() > 400 ? json.toString().substring(0, 400) : json.toString());
        if (json.containsKey("criteria")) {//单条操作按批量来处理
            JSONArray criterisNode = new JSONArray();
            criterisNode.add(json.get("criteria"));
            json.put("criterias", criterisNode);
            json.remove("criteria");
        }
        Set<String> gids = new HashSet<>();
        for (int i = 0; i < json.getJSONArray("criterias").size(); ++i) {
            if (json.getJSONArray("criterias").getJSONObject(i).get("graph_id") == null) {
                return DpUtils.errorJsonMsg("graph_id cannot be null");
            }
            gids.add(json.getJSONArray("criterias").getJSONObject(i).getString("graph_id"));
        }
        String historyData = queryRelationWithBidirection(pjId,
                JSON.toJSONString(json, SerializerFeature.WriteMapNullValue, SerializerFeature.DisableCircularReferenceDetect), true).toString();//删除出错时，记录日志
        JSONObject re = JSONObject.parseObject(historyData);
        if (!re.get(Const.JSON_FIELD_RESULT).toString().equals("success")) {
            return DpUtils.errorJsonMsg("查询已有数据时失败");
        }
        JSONArray content = (JSONArray) re.get(Const.JSON_FIELD_Content);
        JSONArray idList = JSONArray.parseArray(content.toString());
        CommonUtil.removeField(idList, Const.JSON_FIELD_JSON_DATA_INFOS);
        try {
            batchDelete(HBaseTable.rel_btw_objs, idList);
            batchDelete(HBaseTable.rel_infos, content);
            MessageHandler.publish(String.format("{\"type\":8,\"projectId\":\"%s\",\"name\":\"relationChange\",\"description\":\"\"}", CommonMethods.getProject(pjId, true)));
            gids.forEach(id ->
                    MessageHandler.publish(String.format("{\"type\":14,\"projectId\":\"%s\",\"graphId\":\"%s\",\"description\":\"\"}", CommonMethods.getProject(pjId, true), id))
            );
            return DpUtils.successJsonMsg("删除成功");
        } catch (Exception e) {
            e.printStackTrace();
            log.info("删除出错，删除前数据为 : {}", historyData);
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }

    }

//    public static boolean deleteRelation(String pjId, JSONObject json) throws Exception {
//        if (json.containsKey("criteria")) {//单条操作按批量来处理
//            JSONArray criterisNode = new JSONArray();
//            criterisNode.add(json.get("criteria"));
//            json.put("criterias", criterisNode);
//            json.remove("criteria");
//        }
//        JSONObject re = (JSONObject) JSONValue.parse(queryRelation(pjId, json.toString(), true));
//        if (!re.get(Const.JSON_FIELD_RESULT).toString().equals("success")) {
//            return false;
//        }
//        JSONArray content = (JSONArray) re.get(Const.JSON_FIELD_Content);
//        JSONArray idList = (JSONArray) JSONValue.parse(content.toString());
//        CommonUtil.removeField(idList, Const.JSON_FIELD_JSON_DATA_INFOS);
//        String time = CommonUtil.getTime();
//        //删除rel_btw_objs中的内容
//        batchDelete(HBaseTable.rel_btw_objs, idList);
//        //删除rel_infos中的内容
//        batchDelete(HBaseTable.rel_infos, content);
//        return true;
//    }


    public static void getPathsWithEndpoint(String srcId, String desId, String graph_type, Hashtable graphMap, JSONArray onePath, JSONArray allPaths) {
        onePath.add(srcId);
        if (srcId.equals(desId)) {
            JSONArray newOnePath = new JSONArray();
            newOnePath.addAll(onePath);
            allPaths.add(newOnePath);
            return;
        }
        String srcNode = String.join(",", srcId, graph_type, null);
        ArrayList<String> nextIds = (ArrayList<String>) graphMap.get(srcNode);
        if (nextIds == null || nextIds.size() == 0) {
            return;
        }

        for (int i = 0; i < nextIds.size(); ++i) {
            String nextId = nextIds.get(i);
            if (!alreadyInPath(onePath, nextId)) {
                getPathsWithEndpoint(nextId, desId, graph_type, graphMap, onePath, allPaths);
                onePath.remove(onePath.size() - 1);
            }
        }
    }

    private static Boolean alreadyInPath(JSONArray path, String id) {
        for (int i = 0; i < path.size(); ++i) {
            if (id.equals(path.get(i).toString())) {
                return true;
            }
        }
        return false;
    }

    public static void getPaths(String oriId, Hashtable graphMap, JSONArray paths, JSONArray onePath, JSONArray givenRelTypes, int depth) {
        if (depth == givenRelTypes.size()) {
            JSONArray newOnePath = new JSONArray();
            newOnePath.addAll(onePath);
            paths.add(newOnePath);
            return;
        }
        String graph_type = (String) ((JSONObject) givenRelTypes.get(depth)).get(RelTable.KEY_GRAPH_ID);
        String rel_type = (String) ((JSONObject) givenRelTypes.get(depth)).get(RelTable.KEY_REL_TYPE);
        String oriNode = String.join(",", oriId, graph_type, rel_type);
        if (!graphMap.containsKey(oriNode))
            return;
        ArrayList nextIds = (ArrayList) graphMap.get(oriNode);
        for (int i = 0; i < nextIds.size(); ++i) {
            String desId = (String) nextIds.get(i);
            if (desId.equals(oriId))
                return;
            if (!alreadyInPath(onePath, desId)) {
                onePath.add(desId);
                getPaths(desId, graphMap, paths, onePath, givenRelTypes, depth + 1);
                onePath.remove(onePath.size() - 1);
            }

        }

    }

    private static Hashtable buildDirectionalMap(String pjId) throws Exception {
        if (pjId.startsWith(Const.OBJ_TYPE_PROJECT)) {
            pjId = pjId.substring(2);
        }
        JSONObject json = new JSONObject();
        json.put(RelTable.KEY_PJ_ID, pjId);
        Hashtable directionalMap = new Hashtable();
        directionalMap.putAll(RelStaticInfo.globalGraphRelMap);
        JSONObject localRel = null;
//        try {
        localRel = CommonUtil.query(false, HBaseTable.rel_type_def, json);
        JSONArray content = (JSONArray) localRel.get(Const.JSON_FIELD_Content);
        for (int i = 0; i < content.size(); ++i) {
            String graph_type = (String) ((JSONObject) content.get(i)).get(RelDefTable.KEY_GRAPH_TYPE);
            String rel_type = (String) ((JSONObject) content.get(i)).get(RelDefTable.KEY_REL_TYPE);
            Boolean directional = (Boolean) ((JSONObject) content.get(i)).get(RelDefTable.KEY_DIRECTIONAL);
            directionalMap.put(graph_type + "," + rel_type, directional);
        }
        return directionalMap;
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return null;
    }

    //建立邻接表，key为id、graph_id、rel_type拼接而成，以英文逗号分隔，e.g Eq1101080003001ACATVA001,g1,r1
    //ArrayList里存储下游节点的id，e.g Eq1101080003001ACATVA002
    public static Hashtable<String, ArrayList> buildGraphMap(String pjId) {//pjId = 1101080001
        Hashtable<String, ArrayList> map = new Hashtable<>();
        JSONObject json = new JSONObject();
        json.put(RelTable.KEY_PJ_ID, pjId);
        Hashtable directionalMap = new Hashtable();
//        directionalMap.putAll(RelStaticInfo.globalGraphRelMap);
        try {
//            JSONObject localRel = CommonUtil.query(false, HBaseTable.rel_type_def, json);
//            JSONArray content = (JSONArray) localRel.get(Const.JSON_FIELD_Content);
//            for (int i = 0; i < content.size(); ++i) {
//                String graph_type = (String) ((JSONObject) content.get(i)).get(RelDefTable.KEY_GRAPH_TYPE);
//                String rel_type = (String) ((JSONObject) content.get(i)).get(RelDefTable.KEY_REL_TYPE);
//                Boolean directional = (Boolean) ((JSONObject) content.get(i)).get(RelDefTable.KEY_DIRECTIONAL);
//                directionalMap.put(graph_type + "," + rel_type, directional);
//            }
            directionalMap = buildDirectionalMap(pjId);
            json = CommonUtil.query(false, HBaseTable.rel_btw_objs, json);

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        if (json.get(Const.JSON_FIELD_RESULT) == null || !json.get(Const.JSON_FIELD_RESULT).toString().equals("success"))
            return null;
        JSONArray content = (JSONArray) json.get(Const.JSON_FIELD_Content);
        //存储三种形式的key：id,g_type,r_type; id,null,r_type; id,g_type,null
        for (int i = 0; i < content.size(); ++i) {
            JSONObject node = (JSONObject) content.get(i);
            combineId(node);
            String key1 = String.join(",", node.get(Const.JSON_FIELD_FROM_ID).toString(),
                    node.get(RelTable.KEY_GRAPH_ID).toString(), node.get(RelTable.KEY_REL_TYPE).toString());
            String key2 = String.join(",", node.get(Const.JSON_FIELD_FROM_ID).toString(),
                    null, node.get(RelTable.KEY_REL_TYPE).toString());
            String key3 = String.join(",", node.get(Const.JSON_FIELD_FROM_ID).toString(),
                    node.get(RelTable.KEY_GRAPH_ID).toString(), null);
            if (!map.containsKey(key1)) {
                map.put(key1, new ArrayList());
            }
            if (!map.containsKey(key2)) {
                map.put(key2, new ArrayList());
            }
            if (!map.containsKey(key3)) {
                map.put(key3, new ArrayList());
            }
            map.get(key1).add(node.get(Const.JSON_FIELD_TO_ID));
            map.get(key2).add(node.get(Const.JSON_FIELD_TO_ID));
            map.get(key3).add(node.get(Const.JSON_FIELD_TO_ID));
            //如果是无向的，以to_id作为key再插入一遍
            String key = String.join(",", node.get(RelTable.KEY_GRAPH_ID).toString(), node.get(RelTable.KEY_REL_TYPE).toString());
            if (directionalMap.containsKey(key) && !(boolean) directionalMap.get(key)) {
                String reKey1 = String.join(",", node.get(Const.JSON_FIELD_TO_ID).toString(),
                        node.get(RelTable.KEY_GRAPH_ID).toString(), node.get(RelTable.KEY_REL_TYPE).toString());
                String reKey2 = String.join(",", node.get(Const.JSON_FIELD_TO_ID).toString(),
                        null, node.get(RelTable.KEY_REL_TYPE).toString());
                String reKey3 = String.join(",", node.get(Const.JSON_FIELD_TO_ID).toString(),
                        node.get(RelTable.KEY_GRAPH_ID).toString(), null);
                if (!map.containsKey(reKey1)) {
                    map.put(reKey1, new ArrayList());
                }
                if (!map.containsKey(reKey2)) {
                    map.put(reKey2, new ArrayList());
                }
                if (!map.containsKey(reKey3)) {
                    map.put(reKey3, new ArrayList());
                }
                map.get(reKey1).add(node.get(Const.JSON_FIELD_FROM_ID));
                map.get(reKey2).add(node.get(Const.JSON_FIELD_FROM_ID));
                map.get(reKey3).add(node.get(Const.JSON_FIELD_FROM_ID));
            }
        }
        return map;
    }

    public static void classify(JSONObject targetSetNode, JSONArray innerContent, JSONArray insertArr, JSONArray updateArr, JSONArray deleteArr) {
        for (int i = 0; i < innerContent.size(); ++i) {
            JSONObject existedObj = (JSONObject) innerContent.get(i);
            JSONObject existedInfos = (JSONObject) existedObj.get(Const.JSON_FIELD_JSON_DATA_INFOS);
            JSONObject insertObj = JSONObject.parseObject(existedObj.toString());
            JSONObject updateObj = JSONObject.parseObject(existedObj.toString());
            JSONObject deleteObj = JSONObject.parseObject(existedObj.toString());
            ((JSONObject) insertObj.get(Const.JSON_FIELD_JSON_DATA_INFOS)).clear();
            ((JSONObject) updateObj.get(Const.JSON_FIELD_JSON_DATA_INFOS)).clear();
            ((JSONObject) deleteObj.get(Const.JSON_FIELD_JSON_DATA_INFOS)).clear();
            for (String key : targetSetNode.keySet()) {
                if (targetSetNode.get(key) == null) {//删除该信息点
                    ((JSONObject) deleteObj.get(Const.JSON_FIELD_JSON_DATA_INFOS)).put(key, targetSetNode.get(key));//删除rel_infos
                } else if (existedInfos.containsKey(key)) {//更新该信息点
                    ((JSONObject) updateObj.get(Const.JSON_FIELD_JSON_DATA_INFOS)).put(key, targetSetNode.get(key));//更新rel_infos
                } else {//插入该信息点
                    ((JSONObject) insertObj.get(Const.JSON_FIELD_JSON_DATA_INFOS)).put(key, targetSetNode.get(key));//插入rel_infos
                }
            }
            insertArr.add(insertObj);
            updateArr.add(updateObj);
            deleteArr.add(deleteObj);
        }
    }

//    public static void batchQueryRelInfos(JSONArray idArr) throws Exception {
//        if (idArr.size() == 0)
//            return;
//        JSONObject re = CommonUtil.combine_query(HBaseTable.rel_infos, idArr);
//        for (int i = 0; i < idArr.size(); ++i) {
//            JSONObject oriObj = (JSONObject) idArr.get(i);
//            combineId(oriObj);
//        }
//        JSONArray outterContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
//        for (int i = 0; i < outterContent.size(); ++i) {
//            JSONArray innerContent = (JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content);
//            JSONObject infosNode = CommonUtil.convertInfoPointsToJSONDataWithId(innerContent);
//            JSONObject oriObj = (JSONObject) idArr.get(i);
//            oriObj.put(Const.JSON_FIELD_JSON_DATA_INFOS, infosNode);
//        }
//    }

    private static void queryRelInfos(JSONArray outterContent) throws Exception {

        JSONArray infoQueryJson = new JSONArray();
        for (int i = 0; i < outterContent.size(); ++i) {
            JSONArray innerContent = (JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content);
            infoQueryJson.addAll(innerContent);
        }
        if (infoQueryJson.size() == 0)
            return;
        JSONObject re = CommonUtil.combine_query(HBaseTable.rel_infos, infoQueryJson);
        JSONArray infoArr = (JSONArray) re.get(Const.JSON_FIELD_Content);
        HashMap<String, JSONObject> infoMap = getRelInfoMap(infoArr);
        for (int i = 0; i < outterContent.size(); ++i) {
            JSONArray innerContent = (JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content);
            for (int j = 0; j < innerContent.size(); ++j) {
                JSONObject item = (JSONObject) innerContent.get(j);
                combineId(item);
                String key = String.join("|", item.get(RelTable.KEY_GRAPH_ID).toString(),
                        item.get(RelTable.KEY_REL_TYPE).toString(), item.get(Const.JSON_FIELD_FROM_ID).toString(), item.get(Const.JSON_FIELD_TO_ID).toString());
                item.put(Const.JSON_FIELD_JSON_DATA_INFOS, infoMap.get(key) == null ? new JSONObject() : infoMap.get(key));
            }
        }
    }

    private static HashMap<String, JSONObject> getRelInfoMap(JSONArray arr) {
        HashMap<String, JSONObject> map = new HashMap<>();
        for (int i = 0; i < arr.size(); ++i) {
            JSONObject infoNode = (JSONObject) arr.get(i);
            combineId(infoNode);
            String key = String.join("|", infoNode.get(RelTable.KEY_GRAPH_ID).toString(),
                    infoNode.get(RelTable.KEY_REL_TYPE).toString(), infoNode.get(Const.JSON_FIELD_FROM_ID).toString(), infoNode.get(Const.JSON_FIELD_TO_ID).toString());
            if (!map.containsKey(key)) {
                map.put(key, new JSONObject());
            }
            JSONObject jsonData = map.get(key);
            jsonData.put(infoNode.get(RelTable.KEY_INFO_ID).toString(), CommonUtil.getValue(infoNode));
        }
        return map;
    }

    public static void combineId(JSONObject json) {
        String from_id = CommonUtil.combineId(json.get(RelTable.KEY_PJ_ID).toString(), json.get(RelTable.KEY_FROM_OBJ_TYPE).toString(), json.get(RelTable.KEY_FROM_OBJ_ID).toString());
        String to_id = CommonUtil.combineId(json.get(RelTable.KEY_PJ_ID).toString(), json.get(RelTable.KEY_TO_OBJ_TYPE).toString(), json.get(RelTable.KEY_TO_OBJ_ID).toString());
        String[] keys = {RelTable.KEY_PJ_ID, RelTable.KEY_FROM_OBJ_TYPE, RelTable.KEY_FROM_OBJ_ID, RelTable.KEY_TO_OBJ_TYPE, RelTable.KEY_TO_OBJ_ID};
        for (String key : keys) {
            json.remove(key);
        }
        json.put(Const.JSON_FIELD_FROM_ID, from_id);
        json.put(Const.JSON_FIELD_TO_ID, to_id);
    }

    //将两层Content变为一层，并进行去重
    public static void flatten(JSONObject json) {
        JSONArray outterContent = (JSONArray) json.get(Const.JSON_FIELD_Content);
        if (outterContent.size() == 0)
            return;
        if (outterContent.size() == 1) {
            JSONObject outterObj = (JSONObject) outterContent.get(0);
            JSONArray innerContent = (JSONArray) outterObj.get(Const.JSON_FIELD_Content);
            json.put(Const.JSON_FIELD_Content, innerContent);
            json.put("Count", (long) innerContent.size());
        } else {
            JSONArray newContent = new JSONArray();
            for (int outterInx = 0; outterInx < outterContent.size(); ++outterInx) {
                JSONObject outterObj = (JSONObject) outterContent.get(outterInx);
                if (!outterObj.containsKey(Const.JSON_FIELD_Content))//只有一层，返回
                    return;
                JSONArray innerContent = (JSONArray) outterObj.get(Const.JSON_FIELD_Content);
                for (int innerInx = 0; innerInx < innerContent.size(); ++innerInx) {
                    if (!newContent.contains(innerContent.get(innerInx))) {
                        newContent.add(innerContent.get(innerInx));
                    }
//                    if (!JSONCompareUtil.Instance().Contain(newContent, innerContent.get(innerInx)))
//                        newContent.add(innerContent.get(innerInx));
                }
            }
            json.put(Const.JSON_FIELD_Content, newContent);
            json.put("Count", (long) newContent.size());
        }
    }


    //data:{"from_id","to_id","graph_id","rel_type","infos"} 选填"time","create_time"
    public static void batchInsert(HBaseTable table, JSONArray dataArr) throws Exception {
        JSONArray queryArr = new JSONArray();
        for (int i = 0; i < dataArr.size(); ++i) {
            JSONObject data = (JSONObject) dataArr.get(i);
            rewriteCriteria(data, Const.JSON_FIELD_FROM_ID);
            rewriteCriteria(data, Const.JSON_FIELD_TO_ID);
            if (table.name().equals(RelTable.REL_TABLE_NAME)) {
                data.remove(Const.JSON_FIELD_JSON_DATA_INFOS);
                queryArr.add(data);
            } else {//信息点
                queryArr.addAll(CommonUtil.processJSONDataToInfoPointsWithId(data));
                //上面函数会把infos中value为null的忽视掉，需要再添加上
                JSONObject infos = (JSONObject) data.get(Const.JSON_FIELD_JSON_DATA_INFOS);
                for (String key : infos.keySet()) {
                    if (infos.get(key) == null) {
                        JSONObject tmp = JSONObject.parseObject(data.toString());
                        tmp.remove(Const.JSON_FIELD_JSON_DATA_INFOS);
                        tmp.put(RelTable.KEY_INFO_ID, key);
                        tmp.put(RelTable.COL_B_VALUE, null);
                        tmp.put(RelTable.COL_L_VALUE, null);
                        tmp.put(RelTable.COL_S_VALUE, null);
                        tmp.put(RelTable.COL_D_VALUE, null);
                        tmp.put(RelTable.COL_JSON_VALUE, null);
                        queryArr.add(tmp);
                    }
                }
            }
        }

        if (queryArr.size() > 0)
            CommonUtil.insert(true, table, queryArr);
//        System.out.println();
    }

    //data:{"from_id","to_id","graph_type","rel_type","infos"} 选填"time","del_time"
    public static void batchUpdate(HBaseTable table, JSONArray array) throws Exception {
        JSONArray dataArr = JSONArray.parseArray(array.toString());
        JSONArray queryArr = new JSONArray();
        JSONArray criteriasNode = new JSONArray();
        JSONArray setsNode = new JSONArray();
        if (table.name().equals(RelTable.INFOS_TABLE_NAME)) {
//            data:{"from_id","to_id","graph_type","rel_type","infos"}
            String[] keySet = {RelTable.COL_S_VALUE, RelTable.COL_B_VALUE, RelTable.COL_D_VALUE, RelTable.COL_L_VALUE, RelTable.COL_JSON_VALUE};
            for (int i = 0; i < dataArr.size(); ++i) {
                JSONObject data = (JSONObject) dataArr.get(i);
                rewriteCriteria(data, Const.JSON_FIELD_FROM_ID);
                rewriteCriteria(data, Const.JSON_FIELD_TO_ID);
                queryArr.addAll(CommonUtil.processJSONDataToInfoPointsWithId(data));
            }
            for (int i = 0; i < queryArr.size(); ++i) {
                JSONObject item = (JSONObject) queryArr.get(i);
                JSONObject set = new JSONObject();
                for (String key : keySet) {
                    set.put(key, item.get(key));
                    item.remove(key);
                }
                criteriasNode.add(item);
                setsNode.add(set);
            }
        } else {
            return;
        }

        if (criteriasNode.size() > 0 && setsNode.size() > 0)
            CommonUtil.update(true, table, criteriasNode, setsNode);
//        System.out.println();
    }


    public static void batchDelete(HBaseTable table, JSONArray array) throws Exception {
        JSONArray dataArr = JSONArray.parseArray(array.toString());
        JSONArray queryArr = new JSONArray();
        for (int i = 0; i < dataArr.size(); ++i) {
            JSONObject item = (JSONObject) dataArr.get(i);
            rewriteCriteria(item, Const.JSON_FIELD_FROM_ID);
            rewriteCriteria(item, Const.JSON_FIELD_TO_ID);
            if (item.containsKey(Const.JSON_FIELD_JSON_DATA_INFOS) && ((JSONObject) item.get(Const.JSON_FIELD_JSON_DATA_INFOS)).keySet().size() != 0) {
                //只删除部分信息
                JSONObject infos = (JSONObject) item.get(Const.JSON_FIELD_JSON_DATA_INFOS);
                item.remove(Const.JSON_FIELD_JSON_DATA_INFOS);
                for (String key : infos.keySet()) {
                    JSONObject idNode = JSONObject.parseObject(item.toString());
                    idNode.put(RelTable.KEY_INFO_ID, key);
                    queryArr.add(idNode);
                }
            } else {//不包含infos，删除全部信息
                item.remove(Const.JSON_FIELD_JSON_DATA_INFOS);
                queryArr.add(item);
            }
        }

        if (queryArr.size() > 0)
            CommonUtil.delete(true, table, queryArr);
//        System.out.println();
    }

    public static String createGraphInstance(String projId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            log.info("createGraphInstance : {}", json.toString());
            String graphType = (String) json.get(GraphInstanceTable.KEY_GRAPH_TYPE);
            String graphID = generateGraphID(projId, graphType);
            json.remove(GraphInstanceTable.KEY_GRAPH_TYPE);
            json.put("graph_id", graphID);
            json.put(GraphInstanceTable.KEY_PJ_ID, projId);
            splitGraphID(json);
            if (json.get(GraphInstanceTable.KEY_INFOS) == null) {
                json.put(GraphInstanceTable.KEY_INFOS, new JSONObject());
            }
            json.put(GraphInstanceTable.KEY_INFOS, json.get(GraphInstanceTable.KEY_INFOS).toString());//将infos变成字符串
            JSONObject result = CommonUtil.insert(false, HBaseTable.graph_instance, json);
            if (result.get(Const.JSON_FIELD_RESULT) == null || !result.get(Const.JSON_FIELD_RESULT).toString().equals("success"))
                return DpUtils.errorJsonMsg("operation failed");
            //1.如果不指定生效时间段，将生效时间设为无穷小到无穷大，即任何时间都生效
            if (!json.containsKey("periods") || json.get("periods") == null)
                json.put("periods", new JSONArray());
            JSONArray periods = (JSONArray) json.get("periods");
            if (periods.size() == 0) {
                JSONObject period = new JSONObject();
                period.put(GraphInstanceTable.KEY_BEGIN_TIME, "19000101000000");
                period.put(GraphInstanceTable.KEY_END_TIME, "29000101000000");
                periods.add(period);
            } else {
                for (int i = 0; i < periods.size(); ++i) {
                    JSONObject period = (JSONObject) periods.get(i);
                    if (period.get(GraphInstanceTable.KEY_BEGIN_TIME) == null)
                        period.put(GraphInstanceTable.KEY_BEGIN_TIME, "19000101000000");
                    if (period.get(GraphInstanceTable.KEY_END_TIME) == null)
                        period.put(GraphInstanceTable.KEY_END_TIME, "29000101000000");
                }
            }
            //1.end
            JSONArray insertObjs = convertPeriodsToArray(json);
            result = CommonUtil.insert(true, HBaseTable.rel_btw_graph_period, insertObjs);
            result.clear();
            result.put(Const.JSON_FIELD_RESULT, "success");
            result.put("ResultMsg", "");
            result.put("graph_id", graphID);
            return result.toString();
        } catch (IdGenException e) {
            return DpUtils.errorJsonMsg("graph_id生成失败");
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }

    }

    public static JSONArray queryGraphInstanceHistory(String pjId, String graphType) throws Exception {
        if (pjId.startsWith(Const.OBJ_TYPE_PROJECT)) {
            pjId = pjId.substring(2);
        }
        JSONObject criteria = new JSONObject();
        criteria.put(GraphInstanceTable.KEY_PJ_ID, pjId);
        criteria.put(GraphInstanceTable.KEY_GRAPH_TYPE, graphType);
        //1.查询出所有图实例id和infos
        JSONObject re = CommonUtil.query(false, HBaseTable.graph_instance, criteria);
        JSONArray instContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
        //1.end
        //2.查询每个图实例的起效时间段
        JSONArray criterias = new JSONArray();
        for (int i = 0; i < instContent.size(); ++i) {
            JSONObject node = (JSONObject) instContent.get(i);
            criteria = new JSONObject();
            criteria.put(GraphInstanceTable.KEY_PJ_ID, node.get(GraphInstanceTable.KEY_PJ_ID));
            criteria.put(GraphInstanceTable.KEY_GRAPH_TYPE, node.get(GraphInstanceTable.KEY_GRAPH_TYPE));
            criteria.put(GraphInstanceTable.KEY_SEQUENCE_ID, node.get(GraphInstanceTable.KEY_SEQUENCE_ID));
            criterias.add(criteria);
        }
        re = CommonUtil.combine_query(HBaseTable.rel_btw_graph_period, criterias);
        JSONArray periodContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
        Map<String, JSONArray> periodMap = new HashMap<>();//graphType+sequenceId->period数组
        for (int i = 0; i < periodContent.size(); ++i) {
            JSONObject obj = (JSONObject) periodContent.get(i);
            String key = obj.get(GraphInstanceTable.KEY_GRAPH_TYPE).toString() + obj.get(GraphInstanceTable.KEY_SEQUENCE_ID).toString();
            if (!periodMap.containsKey(key)) {
                periodMap.put(key, new JSONArray());
            }
            JSONArray periodArr = periodMap.get(key);
            JSONObject period = new JSONObject();
            period.put(GraphInstanceTable.KEY_BEGIN_TIME, obj.get(GraphInstanceTable.KEY_BEGIN_TIME));
            period.put(GraphInstanceTable.KEY_END_TIME, obj.get(GraphInstanceTable.KEY_END_TIME));
            periodArr.add(period);
        }
        //2.end
        //3.整理返回结果
        JSONArray resultArr = new JSONArray();
        for (int i = 0; i < instContent.size(); ++i) {
            JSONObject result = new JSONObject();
            JSONObject obj = (JSONObject) instContent.get(i);
            String graphId = "Gt" + obj.get(GraphInstanceTable.KEY_GRAPH_TYPE).toString() + obj.get(GraphInstanceTable.KEY_SEQUENCE_ID).toString();
            String bound_obj_id = null;
            String objType = (String) obj.get(GraphInstanceTable.KEY_OBJ_TYPE);
            String objId = (String) obj.get(GraphInstanceTable.KEY_OBJ_ID);
            if (objType != null && objId != null) {
                bound_obj_id = CommonUtil.combineId(obj.get(GraphInstanceTable.KEY_PJ_ID).toString(), objType, objId);
            }

            result.put("graph_id", graphId);
            result.put("bound_obj_id", bound_obj_id);
            result.put("infos", JSON.parse(obj.get(GraphInstanceTable.KEY_INFOS).toString()));
            result.put("periods", periodMap.get(obj.get(GraphInstanceTable.KEY_GRAPH_TYPE).toString() + obj.get(GraphInstanceTable.KEY_SEQUENCE_ID).toString()));
            resultArr.add(result);
        }
        return resultArr;
        //3.end

    }


    public static String queryGraphInstance(String projId, String jsonStr, boolean doFlatten) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            log.info("queryGraphInstance : {}", json.toString());
            Boolean isBatchquery = json.containsKey("criterias");
            JSONArray criteriasNode;
            if (isBatchquery) {
                criteriasNode = (JSONArray) json.get("criterias");
            } else {//单条查询按照批量查询来处理
                criteriasNode = new JSONArray();
                criteriasNode.add(json.get("criteria"));
            }
            //改写查询条件
            String currentTime = CommonUtil.getTime();
            for (int i = 0; i < criteriasNode.size(); ++i) {
                JSONObject criteria = (JSONObject) criteriasNode.get(i);
                criteria.put(GraphInstanceTable.KEY_PJ_ID, projId);
                if (!criteria.containsKey("time") || criteria.get("time") == null) {
                    criteria.put("time", currentTime);
                }
                splitGraphID(criteria);
                String time = (String) criteria.get("time");
                criteria.remove("time");
                JSONObject range = new JSONObject();
                range.put("$gte", "0");
                range.put("$lte", time);
                criteria.put(GraphInstanceTable.KEY_BEGIN_TIME, range);
                range = new JSONObject();
                range.put("$gte", time);
                range.put("$lte", "9");
                criteria.put(GraphInstanceTable.KEY_END_TIME, range);
            }


            //查询出某段时间的graph_type,sequence_id,需要再查询出这个graph_id的所有时间段
            JSONObject re = CommonUtil.query(true, HBaseTable.rel_btw_graph_period, criteriasNode);
            //1.查询出所有时间段
            criteriasNode.clear();
            JSONArray outterContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < outterContent.size(); ++i) {
                JSONArray innerContent = (JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content);
                for (int j = 0; j < innerContent.size(); ++j) {
                    JSONObject node = (JSONObject) innerContent.get(j);
                    JSONObject criteria = new JSONObject();
                    criteria.put(GraphInstanceTable.KEY_PJ_ID, node.get(GraphInstanceTable.KEY_PJ_ID));
                    criteria.put(GraphInstanceTable.KEY_GRAPH_TYPE, node.get(GraphInstanceTable.KEY_GRAPH_TYPE));
                    criteria.put(GraphInstanceTable.KEY_SEQUENCE_ID, node.get(GraphInstanceTable.KEY_SEQUENCE_ID));
                    criteriasNode.add(criteria);
                }
            }
            JSONObject reWithAllPeriods = CommonUtil.query(true, HBaseTable.rel_btw_graph_period, criteriasNode);
            //填充到map里，key = project_Id,graph_type,sequence_Id，value为包含periods的JSONObject
            Hashtable<String, JSONObject> idToJSONObjectMap = new Hashtable<>();
            outterContent = (JSONArray) reWithAllPeriods.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < outterContent.size(); ++i) {
                JSONArray innerContent = (JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content);
                JSONObject node = convertTimeToPeriodsWithId(innerContent);
                if (node != null) {
                    String key = String.join(",", node.get(GraphInstanceTable.KEY_PJ_ID).toString()
                            , node.get(GraphInstanceTable.KEY_GRAPH_TYPE).toString(), node.get(GraphInstanceTable.KEY_SEQUENCE_ID).toString());
                    idToJSONObjectMap.put(key, node);
                }
            }
            //1.end
            //2.获取obj_id 和 infos
            criteriasNode.clear();
            for (String key : idToJSONObjectMap.keySet()) {
                String[] ids = key.split(",");
                JSONObject criteria = new JSONObject();
                criteria.put(GraphInstanceTable.KEY_PJ_ID, ids[0]);
                criteria.put(GraphInstanceTable.KEY_GRAPH_TYPE, ids[1]);
                criteria.put(GraphInstanceTable.KEY_SEQUENCE_ID, ids[2]);
                criteriasNode.add(criteria);
            }
            JSONObject reWithInfos = CommonUtil.query(true, HBaseTable.graph_instance, criteriasNode);
            flatten(reWithInfos);
            outterContent = (JSONArray) reWithInfos.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < outterContent.size(); ++i) {
                JSONObject node = (JSONObject) outterContent.get(i);
                String key = String.join(",", node.get(GraphInstanceTable.KEY_PJ_ID).toString()
                        , node.get(GraphInstanceTable.KEY_GRAPH_TYPE).toString(), node.get(GraphInstanceTable.KEY_SEQUENCE_ID).toString());
                JSONObject value = idToJSONObjectMap.get(key);
                String bound_obj_id = null;
                String objType = (String) node.get(GraphInstanceTable.KEY_OBJ_TYPE);
                String objId = (String) node.get(GraphInstanceTable.KEY_OBJ_ID);
                if (objType != null && objId != null) {
                    bound_obj_id = CommonUtil.combineId(node.get(GraphInstanceTable.KEY_PJ_ID).toString(), objType, objId);
                }
                value.put("bound_obj_id", bound_obj_id);
//                if(node.get(GraphInsanceTable.KEY_INFOS)!=null) {
                value.put("infos", JSON.parse(node.get(GraphInstanceTable.KEY_INFOS).toString()));
//                }else{
//                    value.put("infos", null);
//                }
            }
            //2.end
            //将查询到的结果填回最初的re
            outterContent = (JSONArray) re.get(Const.JSON_FIELD_Content);
            for (int i = outterContent.size() - 1; i >= 0; --i) {
                JSONArray innerContent = (JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content);
                for (int j = innerContent.size() - 1; j >= 0; --j) {
                    JSONObject node = (JSONObject) innerContent.get(j);
                    String key = String.join(",", node.get(GraphInstanceTable.KEY_PJ_ID).toString()
                            , node.get(GraphInstanceTable.KEY_GRAPH_TYPE).toString(), node.get(GraphInstanceTable.KEY_SEQUENCE_ID).toString());
                    innerContent.remove(j);
                    if (idToJSONObjectMap.containsKey(key)) {
                        combineGraphID(idToJSONObjectMap.get(key));
                        innerContent.add(idToJSONObjectMap.get(key));
                    }
                }
                ((JSONObject) outterContent.get(i)).put("Count", (long) innerContent.size());
            }
            if (!isBatchquery) {//单条查询将结果平铺
                flatten(re);
            } else if (doFlatten) {
                flatten(re);
            }
            return re.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }

    }

    public static String updateGraphInstance(String projId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            log.info("updateGraphInstance : {}", json.toString());
            if (!json.containsKey("criterias")) {//单条操作按照批量来处理
                JSONArray criteriasNode = new JSONArray();
                JSONArray setsNode = new JSONArray();
                criteriasNode.add(json.get("criteria"));
                setsNode.add(json.get("set"));
                json.remove("criteria");
                json.remove("set");
                json.put("criterias", criteriasNode);
                json.put("sets", setsNode);
            }
            JSONArray criterias = (JSONArray) json.get("criterias");
            CommonUtil.addField(criterias, GraphInstanceTable.KEY_PJ_ID, projId);
            JSONArray sets = (JSONArray) json.get("sets");
            for (int i = 0; i < criterias.size(); ++i) {
                splitGraphID((JSONObject) criterias.get(i));
            }
            JSONArray insertArray = new JSONArray();//插入新的时间段-图实例关系
            JSONArray deleteArray = new JSONArray();//删除时间段-图实例关系

            JSONArray updateObjCriteria = new JSONArray();//更新rel_btw_graph_period中的obj
            JSONArray updateObjSet = new JSONArray();

            Hashtable<JSONObject, JSONObject> criteriaSetMap = new Hashtable<>();//用来更新graph_instance表
            JSONArray updateInfosCriteria = new JSONArray();//更新graph_instance中的obj和infos
            JSONArray updateInfosSet = new JSONArray();

            JSONObject existedData = CommonUtil.query(true, HBaseTable.graph_instance, criterias);
            JSONArray outterContent = (JSONArray) existedData.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < outterContent.size(); ++i) {
                JSONObject item = (JSONObject) outterContent.get(i);
                if ((item.getLongValue("Count")) == 0) {//所要更新的数据在数据库中不存在
                    continue;
                }
                //数据库中的数据,包含graph_id和obj_id和infos
                item = (JSONObject) ((JSONArray) ((JSONObject) outterContent.get(i)).get(Const.JSON_FIELD_Content)).get(0);
                item.put(Const.JSON_FIELD_JSON_DATA_INFOS, JSON.parse(item.get(Const.JSON_FIELD_JSON_DATA_INFOS).toString()));//将infos变成JSONObject
                JSONObject targetCriteria = (JSONObject) criterias.get(i);
                JSONObject targetSet = (JSONObject) sets.get(i);
                if (targetSet.containsKey("periods")) {
                    JSONObject deleteNode = JSONObject.parseObject(targetCriteria.toString());
                    deleteArray.add(deleteNode);
                    JSONObject insertNode = JSONObject.parseObject(item.toString());
                    insertNode.put("periods", targetSet.get("periods"));
                    insertArray.addAll(convertPeriodsToArray(insertNode));
                }
                if (targetSet.containsKey("infos")) {
                    JSONObject existedInfos = (JSONObject) item.get("infos");
                    for (String key : ((JSONObject) targetSet.get("infos")).keySet()) {
                        if (((JSONObject) targetSet.get("infos")).get(key) == null) {
                            existedInfos.remove(key);
                        } else {
                            existedInfos.put(key, ((JSONObject) targetSet.get("infos")).get(key));
                        }
                    }
                    if (!criteriaSetMap.containsKey(targetCriteria)) {
                        criteriaSetMap.put(targetCriteria, new JSONObject());
                    }
                    JSONObject setNode = criteriaSetMap.get(targetCriteria);
                    setNode.put("infos", existedInfos.toString());
                }
                if (targetSet.containsKey("bound_obj_id")) {
                    //1.更新graph_instance用
                    if (!criteriaSetMap.containsKey(targetCriteria)) {
                        criteriaSetMap.put(targetCriteria, new JSONObject());
                    }
                    JSONObject setNode = criteriaSetMap.get(targetCriteria);
                    setNode.put("bound_obj_id", targetSet.get("bound_obj_id"));
                    splitGraphID(setNode);
                    //1.end
                    updateObjCriteria.add(targetCriteria);
                    JSONObject objSetNode = new JSONObject();
                    objSetNode.put("bound_obj_id", targetSet.get("bound_obj_id"));
                    splitGraphID(objSetNode);
                    updateObjSet.add(objSetNode);
                }

            }
            for (Map.Entry en : criteriaSetMap.entrySet()) {
                updateInfosCriteria.add(en.getKey());
                updateInfosSet.add(en.getValue());
            }
            CommonUtil.delete(true, HBaseTable.rel_btw_graph_period, deleteArray);
            CommonUtil.insert(true, HBaseTable.rel_btw_graph_period, insertArray);
            CommonUtil.update(true, HBaseTable.rel_btw_graph_period, updateObjCriteria, updateObjSet);
            CommonUtil.update(true, HBaseTable.graph_instance, updateInfosCriteria, updateInfosSet);

            return DpUtils.successJsonMsg("");
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }

    }

    public static String deleteGraphInstance(String pjId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            log.info("deleteGraphInstance : {}", json.toString());
            if (json.containsKey("criteria")) {//单条操作按批量来处理
                JSONArray criterisNode = new JSONArray();
                criterisNode.add(json.get("criteria"));
                json.put("criterias", criterisNode);
                json.remove("criteria");
            }
            JSONArray criterias = (JSONArray) json.get("criterias");
            CommonUtil.addField(criterias, GraphInstanceTable.KEY_PJ_ID, pjId);
            JSONArray criteraisWithGraphID = JSONArray.parseArray(criterias.toString());
            //提取id，发广播
            Set<String> idSet = new HashSet<>();
            for (int i = 0; i < criterias.size(); i++) {
                JSONObject item = criterias.getJSONObject(i);
                if (item.containsKey("graph_id")) {
                    idSet.add(item.getString("graph_id"));
                }
            }
            for (int i = 0; i < criterias.size(); ++i) {
                splitGraphID((JSONObject) criterias.get(i));
            }

            CommonUtil.delete(true, HBaseTable.graph_instance, criterias);
            CommonUtil.delete(true, HBaseTable.rel_btw_graph_period, criterias);
            CommonUtil.delete(true, HBaseTable.rel_btw_objs, criteraisWithGraphID);
            CommonUtil.delete(true, HBaseTable.rel_infos, criteraisWithGraphID);
            //发广播
            idSet.forEach(id ->
                    MessageHandler.publish(String.format("{\"type\":14,\"projectId\":\"%s\",\"graphId\":\"%s\",\"description\":\"\"}", CommonMethods.getProject(pjId, true), id))
            );
            return DpUtils.successJsonMsg("");
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    public static JSONArray convertPeriodsToArray(JSONObject json) {
        JSONArray insertObjs = new JSONArray();
        JSONArray periods = (JSONArray) json.get("periods");
        json.remove("periods");
        for (int i = 0; i < periods.size(); ++i) {
            JSONObject period = (JSONObject) periods.get(i);
            JSONObject insertObj = JSONObject.parseObject(json.toString());
            insertObj.put(GraphInstanceTable.KEY_BEGIN_TIME, period.get(GraphInstanceTable.KEY_BEGIN_TIME));
            insertObj.put(GraphInstanceTable.KEY_END_TIME, period.get(GraphInstanceTable.KEY_END_TIME));
            insertObjs.add(insertObj);
        }
        return insertObjs;
    }

    public static JSONObject convertTimeToPeriodsWithId(JSONArray jsonArray) {
        if (jsonArray.size() == 0) return null;
        JSONObject json = new JSONObject();
        json.put(GraphInstanceTable.KEY_PJ_ID, ((JSONObject) jsonArray.get(0)).get(GraphInstanceTable.KEY_PJ_ID));
        json.put(GraphInstanceTable.KEY_GRAPH_TYPE, ((JSONObject) jsonArray.get(0)).get(GraphInstanceTable.KEY_GRAPH_TYPE));
        json.put(GraphInstanceTable.KEY_SEQUENCE_ID, ((JSONObject) jsonArray.get(0)).get(GraphInstanceTable.KEY_SEQUENCE_ID));
        JSONArray periods = new JSONArray();
        for (int i = 0; i < jsonArray.size(); ++i) {
            JSONObject period = new JSONObject();
            period.put(GraphInstanceTable.KEY_BEGIN_TIME, ((JSONObject) jsonArray.get(i)).get(GraphInstanceTable.KEY_BEGIN_TIME));
            period.put(GraphInstanceTable.KEY_END_TIME, ((JSONObject) jsonArray.get(i)).get(GraphInstanceTable.KEY_END_TIME));
            periods.add(period);
        }
        json.put("periods", periods);
        return json;
    }

    public static void splitGraphID(JSONObject json) throws Exception {
        if (json.containsKey("graph_id")) {
            String graphID = (String) json.get("graph_id");
            if (graphID.length() < 5) {
                throw new Exception("illegal graph_id");
            }
            String graphType = graphID.substring(2, graphID.length() - 3);
            String sequenceID = graphID.substring(graphID.length() - 3);
            json.put(GraphInstanceTable.KEY_GRAPH_TYPE, graphType);
            json.put(GraphInstanceTable.KEY_SEQUENCE_ID, sequenceID);
            json.remove("graph_id");
        }

        if (json.containsKey("bound_obj_id"))
            rewriteCriteria(json, "bound_obj_id");

    }

    public static void combineGraphID(JSONObject criteria) {
//        String projectId = (String) criteria.get(GraphInsanceTable.KEY_PJ_ID);
        if (criteria.containsKey(GraphInstanceTable.KEY_GRAPH_TYPE) && criteria.containsKey(GraphInstanceTable.KEY_SEQUENCE_ID)) {
            String graphType = (String) criteria.get(GraphInstanceTable.KEY_GRAPH_TYPE);
            String sequenceId = (String) criteria.get(GraphInstanceTable.KEY_SEQUENCE_ID);
            String graphId = String.join("", "Gt", graphType, sequenceId);
            criteria.remove(GraphInstanceTable.KEY_PJ_ID);
            criteria.remove(GraphInstanceTable.KEY_GRAPH_TYPE);
            criteria.remove(GraphInstanceTable.KEY_SEQUENCE_ID);
            criteria.put("graph_id", graphId);
        }
    }

    public static String generateGraphID(String projId, String graphType) throws IdGenException {
        JSONObject re = null;
        try {
            JSONObject criteria = new JSONObject();
            criteria.put(GraphInstanceTable.KEY_PJ_ID, projId);
            criteria.put(GraphInstanceTable.KEY_GRAPH_TYPE, graphType);
            re = CommonUtil.query(false, HBaseTable.graph_instance, criteria);
            String countStr = DecimalTONBigit.toString((int) (re.getLongValue("Count") + 1));
            String formatStr = "%1$3s";
            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(GraphInstanceTable.KEY_SEQUENCE_ID))).endsWith(genId)) {
                    countStr = DecimalTONBigit.toString(DecimalTONBigit.toInt(countStr) + 1);
                    genId = String.format(formatStr, countStr).replace(' ', '0');
                    i = -1;
                }
            }
            return "Gt" + graphType + genId;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IdGenException();
        }

    }

    public static String validateExistence(String pjId, String jsonStr) {

        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            if (!json.containsKey("criterias")) {//单条操作按批量进行处理
                JSONArray criterias = new JSONArray();
                criterias.add(JSONObject.parseObject(json.toString()));
                json.clear();
                json.put("criterias", criterias);
            }
            JSONArray criterias = (JSONArray) json.get("criterias");

            JSONArray idArray = new JSONArray();
            JSONArray graphInstanceArray = new JSONArray();
            JSONArray graphRelPairsArray = new JSONArray();
            for (int i = 0; i < criterias.size(); ++i) {
                JSONObject criteria = (JSONObject) criterias.get(i);
                String[] keys = {"graph_id", "rel_type", "from_id", "to_id"};
                for (String key : keys) {
                    if (criteria.get(key) == null || criteria.get(key).toString().length() == 0)
                        return DpUtils.errorJsonMsg("missing key : " + key);
                }
                JSONObject obj = new JSONObject();
                obj.put("id", criteria.get(Const.JSON_FIELD_FROM_ID));
                obj.put(ObjectTable.COL_VALID, true);
                rewriteCriteria(obj, "id");
                idArray.add(obj);

                obj = new JSONObject();
                obj.put("id", criteria.get(Const.JSON_FIELD_TO_ID));
                obj.put(ObjectTable.COL_VALID, true);
                rewriteCriteria(obj, "id");
                idArray.add(obj);

                String graph_id = (String) criteria.get(RelTable.KEY_GRAPH_ID);
                if (graph_id.length() < 5) {
                    throw new Exception("illegal graph_id : " + graph_id);
                }
                obj = new JSONObject();
                obj.put(Const.TABLE_KEY_NAME_PROJECT_ID, pjId);
                obj.put("graph_id", graph_id);
                splitGraphID(obj);
                graphInstanceArray.add(obj);

                String graph_type = graph_id.substring(2, graph_id.length() - 3);
                obj = new JSONObject();
                obj.put(GraphInstanceTable.KEY_GRAPH_TYPE, graph_type);
                obj.put(RelDefTable.KEY_REL_TYPE, criteria.get(RelDefTable.KEY_REL_TYPE));
                obj.put(RelTable.KEY_PJ_ID, pjId);
                graphRelPairsArray.add(obj);
            }

            JSONObject re;
            JSONArray content;
            //检验物理实体是否存在
            HashSet<String> inexistentIdSet = new HashSet<>();
            re = CommonUtil.getCount(true, HBaseTable.objects, idArray);
            content = (JSONArray) re.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < content.size(); ++i) {
                if (((JSONObject) content.get(i)).getLongValue("Count") == 0) {
                    JSONObject idNode = (JSONObject) idArray.get(i);
                    String id = CommonUtil.combineId((String) idNode.get(ObjectTable.KEY_PJ_ID), (String) idNode.get(ObjectTable.KEY_OBJ_TYPE), (String) idNode.get(ObjectTable.KEY_OBJ_ID));
                    inexistentIdSet.add(id);
                }
            }
            if (inexistentIdSet.size() != 0) {
                return DpUtils.errorJsonMsg("请先创建物理对象 ：" + inexistentIdSet.toString());
            }
            //检查图实例是否存在
            HashSet<String> inexistentGraphInstSet = new HashSet<>();
            re = CommonUtil.getCount(true, HBaseTable.graph_instance, graphInstanceArray);
            content = (JSONArray) re.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < content.size(); ++i) {
                if (((JSONObject) content.get(i)).getLongValue("Count") == 0) {
                    JSONObject graphInstNode = (JSONObject) graphInstanceArray.get(i);
                    combineGraphID(graphInstNode);
                    inexistentGraphInstSet.add((String) graphInstNode.get(RelTable.KEY_GRAPH_ID));
                }
            }
            if (inexistentGraphInstSet.size() != 0) {
                return DpUtils.errorJsonMsg("请先创建图实例 ：" + inexistentGraphInstSet.toString());
            }
            //检查关系类型是否定义
            HashSet<String> inexistentRelSet = new HashSet<>();

            re = CommonUtil.query(true, HBaseTable.rel_type_def, graphRelPairsArray);
            flatten(re);
            content = (JSONArray) re.get(Const.JSON_FIELD_Content);
            HashSet<String> relSet = new HashSet<>();
            for (int i = 0; i < content.size(); ++i) {
                String graph = (String) ((JSONObject) content.get(i)).get(RelDefTable.KEY_GRAPH_TYPE);
                String rel = (String) ((JSONObject) content.get(i)).get(RelDefTable.KEY_REL_TYPE);
                relSet.add(graph + "," + rel);
            }
            relSet.addAll(RelStaticInfo.globalGraphRelMap.keySet());
            for (int i = 0; i < graphRelPairsArray.size(); ++i) {
                String graphType = (String) ((JSONObject) graphRelPairsArray.get(i)).get(RelDefTable.KEY_GRAPH_TYPE);
                String relType = (String) ((JSONObject) graphRelPairsArray.get(i)).get(RelDefTable.KEY_REL_TYPE);
                if (!relSet.contains(graphType + "," + relType)) {
                    inexistentRelSet.add(graphType + " : " + relType);
                }
            }
            if (inexistentRelSet.size() != 0) {
                return DpUtils.errorJsonMsg("请先定义关系类型 ：" + inexistentRelSet.toString());
            }
            //通过校验
            return null;
        } catch (Exception e) {
            return DpUtils.errorJsonMsg(e.getMessage());
        }
    }

    //pjId为去掉“Pj”的格式
    public static ArrayList<String> getEqUnderSys(String pjId, String fromId, String graphId, String relType) throws Exception {
        ArrayList<String> result = new ArrayList<>();
        JSONObject criteria = new JSONObject();
        criteria.put(RelTable.KEY_PJ_ID, pjId);
        criteria.put(Const.JSON_FIELD_FROM_ID, fromId);
        criteria.put(RelTable.KEY_GRAPH_ID, graphId);
        criteria.put(RelTable.KEY_REL_TYPE, relType);
        rewriteCriteria(criteria, Const.JSON_FIELD_FROM_ID);

        JSONObject re = CommonUtil.query(false, HBaseTable.rel_btw_objs, criteria);
        JSONArray content = (JSONArray) re.get(Const.JSON_FIELD_Content);
        for (int i = 0; i < content.size(); ++i) {
            JSONObject obj = (JSONObject) content.get(i);
            combineId(obj);
            result.add((String) obj.get(Const.JSON_FIELD_TO_ID));
        }
        return result;

    }


    /**
     * @param criteriaNode 与CommonUtil中不同的是，此方法将对资产id进行改写时，obj_type为Pe
     * @param key
     * @throws Exception
     */
    public static void rewriteCriteria(JSONObject criteriaNode, String key) throws Exception {
        if (criteriaNode.get(key) == null)
            return;
        String id = criteriaNode.get(key).toString().trim();
        String project_id = null;
        String obj_type = null;
        String obj_id = null;
        if (id.startsWith(Const.OBJ_TYPE_PROJECT)) {
            project_id = id.substring(2, 12);
            obj_type = Const.OBJ_TYPE_PROJECT;
//        } else if (id.startsWith(Const.OBJ_TYPE_EQUIPMENT)) {
//            project_id = id.substring(2, 12);
//            obj_type = id.substring(0, 2) + id.substring(15, id.length() - 3);
//            obj_id = id.substring(12, 15) + id.substring(id.length() - 3);
//        } else if (id.startsWith(Const.OBJ_TYPE_SYSTEM)) {
//            project_id = id.substring(2, 12);
//            obj_type = id.substring(0, 2) + id.substring(15, id.length() - 3);
//            obj_id = id.substring(12, 15) + id.substring(id.length() - 3);
//        } else if (id.startsWith(Const.OBJ_TYPE_EQUIPMENT_COMPONENT)) {
//            project_id = id.substring(2, 12);
//            StringBuilder sb = new StringBuilder();
//            obj_type = sb.append(id.substring(0, 2)).append(id.substring(15, 21)).append(id.substring(24, 26)).toString();
//            sb = new StringBuilder();
//            obj_id = sb.append(id.substring(12, 15)).append(id.substring(21, 24)).append(id.substring(26)).toString();
        } else if (id.startsWith(Const.OBJ_TYPE_VO)) {
            project_id = id.substring(4, 14);
            obj_type = id.substring(0, 4);
            obj_id = id.substring(14);
        } else if (id.startsWith(Const.OBJ_TYPE_PROPERTY)) {//Pe + uuid
            obj_type = Const.OBJ_TYPE_PROPERTY;
            obj_id = id.substring(2);
        } else {
            project_id = id.substring(2, 12);
            obj_type = id.substring(0, 2);
            obj_id = id.substring(12);
        }
        criteriaNode.remove(key);
        criteriaNode.put(ObjectTable.KEY_PJ_ID, project_id);
        if (key.equals(Const.JSON_FIELD_FROM_ID)) {
            criteriaNode.put(RelTable.KEY_FROM_OBJ_TYPE, obj_type);
            criteriaNode.put(RelTable.KEY_FROM_OBJ_ID, obj_id);
        } else if (key.equals(Const.JSON_FIELD_TO_ID)) {
            criteriaNode.put(RelTable.KEY_TO_OBJ_TYPE, obj_type);
            criteriaNode.put(RelTable.KEY_TO_OBJ_ID, obj_id);
        } else {
            criteriaNode.put(ObjectTable.KEY_OBJ_TYPE, obj_type);
            criteriaNode.put(ObjectTable.KEY_OBJ_ID, obj_id);
        }
    }

//    public static String getPropertyGraphTypeStr(String type) {
//        if (type == null || type.length() < 2)
//            return null;
//        String t = type.substring(0, 2);
//        switch (t) {
//            case "Bd":
//            case "Fl":
//                return PropertyGraphEnum.Subset.name();
//            case "Eq":
//            case "Ec":
//                return PropertyGraphEnum.Pe2Eq.name();
//        }
//        return null;
//    }

    /**
     * @param pjId
     * @param graphType
     * @param time               某个时间起作用的图实例
     * @param createWhenNotExist 不存在图实例时，是否创建
     * @return 图实例id。如果不存在图实例，且不进行创建，返回null
     * @throws Exception
     */
    public static String getGraphInstance(String pjId, String graphType, String time, boolean createWhenNotExist) throws Exception {

        if (pjId.startsWith(Const.OBJ_TYPE_PROJECT)) {
            pjId = pjId.substring(2);
        }
        //1.查询图实例
        JSONObject criteria = new JSONObject();
        criteria.put(GraphInstanceTable.KEY_PJ_ID, pjId);
        criteria.put(GraphInstanceTable.KEY_GRAPH_TYPE, graphType);
        JSONObject range = new JSONObject();
        range.put("$lte", time);
//        range.put("$gte","00000000000000");
        criteria.put(GraphInstanceTable.KEY_BEGIN_TIME, range);
        range = new JSONObject();
        range.put("$gte", time);
//        range.put("$lte","99999999999999");
        criteria.put(GraphInstanceTable.KEY_END_TIME, range);
        JSONObject re = CommonUtil.query(false, HBaseTable.rel_btw_graph_period, criteria);
        if (!re.get(Const.JSON_FIELD_RESULT).toString().equals("success")) {
            throw new Exception("查询图实例出错");
        }
        //1.end
        //2.如果某一时间起作用的图实例存在多张，选取sequencyId小的
        JSONArray content = (JSONArray) re.get(Const.JSON_FIELD_Content);
        String sequencyId = null;
        for (int i = 0; i < content.size(); ++i) {
            String tempSequencyId = ((JSONObject) content.get(i)).get(GraphInstanceTable.KEY_SEQUENCE_ID).toString();
            if (sequencyId == null) {
                sequencyId = tempSequencyId;
            } else if (compareId(sequencyId, tempSequencyId) > 0) {
                sequencyId = tempSequencyId;
            }
        }
        String graphId = null;
        if (sequencyId != null) {
            graphId = Const.OBJ_TYPE_GRAPH + graphType + sequencyId;
        }
        //2.end
        if (!createWhenNotExist) {//不进行创建，直接返回图实例id，可能为null
            return graphId;
        } else if (graphId == null && createWhenNotExist) {
            graphId = createGraph(pjId, graphType, time);
        }
        return graphId;
    }

    /**
     * @param id1 数据平台的顺序id，62进制
     * @param id2
     * @return negative, if id1 < id2; positive, if id1 > id2; 0, if id1 == id2
     */
    public static int compareId(String id1, String id2) {
        int num1 = DecimalTONBigit.toInt(id1);
        int num2 = DecimalTONBigit.toInt(id2);
        return num1 - num2;
    }

    public static JSONArray getEqBySysInstance(String sysId, Set<String> types) {
        Hashtable<String, Set<String>> typeToIdMap = new Hashtable<>();
        JSONArray typeCriterias = new JSONArray();
        JSONArray result = new JSONArray();
        String pjId = sysId.substring(2, 12);
        try {
            String graphId = getGraphInstance(pjId, "SystemEquip", CommonUtil.getTime(), false);
            if (graphId == null) {
                return result;
            }
            //1.查询该系统下所有的设备id
            JSONObject queryNode = new JSONObject();
            queryNode.put(RelTable.KEY_PJ_ID, pjId);
            queryNode.put(RelTable.KEY_GRAPH_ID, graphId);
            queryNode.put(RelTable.KEY_REL_TYPE, "1");
            queryNode.put(RelTable.KEY_FROM_OBJ_TYPE, sysId.substring(0, 2));
            queryNode.put(RelTable.KEY_FROM_OBJ_ID, sysId.substring(12));
            JSONArray queryArr = new JSONArray();
            queryArr.add(queryNode);
            if (queryArr.size() == 0)
                return result;
            JSONObject re = CommonUtil.combine_query(HBaseTable.rel_btw_objs, queryArr);//combine_select 比 select 要快点
            //1.end
            //2.查询所有设备id的具体设备类型
            JSONArray content = (JSONArray) re.get(Const.JSON_FIELD_Content);
            if (content.size() == 0)//该系统下没有任何设备
                return result;
            for (int i = 0; i < content.size(); ++i) {
                JSONObject obj = (JSONObject) content.get(i);
                JSONObject typeCriteria = new JSONObject();
                typeCriteria.put(ObjectTable.KEY_PJ_ID, pjId);
                typeCriteria.put(ObjectTable.KEY_OBJ_TYPE, obj.get(RelTable.KEY_TO_OBJ_TYPE));
                typeCriteria.put(ObjectTable.KEY_OBJ_ID, obj.get(RelTable.KEY_TO_OBJ_ID));
                typeCriterias.add(typeCriteria);
            }
            re = CommonUtil.combine_query(HBaseTable.objects, typeCriterias);
            //2.end
            //3.将所有设备按具体类型放到map里
            content = (JSONArray) re.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < content.size(); ++i) {
                JSONObject obj = (JSONObject) content.get(i);
                String eqId = CommonUtil.combineId(pjId, obj.get(ObjectTable.KEY_OBJ_TYPE).toString(), obj.get(ObjectTable.KEY_OBJ_ID).toString());
                String deltailType = Strings.nullToEmpty((String) obj.get(ObjectTable.COL_SUBTYPE));
                if (!typeToIdMap.containsKey(deltailType)) {
                    typeToIdMap.put(deltailType, new HashSet<>());
                }
                Set<String> eqSet = typeToIdMap.get(deltailType);
                eqSet.add(eqId);
            }
            //3.end
            for (String type : types) {
                if (typeToIdMap.get(type) == null)
                    continue;
                Set<String> eqSet = typeToIdMap.get(type);
                for (String eqId : eqSet) {
                    result.add(eqId);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @param graphid 图id
     * @param relType 关系类型
     * @param id      对象Aid
     * @param objType 对象B的类型
     * @param isFrom  对象A是否是from_id
     */
    public static JSONArray queryRelByType(String pjId, String graphid, String relType, String id, String objType, boolean isFrom) throws Exception {
        JSONObject criteria = new JSONObject();
        criteria.put(RelTable.KEY_GRAPH_ID, graphid);
        criteria.put(RelTable.KEY_REL_TYPE, relType);
        if (isFrom) {
            criteria.put(Const.JSON_FIELD_FROM_ID, id);
            rewriteCriteria(criteria, Const.JSON_FIELD_FROM_ID);
        } else {
            criteria.put(Const.JSON_FIELD_TO_ID, id);
            rewriteCriteria(criteria, Const.JSON_FIELD_TO_ID);
        }
        JSONObject re = CommonUtil.query(false, HBaseTable.rel_btw_objs, criteria);
        JSONArray content = (JSONArray) re.get(Const.JSON_FIELD_Content);
        for (int i = 0; i < content.size(); ++i) {
            combineId((JSONObject) content.get(i));
        }
        filterQueryRelByType(pjId, content, objType, isFrom);
        return content;
    }

    private static void filterQueryRelByType(String pjId, JSONArray content, String objType, boolean isFrom) {
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        if (eqStaticInfo.getSysSet().contains(objType) || eqStaticInfo.getEqSet().contains(objType) || eqStaticInfo.getEcSet().contains(objType) || eqStaticInfo.getFamilySet().contains(objType)) {
            //如果是具体的系统、设备、部件、种族类型，需要再去查询objects表
            Set<String> idSet = new HashSet<>();
            for (int i = 0; i < content.size(); ++i) {
                JSONObject node = (JSONObject) content.get(i);
                if (isFrom) {
                    idSet.add(node.get(Const.JSON_FIELD_TO_ID).toString());
                } else {
                    idSet.add(node.get(Const.JSON_FIELD_FROM_ID).toString());
                }
            }
            Map<String, String> subtypeMap = getObjSubtype(idSet);
            for (int i = content.size() - 1; i >= 0; --i) {
                JSONObject node = (JSONObject) content.get(i);
                String targetId = isFrom ? node.get(Const.JSON_FIELD_TO_ID).toString() : node.get(Const.JSON_FIELD_FROM_ID).toString();
                if (!objType.equals(subtypeMap.get(targetId))) {
                    //如果要查询的类型与id对应的类型不相符，删除
                    content.remove(i);
                }
            }
        } else {
            //基本类型，不再去查询objects表中的subtype
            for (int i = content.size() - 1; i >= 0; --i) {
                JSONObject node = (JSONObject) content.get(i);
                String targetId = isFrom ? node.get(Const.JSON_FIELD_TO_ID).toString() : node.get(Const.JSON_FIELD_FROM_ID).toString();
                if (!targetId.startsWith(objType)) {
                    //如果要查询的类型与id对应的类型不相符，删除
                    content.remove(i);
                }
            }
        }
    }

    private static Map<String, String> getObjSubtype(Set<String> idSet) {
        Map<String, String> subtypeMap = new HashMap<>();
        JSONArray criterias = new JSONArray();
        for (String id : idSet) {
            JSONObject node = new JSONObject();
            node.put("id", id);
            try {
                rewriteCriteria(node, "id");
                criterias.add(node);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            JSONObject re = CommonUtil.combine_query(HBaseTable.objects, criterias);
            JSONArray content = (JSONArray) re.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < content.size(); ++i) {
                JSONObject obj = (JSONObject) content.get(i);
                String objId = CommonUtil.combineId((String) obj.get(ObjectTable.KEY_PJ_ID), (String) obj.get(ObjectTable.KEY_OBJ_TYPE), (String) obj.get(ObjectTable.KEY_OBJ_ID));
                subtypeMap.put(objId, Strings.nullToEmpty((String) obj.get(ObjectTable.COL_SUBTYPE)));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return subtypeMap;
    }

    /**
     * 获取图类型下当前有效且序号最小的图id
     *
     * @param pjId      不带Pj的项目id
     * @param graphType 图类型
     * @return 正常返回图id, 错误情况返回null, 没有图id返回空字符串
     */
    public static String getFirstValidGraphInstanceByGraphType(String pjId, String graphType) {
        JSONObject obj = new JSONObject();
        JSONObject criteria = new JSONObject();
        criteria.put("graph_type", graphType);
        criteria.put("time", CommonUtil.getTime());
        obj.put("criteria", criteria);
        String json = queryGraphInstance(CommonMethods.getProject(pjId, false), obj.toString(), true);
        JSONObject result = JSONObject.parseObject(json);
        if (!result.get("Result").equals("success")) {
            return null;
        }
        JSONArray content = (JSONArray) result.get("Content");
        for (int i = 0; i < content.size(); ++i) {
            JSONObject first = (JSONObject) content.get(i);
            return first.get("graph_id").toString();
        }
        return "";
    }

    public static JSONArray queryRelationByGraphIdRelType(String projectId, String graphId, String relType, String fromId, String toId) {
        JSONObject obj = new JSONObject();
        obj.put(RelTable.KEY_PJ_ID, CommonMethods.getProject(projectId, false));
        obj.put(RelTable.KEY_GRAPH_ID, graphId);
        if (relType != null)
            obj.put(RelTable.KEY_REL_TYPE, relType);
        if (fromId != null && fromId.length() > 0) {
            JSONObject fromIdObj = new JSONObject();
            fromIdObj.put("id", fromId);
            try {
                CommonUtil.rewriteObjectTableCriteria(CommonMethods.getProject(projectId, false), fromIdObj, "id", true);
                obj.put(RelTable.KEY_FROM_OBJ_TYPE, fromIdObj.getString(ObjectTable.KEY_OBJ_TYPE));
                obj.put(RelTable.KEY_FROM_OBJ_ID, fromIdObj.getString(ObjectTable.KEY_OBJ_ID));
            } catch (Exception e) {
            }
        }
        if (toId != null && toId.length() > 0) {
            JSONObject toIdObj = new JSONObject();
            toIdObj.put("id", toId);
            try {
                CommonUtil.rewriteObjectTableCriteria(CommonMethods.getProject(projectId, false), toIdObj, "id", true);
                obj.put(RelTable.KEY_TO_OBJ_TYPE, toIdObj.getString(ObjectTable.KEY_OBJ_TYPE));
                obj.put(RelTable.KEY_TO_OBJ_ID, toIdObj.getString(ObjectTable.KEY_OBJ_ID));
            } catch (Exception e) {
            }
        }
        JSONArray criterias = new JSONArray();
        criterias.add(obj);
        try {
            JSONObject result = null;
            if (relType != null)
                result = CommonUtil.combine_query(HBaseTable.rel_btw_objs, criterias);
            else
                result = CommonUtil.query(false, HBaseTable.rel_btw_objs, obj);
            JSONArray content = result.getJSONArray("Content");
            for (int i = 0; i < content.size(); ++i)
                RelationUtil.combineId(content.getJSONObject(i));
            return content;
        } catch (Exception e) {
            return null;
        }
    }

    public static JSONArray subsetQuery(String projectId, String id, String graphId, String relType, Set<String> typeSet, CommonQueryCriteria cqc, String fromId, String toId, EqStaticInfo eqStaticInfo) {
//        JSONObject object = new JSONObject();
//        JSONObject criteria = new JSONObject();
//        criteria.put("graph_id", graphId);
//        criteria.put("rel_type", relType);
//        object.put("criteria", criteria);
        JSONArray objectInGraph = RelationUtil.queryRelationByGraphIdRelType(projectId, graphId, relType, fromId, toId);
        if (objectInGraph == null || objectInGraph.size() == 0)
            return new JSONArray();

        if (!id.startsWith("Pj")) {
            ArrayList<String> idSubsetArray = SubsetUtil.getSubset(projectId, id, typeSet, cqc, eqStaticInfo);
            Set<String> idSet = new HashSet<>(idSubsetArray);
            for (int i = objectInGraph.size() - 1; i > -1; --i) {
                JSONObject singleRel = (JSONObject) objectInGraph.get(i);
                String tmpFromId = (String) singleRel.get("from_id");
                String tmpToId = (String) singleRel.get("to_id");
                if (tmpFromId != null && tmpToId != null && !idSet.contains(tmpFromId) && !idSet.contains(tmpToId))
                    objectInGraph.remove(i);
            }
        }
        return objectInGraph;
    }

    public static void getGraphId(String projectId, List<RelationCriteria> include, List<RelationCriteria> exclude) throws Exception {
        if (include.size() == 0 && exclude.size() == 0)
            return;
        // key --> 图类型, value --> 图实例
        Map<String, String> graphTypeMap = new HashMap<>();
        getGraphTypeFromCriteria(include, graphTypeMap);
        getGraphTypeFromCriteria(exclude, graphTypeMap);
        if (graphTypeMap.size() == 0) {
            return;
        }
        try {
            RelationUtil.batchGetGraphInstance(CommonMethods.getProject(projectId, false), graphTypeMap);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("获取图实例失败");
        }
        setGraphId(include, graphTypeMap);
        setGraphId(exclude, graphTypeMap);
    }

    private static void setGraphId(List<RelationCriteria> include, Map<String, String> graphTypeMap) {
        for (int i = include.size() - 1; i > -1; --i) {
            RelationCriteria relation = include.get(i);
            if (relation.getGraphId() == null || relation.getGraphId().length() == 0) {
                String graphType = relation.getGraphType();
                String graphId = graphTypeMap.get(graphType);
                if (graphId == null) {
                    include.remove(i);
                    continue;
                }
                relation.setGraphId(graphId);
            }
        }
    }

    public static void getGraphTypeFromCriteria(List<RelationCriteria> include, Map<String, String> graphTypeMap) {
        for (int i = include.size() - 1; i > -1; --i) {
            RelationCriteria relation = include.get(i);
            if (relation.getGraphId() == null || relation.getGraphId().length() == 0) {
                String graphType = relation.getGraphType();
                if (graphType == null || graphType.length() == 0) {
                    include.remove(i);
                    continue;
                }
                graphTypeMap.putIfAbsent(graphType, null);
            }
        }
    }

    public static IncludeExclude getIncludeExcludeId(String pjId, List<RelationCriteria> include, List<RelationCriteria> exclude) throws Exception {
        IncludeExclude includeExclude = new IncludeExclude();
        if (include.size() == 0 && exclude.size() == 0)
            return includeExclude;
        if (include.size() > 0)
            includeExclude.setInclude(true);  // 是否有要包含的关系
        if (exclude.size() > 0)
            includeExclude.setExclude(true);  // 是否有要被排除的关系
        Map<String, RelationCriteria> includeIndexMap = new HashMap<>();
        Map<String, RelationCriteria> excludeIndexMap = new HashMap<>();
        JSONArray criterias = new JSONArray();
        JSONArray criterias_from = new JSONArray();
        JSONArray criterias_to = new JSONArray();
        JSONArray criterias_from_to = new JSONArray();
        generateRelationQueryCriteria(pjId, include, includeIndexMap, criterias, criterias_from, criterias_to, criterias_from_to);
        generateRelationQueryCriteria(pjId, exclude, excludeIndexMap, criterias, criterias_from, criterias_to, criterias_from_to);
        try {
            JSONArray content = CommonUtil.multiCombineQuery(HBaseTable.rel_btw_objs, criterias, criterias_from, criterias_to, criterias_from_to);
            for (int i = 0; i < content.size(); ++i) {
                JSONObject singleRel = content.getJSONObject(i);
                combineId(singleRel);
                List<String> possibleKeys = new ArrayList<>();
                String possibleKey = String.join(".", singleRel.getString(RelTable.KEY_GRAPH_ID), singleRel.getString(RelTable.KEY_REL_TYPE), "", "");
                possibleKeys.add(possibleKey);
                possibleKey = String.join(".", singleRel.getString(RelTable.KEY_GRAPH_ID),
                        singleRel.getString(RelTable.KEY_REL_TYPE), singleRel.getString(Const.JSON_FIELD_FROM_ID), "");
                possibleKeys.add(possibleKey);
                possibleKey = String.join(".", singleRel.getString(RelTable.KEY_GRAPH_ID),
                        singleRel.getString(RelTable.KEY_REL_TYPE), "", singleRel.getString(Const.JSON_FIELD_TO_ID));
                possibleKeys.add(possibleKey);
                possibleKey = String.join(".", singleRel.getString(RelTable.KEY_GRAPH_ID),
                        singleRel.getString(RelTable.KEY_REL_TYPE), singleRel.getString(Const.JSON_FIELD_FROM_ID), singleRel.getString(Const.JSON_FIELD_TO_ID));
                possibleKeys.add(possibleKey);

                String fromId = singleRel.getString(Const.JSON_FIELD_FROM_ID);
                String toId = singleRel.getString(Const.JSON_FIELD_TO_ID);
                boolean hasInclude = false, hasExclude = false;
                for (String key : possibleKeys) {
                    if (includeIndexMap.containsKey(key) && !hasInclude) {
                        RelationCriteria relation = includeIndexMap.get(key);
                        if (relation.getSide() == RelationSide.both) {
                            includeExclude.getIncludeSet().add(fromId);
                            includeExclude.getIncludeSet().add(toId);
                        } else if (relation.getSide() == RelationSide.fromId) {
                            includeExclude.getIncludeSet().add(fromId);
                        } else {
                            includeExclude.getIncludeSet().add(toId);
                        }
                        hasInclude = true;
                    }
                    if (excludeIndexMap.containsKey(key) && !hasExclude) {
                        RelationCriteria relation = excludeIndexMap.get(key);
                        if (relation.getSide() == RelationSide.both) {
                            includeExclude.getExcludeSet().add(fromId);
                            includeExclude.getExcludeSet().add(toId);
                        } else if (relation.getSide() == RelationSide.fromId) {
                            includeExclude.getExcludeSet().add(fromId);
                        } else {
                            includeExclude.getExcludeSet().add(toId);
                        }
                        hasExclude = true;
                    }
                }
            }
        } catch (Exception e) {
            throw new Exception("Zillion查询异常");
        }
        return includeExclude;
    }

    public static void generateRelationQueryCriteria(String pjId, List<RelationCriteria> include, Map<String, RelationCriteria> includeIndexMap, JSONArray criterias, JSONArray criterias_from, JSONArray criterias_to, JSONArray criterias_from_to) {
        for (int i = 0; i < include.size(); ++i) {
            RelationCriteria relation = include.get(i);
            String key = String.join(".", relation.getGraphId(), relation.getRelType(), relation.getFromId(), relation.getToId());
            if (includeIndexMap.containsKey(key))
                continue;
            includeIndexMap.put(key, relation);
            JSONObject singleCriteria = new JSONObject();
            singleCriteria.put(RelTable.KEY_PJ_ID, pjId);
            singleCriteria.put(RelTable.KEY_GRAPH_ID, relation.getGraphId());
            singleCriteria.put(RelTable.KEY_REL_TYPE, relation.getRelType());
            JSONObject fromIdObj = new JSONObject();
            fromIdObj.put("id", relation.getFromId());
            JSONObject toIdObj = new JSONObject();
            toIdObj.put("id", relation.getToId());
            if (relation.getFromId().length() == 0 && relation.getToId().length() == 0) {
                criterias.add(singleCriteria);
            } else if (relation.getFromId().length() > 0 && relation.getToId().length() > 0) {
                try {
                    CommonUtil.rewriteObjectTableCriteria(pjId, fromIdObj, "id", true);
                    singleCriteria.put(RelTable.KEY_FROM_OBJ_TYPE, fromIdObj.getString(ObjectTable.KEY_OBJ_TYPE));
                    singleCriteria.put(RelTable.KEY_FROM_OBJ_ID, fromIdObj.getString(ObjectTable.KEY_OBJ_ID));
                    CommonUtil.rewriteObjectTableCriteria(pjId, toIdObj, "id", true);
                    singleCriteria.put(RelTable.KEY_TO_OBJ_TYPE, toIdObj.getString(ObjectTable.KEY_OBJ_TYPE));
                    singleCriteria.put(RelTable.KEY_TO_OBJ_ID, toIdObj.getString(ObjectTable.KEY_OBJ_ID));
                    criterias_from_to.add(singleCriteria);
                } catch (Exception e) {
                }
            } else if (relation.getFromId().length() > 0) {
                try {
                    CommonUtil.rewriteObjectTableCriteria(pjId, fromIdObj, "id", true);
                    singleCriteria.put(RelTable.KEY_FROM_OBJ_TYPE, fromIdObj.getString(ObjectTable.KEY_OBJ_TYPE));
                    singleCriteria.put(RelTable.KEY_FROM_OBJ_ID, fromIdObj.getString(ObjectTable.KEY_OBJ_ID));
                    criterias_from.add(singleCriteria);
                } catch (Exception e) {
                }
            } else if (relation.getToId().length() > 0) {
                try {
                    CommonUtil.rewriteObjectTableCriteria(pjId, toIdObj, "id", true);
                    singleCriteria.put(RelTable.KEY_TO_OBJ_TYPE, toIdObj.getString(ObjectTable.KEY_OBJ_TYPE));
                    singleCriteria.put(RelTable.KEY_TO_OBJ_ID, toIdObj.getString(ObjectTable.KEY_OBJ_ID));
                    criterias_to.add(singleCriteria);
                } catch (Exception e) {
                }
            }
        }
    }

    /**
     * @param pjId         1101080001
     * @param graphTypeMap
     * @throws Exception
     */
    private static void batchGetGraphInstance(String pjId, Map<String, String> graphTypeMap) throws Exception {

        //1.查询数据库中的图实例
        String time = CommonUtil.getTime();
        JSONArray criterias = new JSONArray();
        for (String graphType : graphTypeMap.keySet()) {
            JSONObject criteria = new JSONObject();
            criteria.put(GraphInstanceTable.KEY_PJ_ID, pjId);
            criteria.put(GraphInstanceTable.KEY_GRAPH_TYPE, graphType);
            criterias.add(criteria);
        }
        JSONObject re = CommonUtil.combine_query(HBaseTable.rel_btw_graph_period, criterias);
//        JSONObject re = CommonUtil.combine_query(HBaseTable.rel_btw_graph_period, criterias);
        JSONArray content = re.getJSONArray(Const.JSON_FIELD_Content);
        for (int i = content.size() - 1; i > -1; --i) {
            JSONObject obj = content.getJSONObject(i);
            String beginTime = obj.getString(GraphInstanceTable.KEY_BEGIN_TIME);
            String endTime = obj.getString(GraphInstanceTable.KEY_END_TIME);
            if (time.compareTo(beginTime) < 0 || time.compareTo(endTime) > 0) {
                content.remove(i);
            }
        }
        //1.end
        //2.将所有图实例id放到map中
        for (int i = 0; i < content.size(); ++i) {
            JSONObject graph = content.getJSONObject(i);
            String graphType = graph.get(GraphInstanceTable.KEY_GRAPH_TYPE).toString();
            String sequencyId = graph.get(GraphInstanceTable.KEY_SEQUENCE_ID).toString();
            String graphId = Const.OBJ_TYPE_GRAPH + graphType + sequencyId;

            if (graphTypeMap.containsKey(graphType) && graphTypeMap.get(graphType) != null) {//如果同时起作用的图实例存在多张，则操作序号小的
                String existedId = graphTypeMap.get(graphType);
                String tempSequencyId = existedId.substring(existedId.length() - 3);
                if (RelationUtil.compareId(sequencyId, tempSequencyId) > 0) {
                    sequencyId = tempSequencyId;
                    graphTypeMap.put(graphType, Const.OBJ_TYPE_GRAPH + graphType + sequencyId);
                }
            } else {
                graphTypeMap.put(graphType, graphId);
            }
        }
    }

    public static void batchGetGraphInstance(String pjId, Map<String, String> graphTypeMap, boolean createWhenNotExist) throws Exception {
        batchGetGraphInstance(pjId, graphTypeMap);
        if (createWhenNotExist) {
            String time = CommonUtil.getTime();
            for (String graphType : graphTypeMap.keySet()) {
                if (graphTypeMap.get(graphType) == null) {
                    String graphId = createGraph(pjId, graphType, time);
                    graphTypeMap.put(graphType, graphId);
                }
            }
        }
    }

    public static Set<String> getRelationIdSet(String pjId, RelationCriteria relation) throws Exception {
        JSONArray criterias = new JSONArray();
        getRaltionIdSetCriteria(pjId, relation, criterias);
        try {
            JSONObject resultObj = CommonUtil.combine_query(HBaseTable.rel_btw_objs, criterias);
            if (!"success".equals(resultObj.getString("Result")))
                throw new Exception("Zillion查询失败");
            JSONArray content = resultObj.getJSONArray("Content");
            Set<String> set = new HashSet<>();
            for (int i = 0; i < content.size(); ++i) {
                JSONObject singleRel = content.getJSONObject(i);
                String fromId = CommonUtil.combineId(pjId, singleRel.getString(RelTable.KEY_FROM_OBJ_TYPE), singleRel.getString(RelTable.KEY_FROM_OBJ_ID));
                String toId = CommonUtil.combineId(pjId, singleRel.getString(RelTable.KEY_TO_OBJ_TYPE), singleRel.getString(RelTable.KEY_TO_OBJ_ID));
                if (relation.getSide() == RelationSide.both) {
                    set.add(fromId);
                    set.add(toId);
                } else if (relation.getSide() == RelationSide.fromId) {
                    set.add(fromId);
                } else {
                    set.add(toId);
                }
            }
            return set;
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("Zillion查询失败");
        }
    }

    private static void getRaltionIdSetCriteria(String pjId, RelationCriteria relation, JSONArray criterias) {
        if(relation.getFromSet().size() > 0){
            Set<String> fromSet = relation.getFromSet();
            for(String id : fromSet){
                JSONObject criteria = new JSONObject();
                criteria.put(RelTable.KEY_PJ_ID, pjId);
                criteria.put(RelTable.KEY_GRAPH_ID, relation.getGraphId());
                criteria.put(RelTable.KEY_REL_TYPE, relation.getRelType());
                criteria.put(RelTable.KEY_FROM_OBJ_TYPE, CommonUtil.getObjectTypeById(id));
                criteria.put(RelTable.KEY_FROM_OBJ_ID, CommonUtil.getObjectIdById(id));
                criterias.add(criteria);
            }
        }else if(relation.getToSet().size() > 0){
            Set<String> toSet = relation.getToSet();
            for(String id : toSet){
                JSONObject criteria = new JSONObject();
                criteria.put(RelTable.KEY_PJ_ID, pjId);
                criteria.put(RelTable.KEY_GRAPH_ID, relation.getGraphId());
                criteria.put(RelTable.KEY_REL_TYPE, relation.getRelType());
                criteria.put(RelTable.KEY_TO_OBJ_TYPE, CommonUtil.getObjectTypeById(id));
                criteria.put(RelTable.KEY_TO_OBJ_ID, CommonUtil.getObjectIdById(id));
                criterias.add(criteria);
            }
        }else{
            JSONObject criteria = new JSONObject();
            criteria.put(RelTable.KEY_PJ_ID, pjId);
            criteria.put(RelTable.KEY_GRAPH_ID, relation.getGraphId());
            criteria.put(RelTable.KEY_REL_TYPE, relation.getRelType());
            criterias.add(criteria);
        }
    }

    public static Map<String, Set<String>> getGraphRelMap(String projectId) throws Exception {
        if (projectId.startsWith(Const.OBJ_TYPE_PROJECT)) {
            projectId = projectId.substring(2);
        }
        Map<String, Set<String>> result = new HashMap<>();
        result.putAll(RelStaticInfo.globalGraphRelSetMap);
        //查询自定义图类型
        JSONObject criteria = new JSONObject();
        criteria.put(RelDefTable.KEY_PJ_ID, projectId);
        JSONArray content = CommonUtil.query(false, HBaseTable.graph_type_def, criteria).getJSONArray(Const.JSON_FIELD_Content);
        for (int i = 0; i < content.size(); ++i) {
            JSONObject jsonNode = content.getJSONObject(i);
            result.put(jsonNode.getString(RelDefTable.KEY_GRAPH_TYPE), new HashSet<>());
        }
        //查询自定义关系类型
        content = CommonUtil.query(false, HBaseTable.rel_type_def, criteria).getJSONArray(Const.JSON_FIELD_Content);
        for (int i = 0; i < content.size(); ++i) {
            JSONObject jsonNode = content.getJSONObject(i);
            String graphType = jsonNode.getString(RelDefTable.KEY_GRAPH_TYPE);
            String relType = jsonNode.getString(RelDefTable.KEY_REL_TYPE);
            if (!result.containsKey(graphType)) {
                result.put(graphType, new HashSet<>());
            }
            result.get(graphType).add(relType);
        }
        return result;
    }

    /**
     * 根据图类型、关系类型、对象id，查询关系
     *
     * @param pjId      不以Pj开头的项目id
     * @param graphType 图类型
     * @param relType   关系类型
     * @param idSet     对象id
     * @param isFrom    对象id所在位置，true：对象id是fromId，false：对象id是toId
     * @return
     */
    public static Map<String, Set<String>> getRelations(String pjId, String graphType, String relType, Set<String> idSet, boolean isFrom) throws Exception {
        Map<String, Set<String>> result = new HashMap<>();
        String graphId = getGraphInstance(pjId, graphType, CommonUtil.getTime(), false);
        if (graphId == null) {
            return result;
        }
        JSONArray criterias = new JSONArray();
        for (String id : idSet) {
            JSONObject criteria = new JSONObject();
            criteria.put(RelTable.KEY_PJ_ID, pjId);
            criteria.put(RelTable.KEY_GRAPH_ID, graphId);
            criteria.put(RelTable.KEY_REL_TYPE, relType);
            if (isFrom) {
                criteria.put(Const.JSON_FIELD_FROM_ID, id);
                rewriteCriteria(criteria, Const.JSON_FIELD_FROM_ID);
            } else {
                criteria.put(Const.JSON_FIELD_TO_ID, id);
                rewriteCriteria(criteria, Const.JSON_FIELD_TO_ID);
            }
            criterias.add(criteria);
        }
        JSONArray content = CommonUtil.combine_query(HBaseTable.rel_btw_objs, criterias).getJSONArray(Const.JSON_FIELD_Content);
        for (int i = 0; i < content.size(); ++i) {
            JSONObject node = content.getJSONObject(i);
            combineId(node);
            String keyId;
            String valueId;
            if (isFrom) {
                keyId = node.getString(Const.JSON_FIELD_FROM_ID);
                valueId = node.getString(Const.JSON_FIELD_TO_ID);
            } else {
                keyId = node.getString(Const.JSON_FIELD_TO_ID);
                valueId = node.getString(Const.JSON_FIELD_FROM_ID);
            }
            if (!result.containsKey(keyId)) {
                result.put(keyId, new HashSet<>());
            }
            result.get(keyId).add(valueId);
        }
        return result;
    }
}
