package com.sagacloud.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSException;
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.CustomInfoCode;
import com.sagacloud.endpoints.Dictionary;
import com.sagacloud.endpoints.Equipment;
//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.jsonHelper.infoPoint.InfoPoint;
import com.sagacloud.utils.tables.CtmNodeTable;
import com.sagacloud.utils.tables.HBaseTable;
import com.sagacloud.utils.tables.InfocodeSchemeTable;
import org.json.*;
import org.omg.CORBA.COMM_FAILURE;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

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

    public final static String prefix = "ctm-";
    //json路径 -> 信息点数组
    public static Hashtable<String, JSONArray> infoCodeMap = new Hashtable<>();
    public static HashSet<String> firstTagSet = new HashSet<>();
    public static HashSet<String> objTypeSet = new HashSet<>();
    public static Hashtable<String, String> jsonToColumnMap = new Hashtable<>();
    public static Hashtable<String, String> columnToJsonMap = new Hashtable<>();
    public static Hashtable<String, String> typeToPathMap = new Hashtable<>();

    public final static String basePath = "InfoCode2/";
    public final static String eqFamilyPath = "property/eqFamily/";
    public final static String generalInfoBasePath = "property/InfoCode/";
    public final static String projectPath = generalInfoBasePath + "project.json";
    public final static String buildingPath = generalInfoBasePath + "building.json";
    public final static String floorPath = generalInfoBasePath + "floor.json";
    public final static String spacePath = generalInfoBasePath + "space/space.json";
    public final static String ispacePath = generalInfoBasePath + "space/ispace.json";
    public final static String shaftPath = generalInfoBasePath + "shaft.json";
    public final static String sysGenPath = generalInfoBasePath + "system-general.json";
    public final static String equipGenPath = generalInfoBasePath + "equipment-general.json";
    public final static String componentGenPath = generalInfoBasePath + "component-general.json";
    public final static String VOPath = generalInfoBasePath + "VO.json";
    public final static String consumablePath = generalInfoBasePath + "consumable/consumable.json";
    public final static String toolPath = generalInfoBasePath + "tool/tool.json";
    public final static String consumableInfoPath = generalInfoBasePath + "consumable/";
    public final static String toolInfoPath = generalInfoBasePath + "tool/";

    static {
        firstTagSet.add("静态参数");
        firstTagSet.add("反馈参数");
        firstTagSet.add("报警参数");
        firstTagSet.add("设定参数");

        objTypeSet.add("project");
        objTypeSet.add("building");
        objTypeSet.add("floor");
        objTypeSet.add("space");
        objTypeSet.add("ispace");
        objTypeSet.add("shaft");
        objTypeSet.addAll(PhysicalObject.bussinessSpaceTypeMap.keySet());//业务空间类型
        objTypeSet.addAll(Arrays.asList("VOBd", "VOCu", "VOEi", "VOTn", "VOZn", "VOGp", "VOCt", "VOBc", "VOSe", "VOSc",
                "VOSh", "VOSw", "VOSg", "VOSf", "VOSv", "VOBr", "VOMt"));

        jsonToColumnMap.put("firstTag", InfocodeSchemeTable.FIRST_TAG);
        columnToJsonMap.put(InfocodeSchemeTable.FIRST_TAG, "firstTag");
        jsonToColumnMap.put("secondTag", InfocodeSchemeTable.SECOND_TAG);
        columnToJsonMap.put(InfocodeSchemeTable.SECOND_TAG, "secondTag");
        jsonToColumnMap.put("infoPointCode", InfocodeSchemeTable.INFO_POINT_CODE);
        columnToJsonMap.put(InfocodeSchemeTable.INFO_POINT_CODE, "infoPointCode");
        jsonToColumnMap.put("infoPointName", InfocodeSchemeTable.INFO_POINT_NAME);
        columnToJsonMap.put(InfocodeSchemeTable.INFO_POINT_NAME, "infoPointName");
        jsonToColumnMap.put("unit", InfocodeSchemeTable.UNIT);
        columnToJsonMap.put(InfocodeSchemeTable.UNIT, "unit");
        jsonToColumnMap.put("dataType", InfocodeSchemeTable.DATA_TYPE);
        columnToJsonMap.put(InfocodeSchemeTable.DATA_TYPE, "dataType");
        jsonToColumnMap.put("inputMode", InfocodeSchemeTable.INPUT_MODE);
        columnToJsonMap.put(InfocodeSchemeTable.INPUT_MODE, "inputMode");
        jsonToColumnMap.put("dataSource", InfocodeSchemeTable.DATA_SOURCE);
        columnToJsonMap.put(InfocodeSchemeTable.DATA_SOURCE, "dataSource");
        jsonToColumnMap.put("note", InfocodeSchemeTable.NOTE);
        columnToJsonMap.put(InfocodeSchemeTable.NOTE, "note");
        jsonToColumnMap.put("func-id", InfocodeSchemeTable.FUNC_ID);
        columnToJsonMap.put(InfocodeSchemeTable.FUNC_ID, "func-id");

        typeToPathMap.put("project", projectPath);
        typeToPathMap.put("building", buildingPath);
        typeToPathMap.put("floor", floorPath);
        typeToPathMap.put("space", spacePath);
        typeToPathMap.put("ispace", ispacePath);
        typeToPathMap.put("shaft", shaftPath);
        typeToPathMap.put("sy-gen", sysGenPath);
        typeToPathMap.put("eq-gen", equipGenPath);
        typeToPathMap.put("consumable", consumablePath);
        typeToPathMap.put("tool", toolPath);
//        typeToPathMap.put("ec-gen", componentGenPath);
    }

    public static Boolean checkRange(HashSet set, String key) {
        return set.contains(key);
    }


    public static void format(Object obj, Boolean autoComplete) {//将json的key变为表格的列名
        if (obj instanceof JSONObject) {
            formatOne((JSONObject) obj, autoComplete);
        } else if (obj instanceof JSONArray) {
            for (int i = 0; i < ((JSONArray) obj).size(); ++i) {
                formatOne((JSONObject) ((JSONArray) obj).get(i), autoComplete);
            }
        }
    }

    //    private static void formatOne(JSONObject json, Boolean autoComplete) {
