package com.sagacloud.endpoints.item;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.sagacloud.dict.CsStaticInfo;
import com.sagacloud.dict.EqStaticInfo;
import com.sagacloud.dict.TlStaticInfo;
import com.sagacloud.endpoints.StatusData;
import com.sagacloud.exception.NoTypeException;
import com.sagacloud.utils.*;
import com.sagacloud.utils.jsonHelper.SubsetEntity;
import com.sagacloud.utils.objects.CommonQueryCriteria;
import com.sagacloud.utils.objects.OutsideGraphQueryProcessor;
import com.sagacloud.utils.objects.RelationCriteria;
import com.sagacloud.utils.qrCode.QRCodeObj;
import com.sagacloud.utils.qrCode.QRCodeUtil;
import com.sagacloud.utils.relationUtils.RelationUtil;
import com.sagacloud.utils.relationUtils.SubsetUtil;
import com.sagacloud.utils.tables.HBaseTable;
import com.sagacloud.utils.tables.ObjInfosTable;
import com.sagacloud.utils.tables.ObjectTable;

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.awt.*;
import java.util.List;
import java.util.*;

//import com.sagacloud.json.JSONArray;
//import com.sagacloud.json.JSONObject;
//import com.sagacloud.json.JSONValue;


/**
 * Created by Xiaoyu on 2017/6/28.
 */
@Path("object")
public class PhysicalObject {

    public static Set<String> allTypes = CommonUtil.createSet(
            "Eq", "Sy", "Pj", "Bd", "Fl", "Sp", "Si", "Ec", "Sh", "Pe", "VOBd", "VOEi", "VOCu", "VOTn", "VOZn",
            "VOGp", "VOCt", "VOBc", "VOSe", "VOSc", "VOSh", "VOSw", "VOSg", "VOSf", "VOSv", "VOBr", "VOMt", "Cs", "Tl");
    public static LinkedHashMap<String, String> bussinessSpaceTypeMap = new LinkedHashMap<>();// = CommonUtil.createArrayList("PowerSupplyZone", "LightingZone", "NetworkZone", "AirConditioningZone", "HeatingZone", "NetworkZone", "CleanZone", "DomesticWaterSupplyZone", "FireZone", "SecurityZone", "TenantZone", "FunctionZone");

    static {
        // 此处的put, 必须按照ElementSptoSp中的关系类型顺序添加.
        bussinessSpaceTypeMap.put("PowerSupplyZone", "供电分区");
        bussinessSpaceTypeMap.put("LightingZone", "照明分区");
        bussinessSpaceTypeMap.put("NetworkZone", "网络分区");
        bussinessSpaceTypeMap.put("AirConditioningZone", "空调分区");
        bussinessSpaceTypeMap.put("HeatingZone", "采暖分区");
        bussinessSpaceTypeMap.put("CleanZone", "洁净分区");
        bussinessSpaceTypeMap.put("DomesticWaterSupplyZone", "生活给水分区");
        bussinessSpaceTypeMap.put("FireZone", "防火分区");
        bussinessSpaceTypeMap.put("SecurityZone", "安防分区");
        bussinessSpaceTypeMap.put("TenantZone", "租户分区");
        bussinessSpaceTypeMap.put("FunctionZone", "功能分区");
        bussinessSpaceTypeMap.put("GeneralZone", "默认分区");
    }

    @Path("/subset_query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String subsetQuery(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        return subsetQuery(projectId, json);
    }

    @Path("/subset_query_count")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String subsetQueryCount(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        if(projectId == null || !json.containsKey("objectType")) {
            return DpUtils.errorJsonMsg("必填参数不能为空！");
        }

        if(projectId.length() < 3) {
            return DpUtils.errorJsonMsg("projectId值"+projectId+"不合法");
        }

        boolean validState = true;
        if(json.containsKey("valid")) {
            try {
                validState = json.getBoolean("valid");
            }catch (Exception e) {
                return DpUtils.errorJsonMsg("valid值不合法");
            }
        }

        String objectType = json.getString("objectType");

        JSONObject criteriaObjType = new JSONObject();
        criteriaObjType.put("project_id", projectId.substring(2));
        criteriaObjType.put("obj_type", objectType);
        criteriaObjType.put("valid", validState);

        JSONObject criteriaSubtype = new JSONObject();
        criteriaSubtype.put("project_id", projectId.substring(2));
        criteriaSubtype.put("subtype", objectType);
        criteriaSubtype.put("valid", validState);

        JSONObject jsonParam = new JSONObject();
        jsonParam.put("QueryType", "select_count");
        jsonParam.put("Database", OssUtils.getProperty("database.name"));
        jsonParam.put("Datatable", "objects");

        if(objectType.length() == 2 || objectType.startsWith("VO")) {
            jsonParam.put("Criteria", criteriaObjType);
        }else {
            jsonParam.put("Criteria", criteriaSubtype);
        }

        try {
            JSONObject result = ZillionAgentProvider.GetAgent().Query(jsonParam);
            if("success".equals(result.getString("Result"))) {
                return result.toString();
            }else {
                return DpUtils.errorJsonMsg(result.toString());
            }
        } catch (Exception e) {
            System.out.println("subset_query_count接口执行zillion出错！param="+jsonParam.toString());
            e.printStackTrace();
            return DpUtils.errorJsonMsg("zillion执行出错！" + e.getMessage());
        }
    }

