package com.sagacloud.endpoints;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.base.Strings;
import com.sagacloud.dict.EqStaticInfo;
import com.sagacloud.dict.RelStaticInfo;
//import com.sagacloud.json.JSONArray;
//import com.sagacloud.json.JSONObject;
//import com.sagacloud.json.JSONValue;
import com.alibaba.fastjson.*;
import com.sagacloud.endpoints.item.PhysicalObject;
import com.sagacloud.utils.*;
import com.sagacloud.utils.objects.CommonQueryCriteria;
import com.sagacloud.utils.objects.OutsideGraphQueryProcessor;
import com.sagacloud.utils.relationUtils.RelationUtil;
import com.sagacloud.utils.tables.*;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.*;

@Path("relation")
public class Relation {

    @Path("/create")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String Create(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {

        String validateResult = RelationUtil.validateExistence(projectId.substring(2, 12), jsonStr);
        if (validateResult != null)
            return validateResult;
        return RelationUtil.batchCreateRelation(projectId.substring(2, 12), jsonStr);
    }

    @Path("/update")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String update(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {

        return RelationUtil.updateRelation(projectId.substring(2, 12), jsonStr);
    }

    @Path("/delete")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String delete(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {

        return RelationUtil.deleteRelation(projectId.substring(2, 12), jsonStr);
    }

    @Path("/query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String query(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        Boolean doFlatten = false;
        JSONObject json = JSONObject.parseObject(jsonStr);
        if (json.containsKey("merge")) {
            if (json.get("merge") != null)
                doFlatten = (Boolean) json.get("merge");
            json.remove("merge");
        }
        return JSON.toJSONString(RelationUtil.queryRelationWithBidirection(projectId.substring(2, 12),
                JSON.toJSONString(json, SerializerFeature.WriteMapNullValue, SerializerFeature.DisableCircularReferenceDetect), doFlatten), SerializerFeature.WriteMapNullValue, SerializerFeature.DisableCircularReferenceDetect);
//        return RelationUtil.queryRelation(projectId.substring(2, 12), json.toString(), doFlatten);
    }

    @Path("/query_by_graph_type")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryByGraphType(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            JSONObject criteria = json.getJSONObject("criteria");
            if (criteria.get("graph_type") == null && criteria.get("graph_id") == null) {
                return DpUtils.errorJsonMsg("graph_type 和 graph_id 必填其一");
            }
            String graphType = (String) criteria.get("graph_type");
            if (graphType != null) {
                String graphId = RelationUtil.getGraphInstance(projectId.substring(2), graphType, CommonUtil.getTime(), false);
                if (criteria.get("graph_id") == null) {
                    criteria.put("graph_id", graphId);
                }
            }
            criteria.remove("graph_type");
            if (criteria.get("graph_id") == null) {
                return DpUtils.returnJSONArray(new JSONArray(), "");
            }
            return query(projectId, json.toString());
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(e.getMessage());
        }
    }

    @Path("/query_by_obj_type")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryRelByType(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            JSONObject criteriaNode = (JSONObject) json.get("criteria");
            String graphId = criteriaNode.get(RelTable.KEY_GRAPH_ID).toString();
            String relType = criteriaNode.get(RelTable.KEY_REL_TYPE).toString();
            boolean isFrom = true;
            String id = null;
            String objType = null;
            if (criteriaNode.get(Const.JSON_FIELD_FROM_ID) != null) {
                isFrom = true;
                id = criteriaNode.get(Const.JSON_FIELD_FROM_ID).toString();
                objType = criteriaNode.get(RelTable.KEY_TO_OBJ_TYPE).toString();
            } else if (criteriaNode.get(Const.JSON_FIELD_TO_ID) != null) {
                isFrom = false;
                id = criteriaNode.get(Const.JSON_FIELD_TO_ID).toString();
                objType = criteriaNode.get(RelTable.KEY_FROM_OBJ_TYPE).toString();
            }
            if (id == null || objType == null) {
                return DpUtils.errorJsonMsg("请检查输入");
            }
            JSONArray content = RelationUtil.queryRelByType(projectId, graphId, relType, id, objType, isFrom);
            return DpUtils.returnJSONArray(content, "");
        } catch (Exception e) {
            return DpUtils.errorJsonMsg(e.getMessage());
        }
//        String fromType = (String) criteriaNode.get(RelTable.KEY_FROM_OBJ_TYPE);
//        if (RelationUtil.appendType(fromType) != null) {
//            criteriaNode.put(RelTable.KEY_FROM_OBJ_TYPE, RelationUtil.appendType(fromType));
//        }
//        String toType = (String) criteriaNode.get(RelTable.KEY_TO_OBJ_TYPE);
//        if (RelationUtil.appendType(toType) != null) {
//            criteriaNode.put(RelTable.KEY_TO_OBJ_TYPE, RelationUtil.appendType(toType));
//        }
//        return RelationUtil.queryRelationWithBidirection(projectId.substring(2, 12), json.toString(), true);
    }

    @Path("/query_subset")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String querySubset(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONArray relTypes = (JSONArray) ((JSONObject) json.get("criteria")).get("rel_types");
        JSONArray criterias = new JSONArray();
        for (int i = 0; i < relTypes.size(); ++i) {
            JSONObject item = new JSONObject();
            item.put(RelTable.KEY_GRAPH_ID, ((JSONObject) json.get("criteria")).get("graph_id"));
            item.put(RelTable.KEY_REL_TYPE, relTypes.get(i));
            criterias.add(item);
        }
        json.clear();
        json.put("criterias", criterias);
        return RelationUtil.queryRelation(projectId.substring(2, 12), JSON.toJSONString(json, SerializerFeature.WriteMapNullValue, SerializerFeature.DisableCircularReferenceDetect), false);

    }


    @Path("/query_path")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryPath(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        projectId = projectId.substring(2, 12);
        Hashtable<String, ArrayList> graphMap = RelationUtil.buildGraphMap(projectId);
        if (graphMap == null)
            return DpUtils.errorJsonMsg("邻接表初始化失败");
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            JSONObject criteria = (JSONObject) json.get("criteria");
            if (criteria.containsKey("graph_rel_types")) {//指定关系类型查路径
                String from_id = (String) criteria.get(Const.JSON_FIELD_FROM_ID);
                JSONArray givenRelTypes = (JSONArray) criteria.get("graph_rel_types");
                JSONArray paths = new JSONArray();
                JSONArray onePath = new JSONArray();
                onePath.add(from_id);
                RelationUtil.getPaths(from_id, graphMap, paths, onePath, givenRelTypes, 0);
                return DpUtils.returnJSONArray(paths, "");
            } else {//指定起点终点和图类型，查路径
                String from_id = (String) criteria.get(Const.JSON_FIELD_FROM_ID);
                String to_id = (String) criteria.get(Const.JSON_FIELD_TO_ID);
                String graph_type = (String) criteria.get(RelTable.KEY_GRAPH_ID);
                JSONArray allPaths = new JSONArray();
                RelationUtil.getPathsWithEndpoint(from_id, to_id, graph_type, graphMap, new JSONArray(), allPaths);
                return DpUtils.returnJSONArray(allPaths, "");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    @Path("/query_path_by_distance")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryPathByDistance(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {

        projectId = projectId.substring(2, 12);
        Hashtable<String, ArrayList> graphMap = RelationUtil.buildGraphMap(projectId);
        if (graphMap == null)
            return DpUtils.errorJsonMsg("邻接表初始化失败");
        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONObject criteria = (JSONObject) json.get("criteria");
        long distance = criteria.getLongValue("distance");
        String from_id = (String) criteria.get(Const.JSON_FIELD_FROM_ID);
        String graph_type = (String) criteria.get(RelTable.KEY_GRAPH_ID);
        String rel_type = (String) criteria.get(RelTable.KEY_REL_TYPE);
        JSONArray givenRelTypes = new JSONArray();
        for (long i = 0; i < distance; ++i) {
            JSONObject item = new JSONObject();
            item.put(RelTable.KEY_GRAPH_ID, graph_type);
            item.put(RelTable.KEY_REL_TYPE, rel_type);
            givenRelTypes.add(item);
        }
        JSONArray paths = new JSONArray();
        JSONArray onePath = new JSONArray();
        onePath.add(from_id);
        RelationUtil.getPaths(from_id, graphMap, paths, onePath, givenRelTypes, 0);
        return DpUtils.returnJSONArray(paths, "");

    }

    @Path("/graph_def/create")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String createGraphDef(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        HashSet allGraph = new HashSet();
        allGraph.addAll(RelStaticInfo.globalGraphSet);
        JSONObject criteria = new JSONObject();
        criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            json.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
            String graph_type = (String) json.get(RelDefTable.KEY_GRAPH_TYPE);
            if (allGraph.contains(graph_type)) {
                return DpUtils.errorJsonMsg("已存在");
            }
            JSONObject re = CommonUtil.insert(false, HBaseTable.graph_type_def, json);
            if (re.get(Const.JSON_FIELD_RESULT).toString().equals("success")) {
                return DpUtils.successJsonMsg("创建成功");
            } else {
                return DpUtils.errorJsonMsg("已存在");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    @Path("/graph_def/update")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String updateGraphDef(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONObject criteria = (JSONObject) json.get("criteria");
        criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
        JSONObject set = (JSONObject) json.get("set");
        try {
            JSONObject re = CommonUtil.update(false, HBaseTable.graph_type_def, criteria, set);
            if (re.get(Const.JSON_FIELD_RESULT).toString().equals("success")) {
                return DpUtils.successJsonMsg("更新成功");
            } else {
                return DpUtils.errorJsonMsg("");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    @Path("/graph_def/delete")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String deleteGraphDef(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONObject criteria = (JSONObject) json.get("criteria");
        criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));

        try {
            Long count = CommonUtil.getCount(HBaseTable.rel_type_def, criteria);
            if (count > 0) {
                return DpUtils.errorJsonMsg("被引用过，不能删除");
            }
            CommonUtil.delete(false, HBaseTable.graph_type_def, criteria);
            return DpUtils.successJsonMsg("删除成功");
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    @Path("/graph_def/query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryGraphDef(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONObject criteria = (JSONObject) json.get("criteria");
        criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
        String graphType = (String) criteria.get(RelDefTable.KEY_GRAPH_TYPE);
        JSONArray allContent = new JSONArray();

        try {
            JSONObject re = CommonUtil.query(false, HBaseTable.graph_type_def, criteria);
            JSONArray localGraph = (JSONArray) re.get(Const.JSON_FIELD_Content);
            CommonUtil.addField(localGraph, "scope", "local");
            for (int i = 0; i < RelStaticInfo.globalDefArray.size(); ++i) {
                JSONObject item = new JSONObject();
                com.sagacloud.json.JSONObject defNode = (com.sagacloud.json.JSONObject) RelStaticInfo.globalDefArray.get(i);
                item.put(RelDefTable.KEY_GRAPH_TYPE, defNode.get(RelDefTable.KEY_GRAPH_TYPE));
                item.put(RelDefTable.KEY_DESCRIPTION, defNode.get("graph_name"));
                item.put("scope", "global");
                if (!allContent.contains(item)) {
                    if (graphType == null)
                        allContent.add(item);
                    else {
                        if (graphType.equals(item.get(RelDefTable.KEY_GRAPH_TYPE)))
                            allContent.add(item);
                    }
                }
            }

            allContent.addAll(localGraph);
            return DpUtils.returnJSONArray(allContent, "");
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    @Path("/rel_def/create")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String createRelDef(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        HashSet allGraph = new HashSet();
        HashSet<String> allRel = new HashSet<>();
        allGraph.addAll(RelStaticInfo.globalGraphSet);
        allRel.addAll(RelStaticInfo.globalGraphRelMap.keySet());
        JSONObject criteria = new JSONObject();
        criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
        try {
            //1.查询所有graph_type
            JSONObject re = CommonUtil.query(false, HBaseTable.graph_type_def, criteria);
            JSONArray content = (JSONArray) re.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);
                allGraph.add(graph_type);
            }
            JSONObject json = JSONObject.parseObject(jsonStr);
            json.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
            String graphType = (String) json.get(RelDefTable.KEY_GRAPH_TYPE);
            String relType = (String) json.get(RelDefTable.KEY_REL_TYPE);
            if (!allGraph.contains(graphType)) {
                return DpUtils.errorJsonMsg("请先创建图类型");
            }
            //1.end
            if (allRel.contains(graphType + "," + relType)) {
                return DpUtils.errorJsonMsg("已存在");
            }
            if (!json.containsKey(RelDefTable.KEY_DIRECTIONAL) || json.get(RelDefTable.KEY_DIRECTIONAL) == null)
                json.put(RelDefTable.KEY_DIRECTIONAL, false);
            re = CommonUtil.insert(false, HBaseTable.rel_type_def, json);
            if (re.get(Const.JSON_FIELD_RESULT).toString().equals("success")) {
                return DpUtils.successJsonMsg("创建成功");
            } else {
                return DpUtils.errorJsonMsg("已存在");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }

    }

    @Path("/rel_def/update")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String updateRelDef(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONObject criteria = (JSONObject) json.get("criteria");
        criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
        JSONObject set = (JSONObject) json.get("set");
        try {
            JSONObject re = CommonUtil.update(false, HBaseTable.rel_type_def, criteria, set);
            if (re.get(Const.JSON_FIELD_RESULT).toString().equals("success")) {
                return DpUtils.successJsonMsg("更新成功");
            } else {
                return DpUtils.errorJsonMsg("");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    @Path("/rel_def/delete")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String deleteRelDef(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        //TODO graph_type?
//        {
//            "criteria":{
//            "graph_type":"g",   //必填，图类型
//                    "rel_type":"r"      //必填，关系类型
//        }
//        }

        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONObject criteria = (JSONObject) json.get("criteria");
        criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
        String relType = criteria.get(RelTable.KEY_REL_TYPE).toString();
        try {
            criteria.remove(RelTable.KEY_REL_TYPE);
            JSONObject graphInst = CommonUtil.query(false, HBaseTable.graph_instance, criteria);
            JSONArray criterias = new JSONArray();
            JSONArray graphContent = (JSONArray) graphInst.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < graphContent.size(); ++i) {
                JSONObject obj = (JSONObject) graphContent.get(i);
                String graphId = Const.OBJ_TYPE_GRAPH + obj.get(GraphInstanceTable.KEY_GRAPH_TYPE).toString() + obj.get(GraphInstanceTable.KEY_SEQUENCE_ID).toString();

                JSONObject criteriaTemp = new JSONObject();
                criteriaTemp.put(RelTable.KEY_GRAPH_ID, graphId);
                criteriaTemp.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
                criteriaTemp.put(RelTable.KEY_REL_TYPE, relType);
                criterias.add(criteriaTemp);
            }
            if (CommonUtil.getCount(HBaseTable.rel_btw_objs, criterias)) {
                return DpUtils.errorJsonMsg("被引用过，不能删除");
            }
//            Long count = CommonUtil.getCount(HBaseTable.rel_btw_objs,criteria);
//            if(count > 0){
//                return DpUtils.errorJsonMsg("被引用过，不能删除");
//            }
            CommonUtil.delete(false, HBaseTable.rel_type_def, criteria);
            return DpUtils.successJsonMsg("删除成功");
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    @Path("/rel_def/query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryRelDef(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONObject criteria = (JSONObject) json.get("criteria");
        criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2, 12));
        String graph_type = (String) criteria.get(RelDefTable.KEY_GRAPH_TYPE);
        String rel_type = (String) criteria.get(RelDefTable.KEY_REL_TYPE);
        JSONArray allRel = new JSONArray();
        try {
            JSONObject re = CommonUtil.query(false, HBaseTable.rel_type_def, criteria);
            JSONArray localRel = (JSONArray) re.get(Const.JSON_FIELD_Content);
            CommonUtil.addField(localRel, "scope", "local");
            for (int i = 0; i < RelStaticInfo.globalDefArray.size(); ++i) {
                JSONObject item = new JSONObject();
                item.put(RelDefTable.KEY_GRAPH_TYPE, ((JSONObject) RelStaticInfo.globalDefArray.get(i)).get(RelDefTable.KEY_GRAPH_TYPE));
                item.put(RelDefTable.KEY_REL_TYPE, ((JSONObject) RelStaticInfo.globalDefArray.get(i)).get(RelDefTable.KEY_REL_TYPE));
                item.put(RelDefTable.KEY_DIRECTIONAL, ((JSONObject) RelStaticInfo.globalDefArray.get(i)).get(RelDefTable.KEY_DIRECTIONAL));
                String[] keys = {"rel_name", "description", "target_objs"};
                StringBuilder description = new StringBuilder();

                for (String key : keys) {
                    String value = (String) ((JSONObject) RelStaticInfo.globalDefArray.get(i)).get(key);
                    if (value != null && value.length() != 0) {
                        description.append(value).append(".");
                    }
                }
                item.put(RelDefTable.KEY_DESCRIPTION, description.toString());
                item.put("scope", "global");
                if (graph_type == null) {
                    allRel.add(item);
                } else if (rel_type == null) {
                    if (graph_type.equals(item.get(RelDefTable.KEY_GRAPH_TYPE)))
                        allRel.add(item);
                } else {
                    if (graph_type.equals(item.get(RelDefTable.KEY_GRAPH_TYPE)) && rel_type.equals(item.get(RelDefTable.KEY_REL_TYPE)))
                        allRel.add(item);
                }

            }
            allRel.addAll(localRel);
            return DpUtils.returnJSONArray(allRel, "");
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }
    }

    @Path("/graph_instance/create")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String createGraphInstance(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        HashSet allGraph = new HashSet();
        allGraph.addAll(RelStaticInfo.globalGraphSet);

        JSONObject criteria = JSONObject.parseObject(jsonStr);
        String graphType = (String) criteria.get(GraphInstanceTable.KEY_GRAPH_TYPE);
        String boundObjId = (String) criteria.get("bound_obj_id");
        criteria = new JSONObject();
        criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2));

        try {
            //1.查询所有图类型，没有图类型则不能创建实例
            JSONObject re = CommonUtil.query(false, HBaseTable.graph_type_def, criteria);
            JSONArray content = (JSONArray) re.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);
                allGraph.add(graph_type);
            }
            if (!allGraph.contains(graphType)) {
                return DpUtils.errorJsonMsg("Please define graph type first! 请先定义图类型!");
            }
            //1.end
            //2.检验绑定的对象是否存在
            if (boundObjId != null) {
                criteria.clear();
                criteria.put(RelDefTable.KEY_PJ_ID, projectId.substring(2));
                criteria.put("bound_obj_id", boundObjId);
                criteria.put(ObjectTable.COL_VALID, true);
                CommonUtil.rewriteObjectTableCriteria(projectId.substring(2), criteria, "bound_obj_id");
                long count = CommonUtil.getCount(HBaseTable.objects, criteria);
                if (count <= 0) {
                    return DpUtils.errorJsonMsg("Please create a physical or virtual object first! 请先创建物理实体对象或虚拟对象!");
                }
            }
            //2.end
            return RelationUtil.createGraphInstance(projectId.substring(2), jsonStr);
        } catch (Exception e) {
            e.printStackTrace();
            return DpUtils.errorJsonMsg(Arrays.toString(e.getStackTrace()));
        }

    }

    @Path("/graph_instance/query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryGraphInstance(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        Boolean doFlatten = false;
        JSONObject json = JSONObject.parseObject(jsonStr);
        if (json.containsKey("merge")) {
            if (json.get("merge") != null)
                doFlatten = (Boolean) json.get("merge");
            json.remove("merge");
        }
        return RelationUtil.queryGraphInstance(projectId.substring(2), jsonStr, doFlatten);
    }

    @Path("/graph_instance/get")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String getGraphInstance(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            String graphType = json.getString("graph_type");
            if (graphType == null)
                throw new Exception("没有graph_type!");
            String graphId = RelationUtil.getGraphInstance(projectId.substring(2), graphType, CommonUtil.getTime(), true);
            JSONObject ret = new JSONObject();
            ret.put(Const.JSON_FIELD_RESULT, "success");
            ret.put("ResultMsg", "");
            ret.put("graph_id", graphId);
            return ret.toString();
        } catch (Exception ex) {
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }

    @Path("/graph_instance/query_his")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryGraphInstanceHistory(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            String graphType = json.get("graph_type").toString();
            JSONArray result = RelationUtil.queryGraphInstanceHistory(projectId, graphType);
            return DpUtils.returnJSONArray(result, "");
        } catch (Exception e) {
            return DpUtils.errorJsonMsg(e.getMessage());
        }
    }

    @Path("/graph_instance/update")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String updateGraphInstance(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {

        return RelationUtil.updateGraphInstance(projectId.substring(2), jsonStr);
    }

    @Path("/graph_instance/delete")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String deleteGraphInstance(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {

        return RelationUtil.deleteGraphInstance(projectId.substring(2), jsonStr);
    }

    @Path("/subset/query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String subsetQuery(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            JSONObject query = JSONObject.parseObject(jsonStr);
            CommonQueryCriteria cqc = new CommonQueryCriteria();
            JSONObject criteriasNode = (JSONObject) query.get("criteria");
            String id = PhysicalObject.checkIdNode(projectId, criteriasNode);
            String graphId = Strings.nullToEmpty((String) criteriasNode.get("graph_id"));
            String graphType = Strings.nullToEmpty((String) criteriasNode.get("graph_type"));
            String relType = Strings.nullToEmpty((String) criteriasNode.get("rel_type"));
            String fromId = Strings.nullToEmpty((String) criteriasNode.get("from_id"));
            String toId = Strings.nullToEmpty((String) criteriasNode.get("to_id"));
            if (relType.length() == 0)
                relType = "1";
            if (criteriasNode.containsKey("rel_type") && criteriasNode.get("rel_type") == null)  // 强行让关系类型 = null
                relType = null;
            if((fromId.length() > 0 || toId.length() > 0) && relType == null){
                throw new Exception("暂不支持关系类型为null的情况下查询from_id或to_id");
            }
            Set<String> typeSet = new HashSet<>();
            JSONArray typeArr = (JSONArray) criteriasNode.get("type");
            PhysicalObject.addType(projectId, typeArr, typeSet);
            if (graphId.length() == 0 && graphType.length() == 0)
                throw new Exception("graph_id和graph_type类型至少需要一个");
            // 获取图id
            if (graphId.length() == 0) {
                graphId = OutsideGraphQueryProcessor.getDefaultGraphId(projectId, graphType);
            }

            EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
            JSONArray result = RelationUtil.subsetQuery(projectId, id, graphId, relType, typeSet, cqc, fromId, toId, eqStaticInfo);

            if (cqc.getNodata())
                return DpUtils.returnJSONArray(result, "", cqc.getCount());
            return DpUtils.returnJSONArray(result, "");
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }


//    @Path("/test")
//    @POST
//    @Produces(MediaType.APPLICATION_JSON)
//    public String test(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
//        String pjId = projectId.substring(2);
//        JSONObject json = (JSONObject) JSONValue.parse(jsonStr);
//        String formId = json.get("id").toString();
//        JSONArray types = (JSONArray) json.get("types");
//        Set<String> typeSet = new HashSet<>();
//        for(int i = 0; i < types.size(); ++i){
//            typeSet.add(types.get(i).toString());
//        }
//        ArrayList<String> reuslt = SubsetUtil.getSubset2(formId,typeSet,null);
//        JSONObject re = new JSONObject();
//        re.put("count",new Long(reuslt.size()));
//        re.put("content",reuslt.toString());
//        return re.toString();
//    }

}