//        if (autoComplete) {
//            for (String key : jsonToColumnMap.keySet()) {
//                if (!json.containsKey(key)) {
//                    json.put(key, "");
//                }
//            }
//        }
//        Set<String> tempSet = new HashSet<>(json.keySet());
//        for (String key : tempSet) {
//            if (!jsonToColumnMap.containsKey(key))
//                continue;
//            String value = Strings.nullToEmpty((String) json.get(key));
//            json.remove(key);
//            json.put(jsonToColumnMap.get(key), value);
//        }
//    }
    private static void formatOne(JSONObject json, Boolean autoComplete) {
        formatDataSource(json);
        if (autoComplete) {
            for (String key : jsonToColumnMap.keySet()) {
                if (!json.containsKey(key)) {
                    json.put(key, "");
                }
            }
        }
        Set<String> tempSet = new HashSet<>(json.keySet());
        for (String key : tempSet) {
            if (!jsonToColumnMap.containsKey(key))
                continue;
            String value = Strings.nullToEmpty((String) json.get(key));
            json.remove(key);
            json.put(jsonToColumnMap.get(key), value);
        }
    }

    private static boolean isEnumPattern(String s) {
        String pattern1 = "^((\\d+\\.)+\\s+\\S+\\s+)+$";//枚举值正则
        if (s == null || s.length() == 0)
            return false;
        else {
            s = s + " ";
            return s.matches(pattern1);
        }
    }

    private static void formatDataSource(JSONObject json) {
        if (json.get("dataSource") == null || !isEnumPattern((String) json.get("dataSource")))
            return;
        json.put("dataSource", getDataSOurce((json.get("dataSource").toString())).toString());
    }

    private static void deformatDataSource(JSONObject json) {
        if (json.get("dataSource") == null) {
            return;
        }
        try {
            JSONArray arr = JSONObject.parseArray(json.getString("dataSource"));
            json.put("dataSource", arr);
        } catch (Exception e) {
            return;
        }
    }

    private static Object getDataSOurce(String source) {
        String[] s = source.split("[\\s]+");
        if (s.length <= 1)
            return source;
        JSONArray arr = new JSONArray();
        HashMap<String, JSONObject> numToObjMap = new HashMap<>();
        for (int i = 0; i < s.length; ++i) {
            if (isTitleNum(s[i])) {
                String plainNum = s[i];
                StringBuilder nameBuilder = new StringBuilder();
                for (int k = i + 1; k < s.length && !isTitleNum(s[k]); ++k, ++i) {
                    nameBuilder.append(s[k]).append(" ");
                }
                String name = nameBuilder.toString().trim();
                String[] nums = plainNum.split("\\.");
                if (nums.length == 1) {//是第一级
                    JSONObject json = new JSONObject();
                    json.put("code", nums[0]);
                    json.put("name", name);
                    arr.add(json);
                    numToObjMap.put(nums[0], json);
                } else {//不是第一级标签
                    StringBuilder sb = new StringBuilder();
                    String parentNum = "";
                    String currentNum = "";
                    for (int j = 0; j < nums.length; ++j) {
                        sb.append(nums[j]);
                        if (j != nums.length - 1) {
                            sb.append(".");
                        } else {
                            parentNum = sb.toString();
                            parentNum = parentNum.substring(0, parentNum.lastIndexOf("."));
                        }
                    }
                    currentNum = sb.toString().trim();
                    JSONObject json = new JSONObject();
                    json.put("code", currentNum);
                    json.put("name", name);
                    numToObjMap.put(currentNum, json);

                    JSONObject parentNode = numToObjMap.get(parentNum);
                    if (!parentNode.containsKey("content")) {
                        parentNode.put("content", new JSONArray());
                    }
                    JSONArray parentContent = (JSONArray) parentNode.get("content");
                    parentContent.add(json);
                }
            }
        }

        return arr;
    }

    private static Boolean isTitleNum(String s) {
        return s.contains(".") && s.matches("[\\d\\.]+");
    }

    public static void deFormat(Object obj) {//将表格的列名变为json的key
        if (obj instanceof JSONObject) {
            deFormatOne((JSONObject) obj);
        } else if (obj instanceof JSONArray) {
            for (int i = 0; i < ((JSONArray) obj).size(); ++i) {
                deFormatOne((JSONObject) ((JSONArray) obj).get(i));
            }
        }
    }

    private static JSONObject deFormatOne(JSONObject json) {
        Set<String> tempSet = new HashSet<>(json.keySet());
        for (String key : tempSet) {
            if (!columnToJsonMap.containsKey(key))
                continue;
            String value = "";
            if (json.get(key) != null)
                value = (String) json.get(key);
            json.remove(key);
            json.put(columnToJsonMap.get(key), value);
        }
        deformatDataSource(json);
        return json;
    }

    /**
     * @param pjId 不以Pj开头的项目id
     * @param type project,building,floor,space,sy-gen,eq-gen,ec-gen,2位系统编码,4位设备编码,6位部件编码
     * @return 自定义信息点
     */
    public static JSONArray queryCustomInfos(String pjId, String type) throws Exception {
        String jsonStr = CustomInfoCode.queryFollower("Pj" + pjId);
        JSONObject json = JSONObject.parseObject(jsonStr);
        JSONArray content = (JSONArray) json.get("Content");
        if (content.size() == 0)
            return content;
        String schemeId = (String) ((JSONObject) content.get(0)).get(InfocodeSchemeTable.SCHEME_ID);
        json.clear();
        json.put(InfocodeSchemeTable.SCHEME_ID, schemeId);
        json.put(InfocodeSchemeTable.OBJ_TYPE, type);
        json = CommonUtil.query(false, HBaseTable.infocode_scheme_detail, json);
        content = (JSONArray) json.get("Content");
        InfoCodeUtil.deFormat(content);
        CommonUtil.removeField(content, InfocodeSchemeTable.SCHEME_ID);
        CommonUtil.removeField(content, InfocodeSchemeTable.OBJ_TYPE);
        return content;
    }

    /**
     * @param pjId 不以Pj开头的项目id
     * @param type project,building,floor,space,sy-gen,eq-gen,ec-gen,2位系统编码,4位设备编码,6位部件编码
     * @return 数据字典定义好的信息点(包含general信息点)和自定义信息点的组合
     */
    public static JSONArray queryWholeInfosWithCustom(String pjId, String type) throws Exception {
//        JSONArray commonInfos = queryWholeCommonInfos(type);
        JSONArray commonInfos = getInfosForProperty(pjId, type);//对接到种族版数据字典
        JSONArray customInfos = queryCustomInfos(pjId, type);
        commonInfos.addAll(customInfos);
        return commonInfos;
    }


    /**
     * 内部调用方法
     *
     * @param type project,building,floor,space,2位系统编码,3位种族编码,4位设备编码,6位部件编码
     * @return 只返回数据字典定义好的信息点(包含general), 不包含自定义信息点，eg. "project" -> ("CO2" -> json)
     */
    public static HashMap<String, InfoPoint> getWholeCommonInfosMap(String pjId, String type) {
        HashMap<String, InfoPoint> result = new HashMap<>();
        try {
//            JSONArray content = queryWholeCommonInfos(type);
            JSONArray content = getInfosForProperty(pjId, type);//对接到种族版数据字典
            for (int i = 0; i < content.size(); ++i) {
                JSONObject obj = (JSONObject) content.get(i);
                InfoPoint ip = new InfoPoint();
                ip.setInfoPointCode((String) obj.get("infoPointCode"));
                ip.setInfoPointName((String) obj.get("infoPointName"));
                ip.setInputMode((String) obj.get("inputMode"));
                result.put((String) obj.get("infoPointCode"), ip);
            }
            return result;
        } catch (Exception ex) {
            return null;
        }
    }
    
    /**
     * 内部调用方法
     *
     * @param type project,building,floor,space,2位系统编码,3位种族编码,4位设备编码,6位部件编码
     * @return 只返回数据字典定义好的信息点(包含general), 不包含自定义信息点，eg. "project" -> ("CO2" -> json)
     */
    public static HashMap<String, InfoPoint> getWholeCommonInfosMap(String pjId, String type, String ctmDicId) {
        HashMap<String, InfoPoint> result = new HashMap<>();
        try {
//            JSONArray content = queryWholeCommonInfos(type);
            JSONArray content = getInfosForProperty(pjId, type, ctmDicId);//对接到种族版数据字典
            for (int i = 0; i < content.size(); ++i) {
                JSONObject obj = (JSONObject) content.get(i);
                InfoPoint ip = new InfoPoint();
                ip.setInfoPointCode((String) obj.get("infoPointCode"));
                ip.setInfoPointName((String) obj.get("infoPointName"));
                ip.setInputMode((String) obj.get("inputMode"));
                result.put((String) obj.get("infoPointCode"), ip);
            }
            return result;
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 内部调用方法
     *
     * @param pjId  不以Pj开头的项目id
     * @param types project,building,floor,space,2位系统编码,4位设备编码,6位部件编码
     * @return 自定义信息点
     */
    public static HashMap<String, HashMap<String, InfoPoint>> getCustomInfosMap(String pjId, String... types) {
        HashMap<String, HashMap<String, InfoPoint>> map = new HashMap();
        for (String type : types) {
            map.put(type, new HashMap<>());
        }
        try {
            String jsonStr = CustomInfoCode.queryFollower("Pj" + pjId);
            JSONObject json = JSONObject.parseObject(jsonStr);
            if (!json.get("Result").toString().equals("success"))
                return null;
            JSONArray content = (JSONArray) json.get("Content");
            if (content.size() == 0)
                return map;
            String schemeId = (String) ((JSONObject) content.get(0)).get(InfocodeSchemeTable.SCHEME_ID);
            JSONArray criterias = new JSONArray();
            for (String type : types) {
                json = new JSONObject();
                json.put(InfocodeSchemeTable.SCHEME_ID, schemeId);
                json.put(InfocodeSchemeTable.OBJ_TYPE, type);
                criterias.add(json);
            }
            json = CommonUtil.combine_query(HBaseTable.infocode_scheme_detail, criterias);
            if (!json.get("Result").toString().equals("success"))
                return null;
            content = (JSONArray) json.get("Content");
            InfoCodeUtil.deFormat(content);
            CommonUtil.removeField(content, InfocodeSchemeTable.SCHEME_ID);
            for (int i = 0; i < content.size(); ++i) {
                JSONObject obj = (JSONObject) content.get(i);
                String objType = (String) obj.get(InfocodeSchemeTable.OBJ_TYPE);
                HashMap<String, InfoPoint> mapByType = map.get(objType);
                InfoPoint ip = new InfoPoint();
                ip.setInfoPointCode((String) obj.get("infoPointCode"));
                ip.setInfoPointName((String) obj.get("infoPointName"));
                ip.setInputMode((String) obj.get("inputMode"));
                mapByType.put((String) obj.get("infoPointCode"), ip);
            }
            return map;
        } catch (Exception ex) {
            log.info(ex.getMessage());
            return null;
        }
    }

    /**
     * 内部调用方法
     *
     * @param pjId  不以Pj开头的项目id
     * @param types project,building,floor,space,ispace,2位系统编码,3位种族编码,4位设备编码,6位部件编码
     * @return 数据字典和自定义信息点的组合，各类型设备已包含eq-gen
     */
    public static HashMap<String, HashMap<String, InfoPoint>> getWholeInfosWithCustomMap(String pjId, String... types) {
        HashMap<String, HashMap<String, InfoPoint>> map = getCustomInfosMap(pjId, types);
        if (map == null)
            return new HashMap<>();
        
        String ctmDictId = null;
		try {
			ctmDictId = queryDictId(pjId);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
        for (String type : types) {
            HashMap<String, InfoPoint> wholeCommonInfos = getWholeCommonInfosMap(pjId, type, ctmDictId);
            HashMap<String, InfoPoint> mapByType = map.get(type);
            if (mapByType != null) {
                mapByType.putAll(wholeCommonInfos);
            }else {
            	map.put(type, wholeCommonInfos);
            }
        }
        return map;
    }

    public static void clearCache() {
        infoCodeMap.clear();
    }


    //下面是资产管理所用的函数

    /**
     * 根据项目id查询其所用ctmDict
     *
     * @param pjId
     * @return
     * @throws Exception
     */
    public static String queryDictId(String pjId) throws Exception {
        if (pjId == null) {
            return null;
        }
        if (pjId.startsWith("Pj")) {
            pjId = pjId.substring(2);
        }
        JSONObject criteria = new JSONObject().fluentPut("project_id", pjId);
        JSONObject re = CommonUtil.query(false, HBaseTable.ctm_dict_follower, criteria);
        if (re.getJSONArray("Content").size() == 0) {
            return null;
        }
        return re.getJSONArray("Content").getJSONObject(0).getString("dict_id");
    }

    /**
     * @param type project,building,floor,space,sy-gen,eq-gen,ec-gen,2位系统编码,3位种族编码,4位设备编码,6位部件编码
     * @return 系统：系统通用+系统独有；设备/部件：设备通用 + 种族 + 设备独有/部件独有；其他只返回自身
     * @throws Exception
     */
    public static JSONArray getInfosForProperty(String pjId, String type) throws Exception {

        JSONArray result = new JSONArray();
        if (typeToPathMap.containsKey(type)) {//project,building,floor,space,sy-gen,eq-gen,ec-gen,consumable,tool
            JSONArray infos = getSplitInfos(pjId, type);
            CommonUtil.addField(infos, "classification", "0");//0表示没有分类
            result.addAll(infos);
            return result;
        }
        if (PhysicalObject.bussinessSpaceTypeMap.containsKey(type)) {
            JSONArray infos = getSplitInfos(pjId, type);
            CommonUtil.addField(infos, "classification", "0");//0表示没有分类
            result.addAll(infos);
            return result;
        }
        if (type.startsWith(Const.OBJ_TYPE_VO)) {
            result.addAll(getSplitInfos(pjId, type));
            return result;
        }
        //耗材
        if (CsStaticInfo.getCode2name().keySet().contains(type)) {
            JSONArray commonInfos = getSplitInfos(pjId, "consumable");
            JSONArray privInfos = getSplitInfos(pjId, type);
            result.addAll(commonInfos);
            result.addAll(privInfos);
            return result;
        }
        //工具
        if (TlStaticInfo.getCode2name().keySet().contains(type)) {
            JSONArray commonInfos = getSplitInfos(pjId, "tool");
            JSONArray privInfos = getSplitInfos(pjId, type);
            result.addAll(commonInfos);
            result.addAll(privInfos);
            return result;
        }
        String ctmDictId = queryDictId(pjId);
        EqStaticInfo eqStaticInfo = new EqStaticInfo(null);
        //自定义字典中的类型
        if (ctmDictId != null) {
            return getCtmDictWholeInfos(ctmDictId, type, eqStaticInfo);
        }

        if (eqStaticInfo.getSysSet().contains(type)) {//系统
            JSONArray commonInfos = getSplitInfos(pjId, "sy-gen");
            CommonUtil.addField(commonInfos, "classification", "1");//1表示系统通用
            JSONArray sysInfos = getSplitInfos(pjId, type);
            CommonUtil.addField(sysInfos, "classification", "5");//5表示系统独有
            result.addAll(commonInfos);
            result.addAll(sysInfos);
        } else if (eqStaticInfo.getEqSet().contains(type)) {//设备
            JSONArray commonInfos = getSplitInfos(pjId, "eq-gen");
            CommonUtil.addField(commonInfos, "classification", "2");//2表示设备通用
            JSONArray familyInfos = getSplitInfos(pjId, eqStaticInfo.getEqToFamilyMap().get(type));
            CommonUtil.addField(familyInfos, "classification", "4");//4表示种族信息点
            JSONArray eqInfos = getSplitInfos(pjId, type);
            CommonUtil.addField(eqInfos, "classification", "6");//6表示设备独有
            result.addAll(commonInfos);
            result.addAll(familyInfos);
            result.addAll(eqInfos);
        } else if (eqStaticInfo.getEcSet().contains(type)) {//部件
//            JSONArray commonInfos = getSplitInfos("ec-gen");
//            CommonUtil.addField(commonInfos, "classification", "3");//3表示部件通用
//            JSONArray familyInfos = getSplitInfos(EqStaticInfo.eqToFamilyMap.get(type));
            JSONArray commonInfos = getSplitInfos(pjId, "eq-gen");
            CommonUtil.addField(commonInfos, "classification", "2");//3表示设备通用
            JSONArray familyInfos = getSplitInfos(pjId, eqStaticInfo.getEqToFamilyMap().get(type));
            CommonUtil.addField(familyInfos, "classification", "4");//4表示种族信息点
            JSONArray ecInfos = getSplitInfos(pjId, type);
            CommonUtil.addField(ecInfos, "classification", "7");//7表示部件独有
            result.addAll(commonInfos);
            result.addAll(familyInfos);
            result.addAll(ecInfos);
        } else if (eqStaticInfo.getFamilySet().contains(type)) {
            JSONArray commonInfos = new JSONArray();
//            if (EqStaticInfo.familyMap.get(type)) {//设备种族
            commonInfos = getSplitInfos(pjId, "eq-gen");
            CommonUtil.addField(commonInfos, "classification", "2");//2表示设备通用
//            } else {
//                commonInfos = getSplitInfos("ec-gen");
//                CommonUtil.addField(commonInfos, "classification", "3");//3表示部件通用
//            }
            JSONArray familyInfos = getSplitInfos(pjId, type);
            CommonUtil.addField(familyInfos, "classification", "4");//4表示种族信息点
            result.addAll(commonInfos);
            result.addAll(familyInfos);
        }
        return result;
    }
    
    /**
     * @param pjId
     * @param type project,building,floor,space,sy-gen,eq-gen,ec-gen,2位系统编码,3位种族编码,4位设备编码,6位部件编码
     * @param ctmDictId 自定义数据字典id
     * @return 系统：系统通用+系统独有；设备/部件：设备通用 + 种族 + 设备独有/部件独有；其他只返回自身
     * @throws Exception
     */
    public static JSONArray getInfosForProperty(String pjId, String type, String ctmDictId) throws Exception {

        JSONArray result = new JSONArray();
        if (typeToPathMap.containsKey(type)) {//project,building,floor,space,sy-gen,eq-gen,ec-gen,consumable,tool
            JSONArray infos = getSplitInfos(pjId, type);
            CommonUtil.addField(infos, "classification", "0");//0表示没有分类
            result.addAll(infos);
            return result;
        }
        if (PhysicalObject.bussinessSpaceTypeMap.containsKey(type)) {
            JSONArray infos = getSplitInfos(pjId, type);
            CommonUtil.addField(infos, "classification", "0");//0表示没有分类
            result.addAll(infos);
            return result;
        }
        if (type.startsWith(Const.OBJ_TYPE_VO)) {
            result.addAll(getSplitInfos(pjId, type));
            return result;
        }
        //耗材
        if (CsStaticInfo.getCode2name().keySet().contains(type)) {
            JSONArray commonInfos = getSplitInfos(pjId, "consumable");
            JSONArray privInfos = getSplitInfos(pjId, type);
            result.addAll(commonInfos);
            result.addAll(privInfos);
            return result;
        }
        //工具
        if (TlStaticInfo.getCode2name().keySet().contains(type)) {
            JSONArray commonInfos = getSplitInfos(pjId, "tool");
            JSONArray privInfos = getSplitInfos(pjId, type);
            result.addAll(commonInfos);
            result.addAll(privInfos);
            return result;
        }
        EqStaticInfo eqStaticInfo = new EqStaticInfo(null);
        //自定义字典中的类型
        if (ctmDictId != null) {
            return getCtmDictWholeInfos(ctmDictId, type, eqStaticInfo);
        }

        if (eqStaticInfo.getSysSet().contains(type)) {//系统
            JSONArray commonInfos = getSplitInfos(pjId, "sy-gen");
            CommonUtil.addField(commonInfos, "classification", "1");//1表示系统通用
            JSONArray sysInfos = getSplitInfos(pjId, type);
            CommonUtil.addField(sysInfos, "classification", "5");//5表示系统独有
            result.addAll(commonInfos);
            result.addAll(sysInfos);
        } else if (eqStaticInfo.getEqSet().contains(type)) {//设备
            JSONArray commonInfos = getSplitInfos(pjId, "eq-gen");
            CommonUtil.addField(commonInfos, "classification", "2");//2表示设备通用
            JSONArray familyInfos = getSplitInfos(pjId, eqStaticInfo.getEqToFamilyMap().get(type));
            CommonUtil.addField(familyInfos, "classification", "4");//4表示种族信息点
            JSONArray eqInfos = getSplitInfos(pjId, type);
            CommonUtil.addField(eqInfos, "classification", "6");//6表示设备独有
            result.addAll(commonInfos);
            result.addAll(familyInfos);
            result.addAll(eqInfos);
        } else if (eqStaticInfo.getEcSet().contains(type)) {//部件
//            JSONArray commonInfos = getSplitInfos("ec-gen");
//            CommonUtil.addField(commonInfos, "classification", "3");//3表示部件通用
//            JSONArray familyInfos = getSplitInfos(EqStaticInfo.eqToFamilyMap.get(type));
            JSONArray commonInfos = getSplitInfos(pjId, "eq-gen");
            CommonUtil.addField(commonInfos, "classification", "2");//3表示设备通用
            JSONArray familyInfos = getSplitInfos(pjId, eqStaticInfo.getEqToFamilyMap().get(type));
            CommonUtil.addField(familyInfos, "classification", "4");//4表示种族信息点
            JSONArray ecInfos = getSplitInfos(pjId, type);
            CommonUtil.addField(ecInfos, "classification", "7");//7表示部件独有
            result.addAll(commonInfos);
            result.addAll(familyInfos);
            result.addAll(ecInfos);
        } else if (eqStaticInfo.getFamilySet().contains(type)) {
            JSONArray commonInfos = new JSONArray();
//            if (EqStaticInfo.familyMap.get(type)) {//设备种族
            commonInfos = getSplitInfos(pjId, "eq-gen");
            CommonUtil.addField(commonInfos, "classification", "2");//2表示设备通用
//            } else {
//                commonInfos = getSplitInfos("ec-gen");
//                CommonUtil.addField(commonInfos, "classification", "3");//3表示部件通用
//            }
            JSONArray familyInfos = getSplitInfos(pjId, type);
            CommonUtil.addField(familyInfos, "classification", "4");//4表示种族信息点
            result.addAll(commonInfos);
            result.addAll(familyInfos);
        }
        return result;
    }

    /**
     * @param type project,building,floor,space,sy-gen,eq-gen,ec-gen,2位系统编码,3位种族编码,4位设备编码,6位部件编码
     * @return 只获取指定类型的独有信息点，不会进行组合
     */
    private static JSONArray getSplitInfos(String pjId, String type) throws Exception {
//        if (typeToPathMap.size() == 0) {
//            init();
//        }
        if (type == null)
            return new JSONArray();
        if (type.startsWith(Const.OBJ_TYPE_VO)) {
            if (!infoCodeMap.containsKey(type)) {
                JSONObject all = JSONObject.parseObject(OssUtils.getFileAsString(VOPath));
                for (String key : all.keySet()) {
                    infoCodeMap.put(key, (JSONArray) all.get(key));
                }
            }
            if (infoCodeMap.containsKey(type))
                return JSONArray.parseArray(infoCodeMap.get(type).toString());
            else
                return new JSONArray();
        }
        String path = "";
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        if (typeToPathMap.containsKey(type)) {//project,building,floor,space,sy-gen,eq-gen,ec-gen,consumable,tool
            path = typeToPathMap.get(type);
        } else if (eqStaticInfo.getFamilySet().contains(type)) {//种族编码
            path = eqFamilyPath + type + ".json";
        } else if (CsStaticInfo.getCode2name().keySet().contains(type)) {//耗材
            path = consumableInfoPath + type + ".json";
        } else if (TlStaticInfo.getCode2name().keySet().contains(type)) {//工具
            path = toolInfoPath + type + ".json";
        } else if (PhysicalObject.bussinessSpaceTypeMap.containsKey(type)) {
            path = generalInfoBasePath + "space/" + type + ".json";
        } else {//系统，设备，部件
            String major = eqStaticInfo.getCateToMajorMap().get(type);
            if (eqStaticInfo.getSysSet().contains(type)) {// 系统编码
                path = generalInfoBasePath + major + "/" + type + "/" + type + ".json";
            } else if (eqStaticInfo.getEqSet().contains(type)) {//设备编码
                path = generalInfoBasePath + major + "/" + type.substring(0, 2) + "/" + type + ".json";
            } else if (eqStaticInfo.getEcSet().contains(type)) {//部件
                path = generalInfoBasePath + major + "/" + type.substring(0, 2) + "/" + type + ".json";
            }
        }
        return getInfosFromOss(path);
    }


    private static JSONArray getInfosFromOss(String path) throws Exception {
        try {
            if (!infoCodeMap.containsKey(path)) {
                JSONArray all = JSONObject.parseObject(OssUtils.getFileAsString(path)).getJSONArray("all");
                infoCodeMap.put(path, all);
            }
            JSONArray copy = JSONArray.parseArray(infoCodeMap.get(path).toString());
            return copy;
        } catch (Exception e) {
            return new JSONArray();
        }
    }

    /**
     * @param typeSet ["3位种族编码"]，自动添加eq-gen
     * @return (种族编码, eq - gen)->(信息点编码->InfoPoint);各种族中不包含eq-gen
     */
    public static HashMap<String, HashMap<String, InfoPoint>> innerGetFamilyInfos(String pjId, Set<String> typeSet) throws Exception {
        HashMap<String, HashMap<String, InfoPoint>> result = new HashMap<>();
        HashMap<String, JSONArray> type2Arr = new HashMap<>();
        type2Arr.put("eq-gen", getSplitInfos(pjId, "eq-gen"));
        String ctmDictId = queryDictId(pjId);

        for (String type : typeSet) {
            //自定义字典中的类型
            if (ctmDictId != null) {
                type2Arr.put(type, getCtmDictSplitInfos(ctmDictId, type));
            } else {
                type2Arr.put(type, getSplitInfos(pjId, type));
            }
        }
        type2Arr.forEach((t, arr) -> {
            if (!result.containsKey(t)) {
                result.put(t, new HashMap<String, InfoPoint>());
            }
            HashMap<String, InfoPoint> mapByType = result.get(t);
            for (int i = 0; i < arr.size(); ++i) {
                JSONObject info = (JSONObject) arr.get(i);
                InfoPoint ip = new InfoPoint();
                ip.setInfoPointCode((String) info.get("infoPointCode"));
                ip.setInfoPointName((String) info.get("infoPointName"));
                ip.setInputMode((String) info.get("inputMode"));
                mapByType.put(ip.getInfoPointCode(), ip);
            }
        });
        return result;
    }

    /**
     * @param typeA 种族A
     * @param typeB 种族B
     * @return A并B的信息点集合 - B的信息点，即A∪B-B
     */
    public static Set<String> getDistinctInfos(String pjId, String typeA, String typeB) {
        try {
            Set<String> setA = new HashSet<>();
            JSONArray contentA = getInfosForProperty(pjId, typeA);
            for (int i = 0; i < contentA.size(); ++i) {
                setA.add(((JSONObject) contentA.get(i)).get("infoPointCode").toString());
            }
            JSONArray contentB = getInfosForProperty(pjId, typeB);
            for (int i = 0; i < contentB.size(); ++i) {
                setA.remove(((JSONObject) contentB.get(i)).get("infoPointCode").toString());
            }
            return setA;
        } catch (Exception e) {
            e.printStackTrace();
            return new HashSet<>();
        }

    }

    /**
     * @param type project,building,floor,space,sy-gen,eq-gen,ec-gen,2位系统编码,3位种族编码,4位设备编码,6位部件编码
     * @return type的所有信息点
     */
    public static Set<String> getInfosWithGeneralInfo(String pjId, String type) {
        try {
            Set<String> setA = new HashSet<>();
            JSONArray contentA = getInfosForProperty(pjId, type);
            for (int i = 0; i < contentA.size(); ++i) {
                setA.add(((JSONObject) contentA.get(i)).get("infoPointCode").toString());
            }
            return setA;
        } catch (Exception e) {
            e.printStackTrace();
            return new HashSet<>();
        }

    }

    /**
     * 自定义信息点排序
     */
    public final static Comparator infoComparator = new Comparator<JSONObject>() {

        @Override
        public int compare(JSONObject o1, JSONObject o2) {
            String objType1 = o1.get("obj_type").toString();
            String objType2 = o2.get("obj_type").toString();
            String firstTag1 = o1.get("firstTag").toString();
            String firstTag2 = o2.get("firstTag").toString();
            String secongTag1 = o1.get("secondTag").toString();
            String secongTag2 = o2.get("secondTag").toString();
            String infoPointCode1 = o1.get("infoPointCode").toString();
            String infoPointCode2 = o2.get("infoPointCode").toString();
            int re1 = objType1.compareTo(objType2);
            if (re1 != 0) {//比较objType
                return re1;
            } else {//比较firstTag
                int re2 = firstTag1.compareTo(firstTag2);
                if (re2 != 0) {
                    return re2;
                } else {//比较secongTag
                    int re3 = secongTag1.compareTo(firstTag2);
                    if (re3 != 0) {
                        return re2;
                    } else {
                        return infoPointCode1.compareTo(infoPointCode2);
                    }
                }
            }
        }
    };

    public static void sortByTag(JSONArray infos) {
        ArrayList<JSONObject> tempArr = new ArrayList<>();
        for (int i = 0; i < infos.size(); ++i) {
            tempArr.add((JSONObject) infos.get(i));
        }
        tempArr.sort(infoComparator);
        infos.clear();
        for (JSONObject info : tempArr) {
            infos.add(info);
        }
    }


    public static boolean compareValue(Object infoValue, Object filterValue) {
        if (infoValue == null && filterValue == null)
            return true;
        if (infoValue == null && filterValue != null)
            return false;
        if (infoValue != null && filterValue == null)
            return false;
        if (infoValue instanceof String && filterValue instanceof String) {
            if (((String) infoValue).contains((String) filterValue))
                return true;
            return false;
        } else
            return infoValue.equals(filterValue);
    }


    /**
     * 从自定义字典中获取信息点
     *
     * @param dictId
     * @param types
     * @return
     */
    private static Map<String, JSONArray> getCtmDictSplitInfos(String dictId, List<String> types) throws Exception {
        JSONArray cris = new JSONArray();
        Map<String, JSONArray> reMap = new HashMap<>();
        types.forEach(t -> {
            cris.add(new JSONObject().fluentPut(InfocodeSchemeTable.SCHEME_ID, dictId).fluentPut(InfocodeSchemeTable.OBJ_TYPE, t));
            reMap.put(t, new JSONArray());
        });
        JSONArray content = CommonUtil.combine_query(HBaseTable.infocode_scheme_detail, cris).getJSONArray("Content");
        content.forEach(o -> {
            JSONObject item = (JSONObject) o;
            reMap.get(item.getString(InfocodeSchemeTable.OBJ_TYPE)).add(deFormatOne(item));
        });
        return reMap;
    }

    /**
     * 从自定义字典中获取信息点
     *
     * @param dictId
     * @param type
     * @return
     */
    private static JSONArray getCtmDictSplitInfos(String dictId, String type) throws Exception {
        JSONArray content = CommonUtil.query(false, HBaseTable.infocode_scheme_detail,
                new JSONObject().fluentPut(InfocodeSchemeTable.SCHEME_ID, dictId).fluentPut(InfocodeSchemeTable.OBJ_TYPE, type))
                .getJSONArray("Content");
        deFormat(content);
        return content;
    }

    /**
     * 获取自定义字典中设备/种族的信息点
     *
     * @param dictId
     * @param type
     * @return
     * @throws Exception
     */
    public static JSONArray getCtmDictWholeInfos(String dictId, String type, EqStaticInfo eqStaticInfo) throws Exception {
        JSONArray arr = eqStaticInfo.getCtmNodeArr();
        if(arr == null){
            arr = CommonUtil.query(false, HBaseTable.ctm_node,
                    new JSONObject().fluentPut(CtmNodeTable.KEY_DICT_ID, dictId)).getJSONArray("Content");
        }

        String ref = null, family = null;
        boolean include = false;
        for (int i = 0; i < arr.size(); i++) {
            JSONObject node = arr.getJSONObject(i);
            if (node.getString(CtmNodeTable.KEY_CODE).equalsIgnoreCase(type)) {
                include = true;
                ref = node.getString(CtmNodeTable.COL_REF);
                family = node.getString(CtmNodeTable.COL_FAMILY);
                break;
            }
        }
        JSONArray result = new JSONArray();
        //如果没找到节点
        if (!include) {
            return result;
        }
        //资产（种族）节点
        if ((family == null || family.isEmpty()) && type.length() == 3) {
            JSONArray commonInfos = getSplitInfos(null, "eq-gen");
            CommonUtil.addField(commonInfos, "classification", "2");//2表示设备通用
            JSONArray familyInfos = getCtmDictSplitInfos(dictId, type);
            CommonUtil.addField(familyInfos, "classification", "4");//4表示种族信息点
            result.addAll(commonInfos);
            result.addAll(familyInfos);
            if (ref != null && !ref.isEmpty()) {
                JSONArray reInfos = getSplitInfos(null, ref);
                CommonUtil.addField(reInfos, "classification", "4");//4表示种族信息点
                result.addAll(reInfos);
            }
            return result;
        }
        //系统
        if (type.length() == 2) {
            JSONArray commonInfos = getSplitInfos(null, "sy-gen");
            CommonUtil.addField(commonInfos, "classification", "1");//1表示系统通用
            JSONArray sysInfos = getCtmDictSplitInfos(dictId, type);
            CommonUtil.addField(sysInfos, "classification", "5");//5表示系统独有
            result.addAll(commonInfos);
            result.addAll(sysInfos);
            if (ref != null && !ref.isEmpty()) {
                JSONArray reInfos = getSplitInfos(null, ref);
                CommonUtil.addField(reInfos, "classification", "5");//5表示系统独有
                result.addAll(reInfos);
            }
            return result;
        }
        //设备或部件
        String familyRef = null;
        for (int i = 0; i < arr.size(); i++) {
            JSONObject node = arr.getJSONObject(i);
            if (node.getString(CtmNodeTable.KEY_CODE).equalsIgnoreCase(family)) {
                familyRef = node.getString(CtmNodeTable.COL_REF);
                break;
            }
        }
        JSONArray commonInfos = getSplitInfos(null, "eq-gen");
        CommonUtil.addField(commonInfos, "classification", "2");//2表示设备通用
        result.addAll(commonInfos);
        if (ref != null && !ref.isEmpty()) {
            JSONArray eqInfos = getSplitInfos(null, ref);
            CommonUtil.addField(eqInfos, "classification", "6");//6表示设备独有
            result.addAll(eqInfos);
            JSONArray familyInfos = getSplitInfos(null, new EqStaticInfo(null).getEqToFamilyMap().get(ref));
            CommonUtil.addField(familyInfos, "classification", "4"); //4表示种族信息点
            result.addAll(familyInfos);
        } else {
            if (familyRef != null && !familyRef.isEmpty()) {
                JSONArray familyInfos = getSplitInfos(null, familyRef);
                CommonUtil.addField(familyInfos, "classification", "4"); //4表示种族信息点
                result.addAll(familyInfos);
            }
        }
        List<String> types = new ArrayList<>(2);
        types.add(type);
        types.add(family);
        Map<String, JSONArray> map = getCtmDictSplitInfos(dictId, types);
        JSONArray tmpArr = map.get(type);
        CommonUtil.addField(tmpArr, "classification", "6");//6表示设备独有
        result.addAll(tmpArr);

        tmpArr = map.get(family);
        CommonUtil.addField(tmpArr, "classification", "4");//4表示种族信息点
        result.addAll(tmpArr);
        return result;
    }
}