    private JSONObject queryObjectCount(JSONObject jsonParam) throws Exception {
        return ZillionAgentProvider.GetAgent().Query(jsonParam);
    }

    public String subsetQuery(String projectId, JSONObject json) {
        try {
//            JSONObject json = JSONObject.parseObject(jsonStr);
            CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(json);
            Boolean nodata = cqc.getNodata();
            cqc.setNodata(false);
            
            JSONObject criteriaNode = (JSONObject) json.get("criteria");
            JSONArray jsonType = ((JSONArray) criteriaNode.get("type"));
            ArrayList<String> types = new ArrayList<>();
            for (int i = 0; i < jsonType.size(); ++i) {
                types.add(jsonType.get(i).toString());
            }
            EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
            JSONArray result = ObjectUtil.subsetQuery(projectId.substring(2), types, criteriaNode.get("id") != null ? criteriaNode.get("id").toString() : projectId, projectId.substring(2), cqc, eqStaticInfo);
            
            if (nodata)
                return DpUtils.returnJSONArray(new JSONArray(), "", cqc.getSkip_totalCount());
            return DpUtils.returnJSONArray(result, cqc.getSkip_totalCount());
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }

    @Path("/batch_query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String batchQueryById(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        JSONObject json = JSONObject.parseObject(jsonStr);
        return batchQueryById(projectId, json);
    }

    public String batchQueryById(String projectId, JSONObject json) {
        try {
//            JSONObject json = JSONObject.parseObject(jsonStr);
            JSONArray criteriasNode = (JSONArray) json.get("criterias");
            CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(json);
            EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
            JSONArray result = CommonUtil.batchQuerySelfInfo(projectId.substring(2), criteriasNode, cqc, eqStaticInfo);
            if (cqc.getNodata())
                return DpUtils.returnJSONArray(result, "", cqc.getCount());
            return DpUtils.returnJSONArray(result, cqc.getSkip_totalCount());
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }

    @Path("/query_by_info")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryByInfo(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            Boolean set = true; // set 为true 则取交集, false取并集
            ArrayList<String> types = new ArrayList<>();
            String id = projectId;
            JSONObject json = JSONObject.parseObject(jsonStr);
            JSONArray infos = null;

            CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(json);
            Boolean nodata = cqc.getNodata();
            cqc.setNodata(false);
            
            if (!json.containsKey("criteria"))
                throw new Exception("缺少criteria节点.");
            JSONObject criteria = (JSONObject) json.get("criteria");
            if (criteria.get("set") != null && criteria.get("set").equals(false))
                set = false;
            if (criteria.get("id") != null)
                id = criteria.get("id").toString();
            if (!(id.startsWith(Const.OBJ_TYPE_PROJECT) || id.startsWith(Const.OBJ_TYPE_FLOOR) || id.startsWith(Const.OBJ_TYPE_BUILDING) || id.startsWith(Const.OBJ_TYPE_EQUIPMENT)))
                throw new Exception("id不合法! 只能是项目, 建筑, 楼层或者设备类型id");
            if (criteria.containsKey("type") && criteria.get("type") instanceof JSONArray) {
                JSONArray ts = (JSONArray) criteria.get("type");
                for (int i = 0; i < ts.size(); ++i)
                    types.add(ts.get(i).toString());
                checkTypes(projectId, types, id);
            }
            if (!criteria.containsKey(Const.JSON_FIELD_JSON_DATA_INFOS))
                throw new Exception("缺少infos节点.");
            infos = (JSONArray) criteria.get(Const.JSON_FIELD_JSON_DATA_INFOS);
            EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
            if (infos.size() == 0) {
                JSONArray result = ObjectUtil.subsetQuery(projectId.substring(2), types, id, projectId.substring(2), cqc, eqStaticInfo);
                if (nodata)
                    return DpUtils.returnJSONArray(new JSONArray(), "", cqc.getSkip_totalCount());
                return DpUtils.returnJSONArray(result, cqc.getSkip_totalCount());
            }

            JSONArray result = CommonUtil.queryObjectByInfoPointValue(projectId.substring(2), id, infos, types, set, cqc, eqStaticInfo);
            //JSONArray result = CommonUtil.queryObjectByInfoPointValue(projectId.substring(2), infos, noData, arr, valid, createTime, set, types);
            if (nodata)
                return DpUtils.returnJSONArray(new JSONArray(), "", cqc.getSkip_totalCount());
            return DpUtils.returnJSONArray(result, cqc.getSkip_totalCount());
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }

    public static void checkTypes(String pjId, ArrayList<String> types, String id) throws Exception {
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        for (int i = 0; i < types.size(); ++i) {
            String type = types.get(i);
            if (id.startsWith(Const.OBJ_TYPE_BUILDING) && (type.equals(Const.OBJ_TYPE_PROJECT) || type.startsWith(Const.OBJ_TYPE_VO))) // building 不能查项目, 和VO
            {
                throw new Exception("不支持的类型:" + type);
            }
            if (id.startsWith(Const.OBJ_TYPE_FLOOR) && !(type.equals(Const.OBJ_TYPE_FLOOR) || type.equals(Const.OBJ_TYPE_SPACE)
                    || type.equals(Const.OBJ_TYPE_ISPACE)))
            //|| EqStaticInfo.familySet.contains(type)))   // 楼层只能查楼层或者空间, 资产.
            {
                throw new Exception("不支持的类型:" + type);
            }
            if (allTypes.contains(type) || eqStaticInfo.getSysSet().contains(type) || eqStaticInfo.getEqSet().contains(type)) {
                continue;
            }
            throw new Exception("不支持的类型:" + type);
        }
    }

    @Path("/batch_update")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String batchUpdate(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(json);
            HashMap<String, HashSet<String>> idInfos = new HashMap<>();
            if (cqc.isCoverInfos()) {
                JSONArray criterias = (JSONArray) json.get("criterias");
                for (Object criteria : criterias) {
                    JSONObject singleObj = (JSONObject) criteria;
                    if (singleObj.get("id") == null || idInfos.containsKey(singleObj.get("id").toString()) || !DpUtils.checkId(singleObj.get("id").toString()))
                        throw new Exception("请检查Id!");
                    JSONObject infos = (JSONObject) singleObj.get("infos");
                    HashSet<String> infoSet = new HashSet<>(infos.keySet());
                    idInfos.put(singleObj.get("id").toString(), infoSet);
                }
            }
            ArrayList<String> error = ObjectUtil.batchUpdate(projectId, (JSONArray) json.get("criterias"), true, false, true, cqc);
            if (cqc.isCoverInfos()) {
                PropertyUtil.syncInfos(projectId.substring(2), idInfos);
            }
            if (error.size() > 0) {
                StringBuilder sb = new StringBuilder();
                for (String str : error)
                    sb.append(str).append('|');
                sb.deleteCharAt(sb.length() - 1);
                return DpUtils.errorJsonMsg(sb.toString());
            }
            return DpUtils.successJsonMsg("");
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }

    @Path("/query_part_info")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryPartInfo(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        Hashtable<String, Object> infoMap = new Hashtable<>(); //id+"|"+infoPointCode;
        String now = CommonUtil.getTime();
        try {
            JSONObject json = JSONObject.parseObject(jsonStr);
            if (json.get("time") != null) {
                now = json.get("time").toString();
            }
            JSONArray criterias = (JSONArray) json.get("criterias");
            for (Object o : criterias) {
                JSONObject criteria = (JSONObject) o;
//                CommonUtil.rewriteCriteria(criteria, "id");
                DpUtils.rewriteCriteria(criteria, "id", true);
                criteria.put(ObjInfosTable.KEY_INFO_ID, criteria.get("code"));
                criteria.remove("code");
            }
            JSONObject result = CommonUtil.combine_query(HBaseTable.obj_infos, criterias);
            JSONArray content = (JSONArray) result.get(Const.JSON_FIELD_Content);
            for (int i = 0; i < content.size(); ++i) {
                JSONObject node = (JSONObject) content.get(i);
                String objId = CommonUtil.combineId((String) node.get(ObjInfosTable.KEY_PJ_ID), (String) node.get(ObjInfosTable.KEY_OBJ_TYPE), (String) node.get(ObjInfosTable.KEY_OBJ_ID));
                String infoId = (String) node.get(ObjInfosTable.KEY_INFO_ID);
                String currTime = node.get(ObjInfosTable.KEY_TIME).toString();
                //1.获取比传入时间小，并且在所有历史中时间最大的信息点，放入map中
                if (!infoMap.containsKey(objId + "|" + infoId) && currTime.compareTo(now) < 0) {
                    infoMap.put(objId + "|" + infoId, node);
                } else if (infoMap.containsKey(objId + "|" + infoId)) {
                    String preTime = ((JSONObject) infoMap.get(objId + "|" + infoId)).get(ObjInfosTable.KEY_TIME).toString();
                    if (currTime.compareTo(preTime) > 0 && currTime.compareTo(now) < 0) {
                        infoMap.put(objId + "|" + infoId, node);
                    }
                }//1.end
            }
            JSONArray reContent = JSONObject.parseObject(jsonStr).getJSONArray("criterias");
            for (int i = 0; i < reContent.size(); ++i) {
                JSONObject obj = (JSONObject) reContent.get(i);
                Object infoNode = infoMap.get(obj.get("id").toString() + "|" + obj.get("code").toString());
                if (infoNode == null) {
                    obj.put("data", null);
                } else {
                    obj.put("data", CommonUtil.getValue((JSONObject) infoNode));
                }
            }
            return DpUtils.returnJSONArray(reContent, "");
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }

    @Path("/move")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String move(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/objectMoveSchema.json");
            if (validateInfo != null && validateInfo.length() != 0)
                return DpUtils.errorJsonMsg(validateInfo);
        } catch (Exception ex) {
            return DpUtils.errorJsonMsg("输入数据格式错误!");
        }
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        JSONArray pairs = (JSONArray) jsonObject.get("criterias");
        if (pairs.size() == 0)
            return DpUtils.successJsonMsg("");
        JSONArray errors = new JSONArray();
        HashMap<String, JSONObject> moveIdMap = new HashMap<>();
        //2019-11-13修改，系统可以在多个建筑下
        HashMap<String, Set<String>> sysIdMap = new HashMap<>();
        Set<String> allIds = new HashSet<>();
        try {
            for (int i = pairs.size() - 1; i > -1; --i) {
                JSONObject single = (JSONObject) pairs.get(i);
                String moveId = Strings.nullToEmpty((String) single.get("moveId"));
                String toId = Strings.nullToEmpty((String) single.get("toId"));
                // 检查是否符合移动规则
                if (!ObjectUtil.checkMoveType(moveId, toId)) {
                    PropertyUtil.moveToError(pairs, i, errors, "id错误或不允许的类型移动!");
                    continue;
                }
                if(moveId.startsWith("Sy")){
                    if(!sysIdMap.keySet().contains(moveId)){
                        sysIdMap.put(moveId, new HashSet<>());
                    }
                    sysIdMap.get(moveId).add(toId);
                }else if (moveIdMap.containsKey(moveId)) {
                    PropertyUtil.moveToError(pairs, i, errors, "moveId重复!");
                    continue;
                }
                moveIdMap.put(moveId, single);
                if (!allIds.contains(moveId))
                    allIds.add(moveId);
                if (toId.length() != 0 && !allIds.contains(toId))
                    allIds.add(toId);
            }
            // 检查id对象是否valid
            if (!ObjectUtil.filterValid(projectId.substring(2), allIds, true, null))
                throw new Exception("连接错误");
            List<SubsetEntity> list = new ArrayList<>();
            for (String moveId : moveIdMap.keySet()) {
                JSONObject single = moveIdMap.get(moveId);
                String toId = Strings.nullToEmpty((String) single.get("toId"));
                if (!allIds.contains(moveId) || (toId.length() != 0 && !allIds.contains(toId))) {
                    single.put("error", "id不存在或已废除!");
                    errors.add(single);
                } else {
                    SubsetEntity se = new SubsetEntity(toId.length() == 0 ? null : toId, moveId);
                    list.add(se);
                }
            }
            //2019-11-13修改，系统可以在多个建筑下
            sysIdMap.forEach((moveId, toIds) -> {
                toIds.forEach(toId -> {
                    if (!allIds.contains(moveId) || (toId.length() != 0 && !allIds.contains(toId))) {
                        errors.add(new JSONObject().fluentPut("moveId", moveId).fluentPut("toId", toId).fluentPut("error", "id不存在或已废除!"));
                    } else {
                        SubsetEntity se = new SubsetEntity(toId.length() == 0 ? null : toId, moveId);
                        list.add(se);
                    }
                });
            });
            if (list.size() == 0)
                return DpUtils.batchReturn(false, "", errors);
            // 修改关系, 实现move
            if (!SubsetUtil.modify(projectId, list))
                throw new Exception("关系修改失败!");
            return DpUtils.batchReturn(true, "", errors);
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }

    @Path("/outside_query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String outsideGraphQuery(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            String validateInfo = DpUtils.validateJsonSchema(jsonStr, "jsonSchema/outsideGraphQuery.json");
            if (validateInfo != null && validateInfo.length() != 0)
                return DpUtils.errorJsonMsg(validateInfo);
        } catch (Exception ex) {
            return DpUtils.errorJsonMsg("输入数据错误!");
        }
        try {
            JSONObject query = JSONObject.parseObject(jsonStr);
            CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(query);
            JSONObject criteriasNode = (JSONObject) query.get("criteria");
            String id = checkIdNode(projectId, criteriasNode);
            cqc.setDirectOnlyId(id);
            String graphId = Strings.nullToEmpty((String) criteriasNode.get("graphId"));
            String graphType = Strings.nullToEmpty((String) criteriasNode.get("graphType"));
            String relType = Strings.nullToEmpty((String) criteriasNode.get("relType"));
            String fromId = Strings.nullToEmpty((String) criteriasNode.get("fromId"));
            String toId = Strings.nullToEmpty((String) criteriasNode.get("toId"));
            if (relType.length() == 0)
                relType = "1";
            if (criteriasNode.containsKey("relType") && criteriasNode.get("relType") == null)
                relType = null;
            boolean isExclude = true;
            // side指定关系类型的fromId还是toId. -1 是fromId, 1是toId, 0 是两边都有
            long side = criteriasNode.get("side") == null ? 0L : criteriasNode.getLongValue("side");
            Set<String> typeSet = new HashSet<>();
            JSONArray typeArr = (JSONArray) criteriasNode.get("type");
            addType(projectId, typeArr, typeSet);
            if (graphId.length() == 0 && graphType.length() == 0)
                throw new Exception("graphId和graphType类型至少需要一个");
            // 获取图id
            if (graphId.length() == 0) {
                graphId = OutsideGraphQueryProcessor.getDefaultGraphId(projectId, graphType);
            }

            if (criteriasNode.get("exclude") != null && criteriasNode.get("exclude").equals(false)) {
                isExclude = false;
            }
            JSONArray result = OutsideGraphQueryProcessor.Query(projectId, id, graphId, relType, fromId, toId, side, typeSet, isExclude, cqc);

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

    public static void addType(String pjId, JSONArray typeArr, Set<String> typeSet) throws Exception {
        if (typeArr == null || typeArr.size() == 0)
            throw new NoTypeException("key: type缺失");
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        for (int i = 0; i < typeArr.size(); ++i) {
            String type = (String) typeArr.get(i);
            if (type == null || type.trim().length() == 0)
                continue;
            boolean isAllowed = false;
            if (allTypes.contains(type)) {
                if (!type.equals("Pj") && !type.equals("Bd")) {
                    isAllowed = true;
                }
            } else if (eqStaticInfo.getEqSet().contains(type)) {
                isAllowed = true;
            } else if (eqStaticInfo.getEcSet().contains(type)) {
                isAllowed = true;
            } else if (eqStaticInfo.getSysSet().contains(type)) {
                isAllowed = true;
            } else if (eqStaticInfo.getFamilySet().contains(type)) {
                isAllowed = true;
            } else if (bussinessSpaceTypeMap.containsKey(type)) {
                isAllowed = true;
            }
            if (!isAllowed)
                throw new Exception("不允许的类型:" + type);
            if (!typeSet.contains(type))
                typeSet.add(type);
        }
        if (typeSet.size() == 0)
            throw new Exception("没有要查找的类型");
    }

    public static boolean addRelType(String pjId, JSONArray typeArr, Set<String> typeSet) throws Exception {
        if (typeArr == null || typeArr.size() == 0)
            throw new NoTypeException("key: type缺失");
        boolean hasDetailedType = false;
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        for (int i = 0; i < typeArr.size(); ++i) {
            String type = (String) typeArr.get(i);
            if (type == null || type.trim().length() == 0)
                continue;
            boolean isAllowed = false;
            if (allTypes.contains(type)) {
                isAllowed = true;
            } else if (eqStaticInfo.getEqSet().contains(type)) {
                hasDetailedType = true;
                isAllowed = true;
            } else if (eqStaticInfo.getEcSet().contains(type)) {
                isAllowed = true;
                hasDetailedType = true;
            } else if (eqStaticInfo.getSysSet().contains(type)) {
                isAllowed = true;
                hasDetailedType = true;
            } else if (eqStaticInfo.getFamilySet().contains(type)) {
                isAllowed = true;
                hasDetailedType = true;
            } else if (bussinessSpaceTypeMap.containsKey(type)) {
                isAllowed = true;
                hasDetailedType = true;
            }
            if (!isAllowed)
                throw new Exception("不允许的类型:" + type);
            if (!typeSet.contains(type))
                typeSet.add(type);
        }
        if (typeSet.size() == 0)
            throw new Exception("没有要查找的类型");
        return hasDetailedType;
    }

    public static String checkIdNode(String projectId, JSONObject criteriasNode) throws Exception {
        if (criteriasNode.get("id") != null && criteriasNode.get("id").toString().length() > 0) {
            if (criteriasNode.get("id").toString().startsWith("Bd") || criteriasNode.get("id").toString().startsWith("Pj")
                    || criteriasNode.get("id").toString().startsWith("Fl")) {
                if (DpUtils.checkId(criteriasNode.get("id").toString())) {
                    return criteriasNode.get("id").toString();
                } else
                    throw new Exception("id非法");
            } else
                throw new Exception("id不允许");
        }
        return projectId;
    }

    @Path("/rel_query")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String relationQuery(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            JSONObject query = JSONObject.parseObject(jsonStr);
            CommonQueryCriteria cqc = CommonUtil.generateCommonQueryCriteria(query);
            JSONObject criteriasNode = (JSONObject) query.get("criteria");
            RelationCriteria relation = JSONObject.parseObject(criteriasNode.toJSONString(), RelationCriteria.class);
            relation.processFromToId();
            Set<String> typeSet = new HashSet<>();
            JSONArray typeArr = (JSONArray) criteriasNode.get("type");
            boolean hasDetailedType = false;
            try {
                hasDetailedType = addRelType(projectId, typeArr, typeSet);
            } catch (NoTypeException noType) {
                hasDetailedType = false;
            }
            if ((relation.getGraphId() == null || relation.getGraphId().length() == 0) && (relation.getGraphType() == null || relation.getGraphType().length() == 0))
                throw new Exception("graphId和graphType类型至少需要一个");
            // 获取图id
            if (relation.getGraphId() == null || relation.getGraphId().length() == 0) {
                String graphId = OutsideGraphQueryProcessor.getDefaultGraphId(projectId, relation.getGraphType());
                relation.setGraphId(graphId);
            }

            Set<String> relResult = RelationUtil.getRelationIdSet(CommonMethods.getProject(projectId, false), relation);
            // 筛选详细类型
            if (hasDetailedType) {
                DpUtils.filterDetailedType(CommonMethods.getProject(projectId, false), relResult, typeSet);
            } else {
                DpUtils.filterMainType(relResult, typeSet);
            }
            JSONArray criterias = new JSONArray();
            for (String id : relResult) {
                JSONObject idObj = new JSONObject();
                idObj.put("id", id);
                criterias.add(idObj);
            }
            EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
            JSONArray result = CommonUtil.batchQuerySelfInfo(projectId.substring(2), criterias, cqc, eqStaticInfo);
            if (cqc.getNodata())
                return DpUtils.returnJSONArray(result, "", cqc.getCount());
            return DpUtils.returnJSONArray(result, cqc.getSkip_totalCount());
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }

    /**
     * 返回带有实时数据的物理对象查询
     *
     * @param projectId
     * @param jsonStr
     * @return
     */
    @Path("/query_with_param")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String queryWithParam(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        //1.查询物理世界对象
        JSONObject query = JSONObject.parseObject(jsonStr);
        String objId = query.getString("id");
        query.remove("id");
        query.put("historyInfos", false);
        JSONArray criterias = JSONObject.parseArray("[{\"id\":\"" + objId + "\"}]");
        query.put("criterias", criterias);
        JSONObject resp = JSONObject.parseObject(batchQueryById(projectId, query));
        if (resp.getJSONArray("Content") == null || resp.getJSONArray("Content").size() == 0) {
            return DpUtils.successJsonMsg("查询的对象不存在");
        }
        JSONObject dpObj = resp.getJSONArray("Content").getJSONObject(0);
        //2.查询实时数据
        JSONObject infosNode = dpObj.getJSONObject("infos");
        criterias = new JSONArray();
        for (String key : infosNode.keySet()) {
            JSONObject one = new JSONObject();
            one.put("id", objId);
            one.put("code", key);
            criterias.add(one);
        }
        query = new JSONObject();
        query.put("criterias", criterias);
        resp = JSONObject.parseObject(new StatusData().batchQueryParam(projectId, null, query.toString()));
        JSONArray content = resp.getJSONArray("Content");
        Map<String, JSONObject> dataMap = new HashMap<>();//infoCode-> dataNode
        if (content != null) {
            for (int i = 0; i < content.size(); ++i) {
                JSONObject one = content.getJSONObject(i);
                if (one.containsKey("data")) {
                    JSONObject dataNode = new JSONObject();
                    dataNode.put("data", one.get("data"));
                    dataNode.put("receivetime", one.get("receivetime"));
                    dataMap.put(one.getString("code"), dataNode);
                }
            }
        }

        Set<String> infoCodeCopy = new HashSet<>(infosNode.keySet());

        for (String info : infoCodeCopy) {
            JSONObject oneInfo = new JSONObject();
            if (dataMap.containsKey(info)) {
                oneInfo = dataMap.get(info);
            }
            oneInfo.put("value", infosNode.get(info));
            infosNode.put(info, oneInfo);
        }

        return DpUtils.successJsonResp("", dpObj).toString();
    }

    /**
     * 返回带有实时数据的物理对象查询
     *
     * @param projectId
     * @param jsonStr
     * @return
     */
    @Path("/qrcode/put")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String generateQRCodeForObjects(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) {
        try {
            JSONObject post = JSONObject.parseObject(jsonStr);
            JSONObject criteriaNode = post.getJSONObject("criteria");
            JSONArray idArray = criteriaNode.getJSONArray("ids");
            if (idArray == null || idArray.size() == 0)
                throw new Exception("ids数组异常");
            int logoLength = 60, qrCodeLength = 400;
            Image logo = null;
            boolean isOverwrite = false;
            if (criteriaNode.getBoolean("isOverwrite") != null) {
                isOverwrite = criteriaNode.getBooleanValue("isOverwrite");
            }
            // 如果指定QRCode的边长
            Integer tmpLength = criteriaNode.getInteger("qrCodeSize");
            if (tmpLength != null) {
                if (QRCodeUtil.isQRSizeQualified(tmpLength)) {
                    qrCodeLength = tmpLength;
                } else
                    throw new Exception("qrCodeSize不在范围内");
            }
            // 如果存在内部logo图
            String tmpUrl = criteriaNode.getString("logoImageUrl");
            if (tmpUrl != null && tmpUrl.length() > 0) {
                logo = QRCodeUtil.getImage(tmpUrl);
                if (logo != null) {
                    Integer tmpLogoLength = criteriaNode.getInteger("logoSize");
                    if (tmpLogoLength != null) {
                        if (QRCodeUtil.isLogoSizeQualified(qrCodeLength, tmpLogoLength)) {
                            logoLength = tmpLogoLength;
                        } else
                            throw new Exception("logoSize不在范围内");
                    }
                }
            }
            // 筛选id, 验证是否合法, 以及是否valid
            Map<String, String> errorInfo = new HashMap<>();
            Set<String> idSet = new HashSet<>(Arrays.asList(idArray.toArray(new String[0])));
            for (String id : idSet) {
                if(id.startsWith(Const.OBJ_TYPE_PROPERTY)){
                    //资产不做校验
                    continue;
                }
                if (!DpUtils.checkId(projectId, id))
                    errorInfo.put(id, "不是预期id");
            }
            idSet.removeAll(errorInfo.keySet());
            boolean noException = ObjectUtil.filterValid(CommonMethods.getProject(projectId, false), idSet, true, null);
            if (!noException)
                throw new Exception("数据库访问异常");
            // 检验对象id是否支持QRCode  验证是否是同一个项目内的对象
            for (String id : idSet) {
                if (CommonMethods.getQRCodeKeyById(id) == null)
                    errorInfo.put(id, "该对象不支持二维码");
            }
            idSet.removeAll(errorInfo.keySet());
            if (idSet.size() == 0)
                return DpUtils.successJsonMsg("");
            // 提交对象到oss
            Map<String, String> idFilekeyMap = new HashMap<>();
            for (String id : idSet)
                idFilekeyMap.put(id, id + "QR");
            QRCodeObj qr = new QRCodeObj(idFilekeyMap, qrCodeLength, logoLength, isOverwrite, logo);
            qr.submit(errorInfo);
            idFilekeyMap.keySet().removeAll(errorInfo.keySet());
            // 将成功上传二维码的对象修改二维码信息点
            JSONArray updateCriteria = CommonMethods.composeUpdateQRCodeArray(idFilekeyMap);
            ObjectUtil.batchUpdate(projectId, updateCriteria, false, false, true, new CommonQueryCriteria());
            return DpUtils.successJsonMsgWithErrorInfo(errorInfo, "");
        } catch (Exception ex) {
            ex.printStackTrace();
            return DpUtils.errorJsonMsg(ex.getMessage());
        }
    }

    @Path("/change_category")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String changeCate(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr) throws Exception {
        JSONArray errs = new JSONArray();
        JSONArray cris = new JSONArray();
        JSONArray sets = new JSONArray();
        EqStaticInfo eqStaticInfo = new EqStaticInfo(projectId);
        JSONArray arr = JSONObject.parseObject(jsonStr).getJSONArray("criterias");
        for(int i = 0; i < arr.size(); i++){
            JSONObject item = arr.getJSONObject(i);
            String id = item.getString("id");
            if(id.toLowerCase().startsWith("eq")){
                if(!eqStaticInfo.getEqSet().contains(item.getString("category"))){
                    errs.add(item.fluentPut("error", item.getString("category") + " not existed!"));
                }
                cris.add(new JSONObject().fluentPut(ObjectTable.KEY_PJ_ID, id.substring(2, 12)).fluentPut(ObjectTable.KEY_OBJ_ID, id.substring(12)).fluentPut(ObjectTable.KEY_OBJ_TYPE, "Eq"));
            }else if(id.toLowerCase().startsWith("sy")){
                if(!eqStaticInfo.getSysSet().contains(item.getString("category"))){
                    errs.add(item.fluentPut("error", item.getString("category") + " not existed!"));
                }
                cris.add(new JSONObject().fluentPut(ObjectTable.KEY_PJ_ID, id.substring(2, 12)).fluentPut(ObjectTable.KEY_OBJ_ID, id.substring(12)).fluentPut(ObjectTable.KEY_OBJ_TYPE, "Sy"));
            }else if(id.toLowerCase().startsWith("ec")){
                if(!eqStaticInfo.getEcSet().contains(item.getString("category"))){
                    errs.add(item.fluentPut("error", item.getString("category") + " not existed!"));
                }
                cris.add(new JSONObject().fluentPut(ObjectTable.KEY_PJ_ID, id.substring(2, 12)).fluentPut(ObjectTable.KEY_OBJ_ID, id.substring(12)).fluentPut(ObjectTable.KEY_OBJ_TYPE, "Ec"));
            }else if(id.toLowerCase().startsWith("tl")){
                if(!TlStaticInfo.getCode2name().keySet().contains(item.getString("category"))){
                    errs.add(item.fluentPut("error", item.getString("category") + " not existed!"));
                }
                cris.add(new JSONObject().fluentPut(ObjectTable.KEY_PJ_ID, id.substring(2, 12)).fluentPut(ObjectTable.KEY_OBJ_ID, id.substring(12)).fluentPut(ObjectTable.KEY_OBJ_TYPE, "Tl"));
            }else if(id.toLowerCase().startsWith("cs")){
                if(!CsStaticInfo.getCode2name().keySet().contains(item.getString("category"))){
                    errs.add(item.fluentPut("error", item.getString("category") + " not existed!"));
                }
                cris.add(new JSONObject().fluentPut(ObjectTable.KEY_PJ_ID, id.substring(2, 12)).fluentPut(ObjectTable.KEY_OBJ_ID, id.substring(12)).fluentPut(ObjectTable.KEY_OBJ_TYPE, "Cs"));
            }

            sets.add(new JSONObject().fluentPut(ObjectTable.COL_SUBTYPE, item.getString("category")));
        }
        if(errs.size() != 0){
            return  DpUtils.errorJson("").fluentPut("Error", errs).toString();
        }
        if(cris.size() > 0){
            return CommonUtil.update(true, HBaseTable.objects, cris, sets).toString();
        }
        return  DpUtils.errorJson("输入格式不对！").toString();
    }
}
