package com.sagacloud.cache.utils;
/*
 * Author: Jxing
 * Create Time: 2018/8/3
 */

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.sagacloud.cache.cachedObject.QueryObjects;
import com.sagacloud.cache.cachedObject.pojo.*;
import com.sagacloud.dict.CsStaticInfo;
import com.sagacloud.dict.EqStaticInfo;
import com.sagacloud.dict.TlStaticInfo;
import com.sagacloud.endpointService.EquipmentService;
import com.sagacloud.endpoints.item.PhysicalObject;
import com.sagacloud.endpoints.tagset.ObjectTagCache;
import com.sagacloud.utils.*;
import com.sagacloud.utils.objects.CommonQueryCriteria;
import com.sagacloud.utils.objects.IncludeExclude;
import com.sagacloud.utils.objects.ObjectType;
import com.sagacloud.utils.objects.FastjsonObjectComparator;
import com.sagacloud.utils.jsonHelper.infoPoint.InfoPoint;
import com.sagacloud.utils.relationUtils.RelationUtil;
import com.sagacloud.utils.tables.HBaseTable;
import com.sagacloud.utils.tables.ObjInfosTable;
import com.sagacloud.utils.tables.ObjectTable;
import com.sagacloud.utils.venders.VendersInfoUtil;

import java.util.*;
import java.util.stream.Collectors;

public class CacheUtil {

    /**
     * 获取信息点表的缓存Map
     * @param pjId 项目id
     * @param infoCode 信息点编码
     * @return 缓存map
     */
    public static Map<String, List<InfoTableObject>> getInfoTableObjectMap(String pjId, String infoCode){
        Map<String, List<InfoTableObject>> map = new HashMap<>();
        JSONArray arr = new JSONArray();
        JSONObject obj = new JSONObject();
        obj.put(ObjInfosTable.KEY_PJ_ID, pjId);
        obj.put(ObjInfosTable.KEY_INFO_ID, infoCode);
        arr.add(obj);
        JSONObject result;
        try {
            result = CommonUtil.combine_query_fastjson(HBaseTable.obj_infos, arr);
            JSONArray content = result.getJSONArray("Content");
            processInfoTableToCache(content, map);
        }catch (Exception ex){
            return map;
        }
        return map;
    }

    private static void processInfoTableToCache(JSONArray content, Map<String, List<InfoTableObject>> map) {
        for(int i = 0; i < content.size(); ++i){
            JSONObject single = content.getJSONObject(i);
            String id = CommonUtil.combineId(Strings.nullToEmpty(single.getString(ObjInfosTable.KEY_PJ_ID)), Strings.nullToEmpty(single.getString(ObjInfosTable.KEY_OBJ_TYPE))
                    , Strings.nullToEmpty(single.getString(ObjInfosTable.KEY_OBJ_ID)));
            InfoTableObject obj = JSONObject.toJavaObject(single, InfoTableObject.class);
            List<InfoTableObject> list = null;
            if(map.get(id) == null){
                list = new ArrayList<InfoTableObject>();
                map.put(id, list);
            }else
                list = map.get(id);
            list.add(obj);
        }
    }

    /**
     * 获取资产的信息点缓存map
     *
     * @param pjId 数字项目id
     * @param infoCode 信息点编码
     * @return 缓存map
     */
    public static Map<String, List<InfoTableObject>> getPropertyInfoTableObjectMap(String pjId, String infoCode) {
        // 根据对象表缓存, 获取项目内所有资产id
        ObjectTableObjectMap cache = QueryObjects.getObjectTableMap(pjId);
        HashMap<String, ObjectTableObject> map = cache.getObjectTableMap();
        Set<String> peIdSet = new HashSet<>();
        for(String id: map.keySet()){
            if(id.startsWith(Const.OBJ_TYPE_PROPERTY) && !peIdSet.contains(id)){
                peIdSet.add(id);
            }
        }
        // 根据id列表, 获取信息点缓存map
        JSONArray arr = new JSONArray();
        Map<String, List<InfoTableObject>> infoMap = new HashMap<>();
        try{
            for(String id : peIdSet){
                JSONObject obj = new JSONObject();
                obj.put(ObjInfosTable.KEY_PJ_ID, null);
                obj.put(ObjInfosTable.KEY_OBJ_TYPE, Const.OBJ_TYPE_PROPERTY);
                obj.put(ObjInfosTable.KEY_OBJ_ID, id.substring(2));
                obj.put(ObjInfosTable.KEY_INFO_ID, infoCode);
                arr.add(obj);
            }
            JSONObject result = CommonUtil.combine_query_fastjson(HBaseTable.obj_infos, arr);
            JSONArray content = result.getJSONArray("Content");
            processInfoTableToCache(content, infoMap);
        }catch (Exception ignore){}
        return infoMap;
    }

    public static HashMap<String, ObjectTableObject> getObjectMap(String pjId) {
        JSONObject criteria = new JSONObject();
        criteria.put(ObjectTable.KEY_PJ_ID, pjId);
        JSONArray arr = new JSONArray();
        HashMap<String, ObjectTableObject> map = new HashMap<>();
        arr.add(criteria);
        try {
            JSONObject result = CommonUtil.combine_query_fastjson(HBaseTable.objects, arr);
            JSONArray content = result.getJSONArray("Content");
            processObjTableToCache(content, map);
        }catch (Exception ignore){}
        return map;
    }

    private static void processObjTableToCache(JSONArray content, HashMap<String, ObjectTableObject> map) {
        for(int i = 0; i < content.size(); ++i){
            JSONObject single = content.getJSONObject(i);
            String id = CommonUtil.combineId(Strings.nullToEmpty(single.getString(ObjectTable.KEY_PJ_ID)), Strings.nullToEmpty(single.getString(ObjectTable.KEY_OBJ_TYPE))
                    , Strings.nullToEmpty(single.getString(ObjectTable.KEY_OBJ_ID)));
            ObjectTableObject obj = JSONObject.toJavaObject(single, ObjectTableObject.class);
            if(!map.containsKey(id))
                map.put(id, obj);
        }
    }


    public static JSONArray getInfoByValueArray(String pjId, String id, ArrayList<String> types, Map<String, Set<Object>> infoValueMap, IncludeExclude includeExclude, boolean set, boolean accurate, CommonQueryCriteria cqc) throws Exception {
    //public static JSONArray getInfoByValueArray(String pjId, String id, ArrayList<String> types, String infoCode, JSONArray infoValues, CommonQueryCriteria cqc) throws Exception {
        QueryObjects queryObjects = QueryObjects.get(pjId);
        JSONArray retArr = new JSONArray();
        Set<String> typeSet = new HashSet<>(types);
        Set<ObjectType> objectTypeSet = new HashSet<>();
        for(int i = 0; i < types.size(); ++i) {
            ObjectType ot = getObjectTypeByIdPrefix(pjId, types.get(i));
            if(ot != null && !objectTypeSet.contains(ot))
                objectTypeSet.add(ot);
        }
        ObjectType[] objectTypeArr = new ObjectType[objectTypeSet.size()];
        objectTypeSet.toArray(objectTypeArr);
        Map<String, FinalJSONObjectMap> allObjectMap = queryObjects.getFinalJSONObjectMap(objectTypeArr);
        Set<String> idSet = new HashSet<>();
        for(String type : allObjectMap.keySet()){
            FinalJSONObjectMap objectMap = allObjectMap.get(type);
            for(String objId : objectMap.getIdToJSONObject().keySet()){
                JSONObject single = objectMap.getIdToJSONObject().get(objId);
                // 检测是不是在id 下
                if(!objId.startsWith(Const.OBJ_TYPE_PROJECT) && !id.startsWith("Pj")){
                    if(objId.startsWith("Pe")){
                        JSONObject relation = single.getJSONObject("relation");
                        if(relation == null)
                            continue;
                        if(!id.equals(relation.getString("building")) && !id.equals(relation.getString("floor")))
                            continue;
                    }else {
                        JSONObject location = single.getJSONObject("location");
                        if (location == null)
                            continue;
                        if (!id.equals(location.getString("building")) && !id.equals(location.getString("floor")))
                            continue;
                    }
                }
                // include/exclude关系筛选
                if(!checkIncludeExclude(objId, includeExclude))
                    continue;
                // 检测objId类型是否是目标类型
                if(!checkObjectType(single, objId, typeSet)){
                    continue;
                }
                // 检测并匹配信息点, infoValueMap是要过滤的信息点集合, set 表示多个信息点过滤的交并集, accurate表示是否模糊查询/精确查询
                JSONObject infoNode = single.getJSONObject("infos");
                boolean isMatch = JSONUtils.checkInfos(infoNode, infoValueMap, set, accurate);
                if(isMatch && !idSet.contains(objId))
                    idSet.add(objId);
            }
        }
        if(idSet.size() > 0)
            return  queryWithPaging(pjId, idSet, cqc);
            //return batchQuerySelfInfo(pjId, idSet, cqc);
        return retArr;
    }

    /**
     * 筛查include exclude 关系
     * @param id  当前要被检测的对象id
     * @param includeExclude
     * @return true表示通过匹配, 需要返回给用户, false表示用户不想要查询该对象
     */
    private static boolean checkIncludeExclude(String id, IncludeExclude includeExclude) {
        // 当不需要筛查的时候
        if(!includeExclude.isExclude() && !includeExclude.isInclude())
            return true;
        // 既有include筛查, 又有exclude筛查
        if(includeExclude.isInclude() && includeExclude.isExclude()){
            if(includeExclude.getIncludeSet().contains(id) && !includeExclude.getExcludeSet().contains(id))
                return true;
            return false;
        }
        // 只有exclude筛查
        if(includeExclude.isExclude()){
            if(includeExclude.getExcludeSet().contains(id))
                return false;
            return true;
        }
        // 只有include筛查
        if(includeExclude.isInclude()){
            if(includeExclude.getIncludeSet().contains(id))
                return true;
            return false;
        }
        return true;
    }

    private static boolean checkObjectType(JSONObject single, String objId, Set<String> typeSet) {
        try {
            if (objId.startsWith(Const.OBJ_TYPE_EQUIPMENT)) {
                if (typeSet.contains(Const.OBJ_TYPE_EQUIPMENT))
                    return true;
                String type = single.getString("category").substring(2);
                if (typeSet.contains(type))
                    return true;
            }else if(objId.startsWith(Const.OBJ_TYPE_EQUIPMENT_COMPONENT)){
                if(typeSet.contains(Const.OBJ_TYPE_EQUIPMENT_COMPONENT))
                    return true;
                String type = single.getString("category").substring(2);
                if(typeSet.contains(type))
                    return true;
            }else if(objId.startsWith(Const.OBJ_TYPE_SYSTEM)){
                if(typeSet.contains(Const.OBJ_TYPE_SYSTEM))
                    return true;
                String type = single.getString("category").substring(2);
                if(typeSet.contains(type))
                    return true;
            }else if(objId.startsWith(Const.OBJ_TYPE_PROPERTY)){
                if(typeSet.contains(Const.OBJ_TYPE_PROPERTY))
                    return true;
                String type = single.getString("family");
                if(typeSet.contains(type))
                    return true;
            }else if(objId.startsWith(Const.OBJ_TYPE_SPACE)){
                if(typeSet.contains(Const.OBJ_TYPE_SPACE))
                    return true;
                String type = single.getString("businessType");
                // 以前没有类型的业务空间 与 GeneralZone匹配
                if(type == null || type.trim().length() == 0){
                    if(typeSet.contains("GeneralZone"))
                        return true;
                }else if(typeSet.contains(type))
                    return true;
            }else if (objId.startsWith(Const.OBJ_TYPE_CONSUMABLE)) {
                if (typeSet.contains(Const.OBJ_TYPE_CONSUMABLE))
                    return true;
                String type = single.getString("category");
                if (typeSet.contains(type))
                    return true;
            }else if (objId.startsWith(Const.OBJ_TYPE_TOOL)) {
                if (typeSet.contains(Const.OBJ_TYPE_TOOL))
                    return true;
                String type = single.getString("category");
                if (typeSet.contains(type))
                    return true;
            }else {
                if(typeSet.contains(objId.startsWith("VO")? objId.substring(0, 4): objId.substring(0, 2)))
                    return true;
            }
            return false;
        }catch (Exception ignore){
            return false;
        }
    }


    public static JSONArray complexQueryByCategory(String pjId, String category, String buildingId, String match, CommonQueryCriteria cqc) {
        Set<String> idSet = queryEquipmentByCategoryFilterUseTags(pjId, category, buildingId, match, cqc.getBusinessTags());
        return queryWithPaging(pjId, idSet, cqc);
    }

    public static JSONArray complexQueryBySystemId(String pjId, String system_id, String graph_id, String rel_type, String match, CommonQueryCriteria cqc) throws Exception {
        ArrayList<String> ids = RelationUtil.getEqUnderSys(pjId, system_id, graph_id, rel_type);
        if(!ids.isEmpty()) {
        	ArrayList<String> tagFilterIds = new ArrayList<>();
        	for(String id : ids) {
        		if(ObjectTagCache.ifHasTag(id, cqc.getBusinessTags(), false)) {
        			tagFilterIds.add(id);
        		}
        	}
        	ids = tagFilterIds;
        }
        // 只获取system_id所在专业下的所有设备类型
        filterMajor(pjId, ids, system_id, match);
        return queryWithPaging(pjId, new HashSet<>(ids), cqc);
    }
    public static JSONArray complexQueryAll(String pjId, CommonQueryCriteria cqc) {
        Set<String> idSet = queryAllEquip(pjId);
        if(!idSet.isEmpty()) {
        	Set<String> idTagFilterSet = new HashSet<>();
        	for(String id : idSet) {
        		if(ObjectTagCache.ifHasTag(id, cqc.getBusinessTags(), false)) {
        			idTagFilterSet.add(id);
        		}
        	}
        	idSet = idTagFilterSet;
        }
        return queryWithPaging(pjId, idSet, cqc);
    }

    private static Set<String> queryAllEquip(String pjId) {
        ObjectTableObjectMap objectMap = QueryObjects.getObjectTableMap(pjId);
        Set<String> idSet = new HashSet<>();
        for(String id : objectMap.getObjectTableMap().keySet()){
            if(id.startsWith("Eq") && !idSet.contains(id)){
                idSet.add(id);
            }
        }
        return idSet;
    }

    private static void filterMajor(String pjId, ArrayList<String> ids, String system_id, String match) throws Exception {
        ObjectTableObjectMap objectTableMap = QueryObjects.getObjectTableMap(pjId);
        if(objectTableMap.getObjectTableMap().get(system_id) == null || !objectTableMap.getObjectTableMap().get(system_id).getValid().equals(true))
            throw new Exception("系统id不存在");
        String type = objectTableMap.getObjectTableMap().get(system_id).getSubType();
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        String systemMajor = eqStaticInfo.getCateToMajorMap().get(type);
        Set<String> detailTypeSet = eqStaticInfo.getMajorToEqMap().get(systemMajor);
        QueryObjects queryObjects = QueryObjects.get(pjId);
        FinalJSONObjectMap equipJSONObject = null;
        if(match != null && match.length() > 0)
            equipJSONObject = queryObjects.getFinalJSONObjectMap(ObjectType.equipment).get(ObjectType.equipment.name());
        for(int i = ids.size() - 1; i > -1; --i){
            String id = ids.get(i);
            if(objectTableMap.getObjectTableMap().get(id) == null || !detailTypeSet.contains(objectTableMap.getObjectTableMap().get(id).getSubType())){
                ids.remove(i);
                continue;
            }
            if(match != null && match.length() > 0){
                if(equipJSONObject.getIdToJSONObject().get(id) == null || equipJSONObject.getIdToJSONObject().get(id).getJSONObject("infos") == null){
                    ids.remove(i);
                    continue;
                }
                JSONObject infoNode = equipJSONObject.getIdToJSONObject().get(id).getJSONObject("infos");
                String equipLocalId = infoNode.getString("EquipLocalId");
                String equipLocalName = infoNode.getString("EquipLocalName");
                if((equipLocalId== null || !equipLocalId.contains(match)) && (equipLocalName == null || !equipLocalName.contains(match))) {
                    ids.remove(i);
                    continue;
                }
            }
        }
    }

    public static JSONArray queryWithPaging(String pjId, Set<String> resultSet, CommonQueryCriteria cqc) {
        JSONArray retArr = new JSONArray();
        try {
            retArr = batchQuerySelfInfo(CommonMethods.getProject(pjId, false), resultSet, cqc);
            if(cqc.getNodata())
                return new JSONArray();
            // 按信息点过滤信息
            if(cqc.isFilter()){
                for(int i = retArr.size() - 1; i > -1; --i){
                    JSONObject singleObj = retArr.getJSONObject(i);
                    JSONObject infos = singleObj.getJSONObject("infos");
                    Object infoValue = infos.get(cqc.getFilterInfoCode());
                    if(!InfoCodeUtil.compareValue(infoValue, cqc.getFilterValue())){
                        retArr.remove(i);
                    }
                }
            }
            // 过滤资产的直接关联位置
            if(cqc.isDirectOnly()){
                if(cqc.getDirectOnlyId() == null || cqc.getDirectOnlyId().length() == 0) {
                    cqc.setDirectOnlyId(CommonMethods.getProject(pjId, true));
                }
                for (int i = retArr.size() - 1; i > -1; --i) {
                    JSONObject singleObj = retArr.getJSONObject(i);
                    JSONObject relation = singleObj.getJSONObject("relation");
                    JSONObject location = singleObj.getJSONObject("location");
                    if (relation == null && location == null)
                        continue;
                    if (relation != null) {
                        if (!DpUtils.filterDirectOnly(cqc.getDirectOnlyId(), relation)) {
                            retArr.remove(i);
                        }
                    } else {
                        if (!DpUtils.filterDirectOnly(cqc.getDirectOnlyId(), location)) {
                            retArr.remove(i);
                        }
                    }
                }

            }
            // 排序和分页
            JSONObject[] arr = new JSONObject[retArr.size()];
            for (int i = 0; i < retArr.size(); ++i)
                arr[i] = (JSONObject) retArr.get(i);
            FastjsonObjectComparator cmp = new FastjsonObjectComparator("create_time");
            Arrays.sort(arr, cmp);
            retArr.clear();
            Long from = 0L;
            int count = arr.length;
            if (cqc.getSkip() != null) {
                from = cqc.getSkip();
                count = cqc.getSkip_count();
            }
            cqc.setSkip_totalCount((long) arr.length);
            long cnt = 0L;
            for (long i = from; i < arr.length && (i - from) < count; ++i) {
                if (cqc.getNodata())
                    ++cnt;
                else
                    retArr.add(arr[(int) i]);
            }
            cqc.setCount(cnt);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return retArr;
    }

    private static Set<String> queryEquipmentByCategory(String pjId, String category, String buildingId, String match) {
        QueryObjects queryObjects = QueryObjects.get(pjId);
        Map<String, FinalJSONObjectMap> objects = queryObjects.getFinalJSONObjectMap(ObjectType.equipment);
        FinalJSONObjectMap equipmentMap = objects.get(ObjectType.equipment.name());
        Set<String> retSet = new HashSet<>();
        Set<String> equipTypes = EquipmentService.getEquipTypeByCategoryOrSystemEquipType(pjId, category);//category == null ? null : EqStaticInfo.majorToEqMap.get(category); // 专业下的所有设备类型
        for(String id : equipmentMap.getIdToJSONObject().keySet()){
            JSONObject jsonObject = equipmentMap.getIdToJSONObject().get(id);
            JSONObject relation = jsonObject.getJSONObject("location");
            // 专业不匹配跳过,  category == null的时候是查询所有专业的设备.
            if(category != null) {
                if (!equipTypes.contains(jsonObject.getString("category").substring(2))) {
                    continue;
                }
            }
            // 建筑不匹配
            if(buildingId != null && buildingId.startsWith(Const.OBJ_TYPE_BUILDING)){
                if(relation == null || relation.getString("building") == null || !relation.getString("building").equals(buildingId))
                    continue;
            }
            // 查找 "EquipLocalID", "EquipLocalName" 信息点, 是否能匹配上match
            boolean isFound = false;
            if(match != null && match.length() > 0){
                JSONObject infoNode = jsonObject.getJSONObject("infos");
                if(infoNode == null)
                    continue;
                String equipLocalId = infoNode.getString("EquipLocalID");
                String equipLocalName = infoNode.getString("EquipLocalName");
                if(equipLocalId!= null && equipLocalId.contains(match)){
                    isFound = true;
                }else if(equipLocalName != null && equipLocalName.contains(match)){
                    isFound = true;
                }
            }else
                isFound = true;
            if(isFound && !retSet.contains(id))
                retSet.add(id);
        }
        return retSet;
    }
    
    /**
     * 
     * @param pjId
     * @param category
     * @param buildingId
     * @param match
     * @param shouldHasTags 对象应该具有的标签编码集合
     * @return
     */
    private static Set<String> queryEquipmentByCategoryFilterUseTags(String pjId, String category, String buildingId, String match, Set<String> shouldHasTags) {
        QueryObjects queryObjects = QueryObjects.get(pjId);
        Map<String, FinalJSONObjectMap> objects = queryObjects.getFinalJSONObjectMap(ObjectType.equipment);
        FinalJSONObjectMap equipmentMap = objects.get(ObjectType.equipment.name());
        Set<String> retSet = new HashSet<>();
        Set<String> equipTypes = EquipmentService.getEquipTypeByCategoryOrSystemEquipType(pjId, category);//category == null ? null : EqStaticInfo.majorToEqMap.get(category); // 专业下的所有设备类型
        for(String id : equipmentMap.getIdToJSONObject().keySet()){
        	if(!ObjectTagCache.ifHasTag(id, shouldHasTags, false)) {
        		continue;
        	}
            JSONObject jsonObject = equipmentMap.getIdToJSONObject().get(id);
            JSONObject relation = jsonObject.getJSONObject("location");
            // 专业不匹配跳过,  category == null的时候是查询所有专业的设备.
            if(category != null) {
                if (!equipTypes.contains(jsonObject.getString("category").substring(2))) {
                    continue;
                }
            }
            // 建筑不匹配
            if(buildingId != null && buildingId.startsWith(Const.OBJ_TYPE_BUILDING)){
                if(relation == null || relation.getString("building") == null || !relation.getString("building").equals(buildingId))
                    continue;
            }
            // 查找 "EquipLocalID", "EquipLocalName" 信息点, 是否能匹配上match
            boolean isFound = false;
            if(match != null && match.length() > 0){
                JSONObject infoNode = jsonObject.getJSONObject("infos");
                if(infoNode == null)
                    continue;
                String equipLocalId = infoNode.getString("EquipLocalID");
                String equipLocalName = infoNode.getString("EquipLocalName");
                if(equipLocalId!= null && equipLocalId.contains(match)){
                    isFound = true;
                }else if(equipLocalName != null && equipLocalName.contains(match)){
                    isFound = true;
                }
            }else
                isFound = true;
            if(isFound && !retSet.contains(id))
                retSet.add(id);
        }
        return retSet;
    }

    public static JSONArray batchQuerySelfInfo(String pjId, Set<String> idSet, CommonQueryCriteria cqc)throws Exception{
        Set<String> typeSet = getTypesByIdSet(pjId, idSet);
        JSONArray objectArr = new JSONArray();
        if(typeSet.size() == 0)
            return objectArr;
        if(cqc.isLinkInfos()){
            if(typeSet.contains(ObjectType.property.name())) {
                if(!typeSet.contains(ObjectType.equipment.name()))
                    typeSet.add(ObjectType.equipment.name());
                if(!typeSet.contains(ObjectType.component.name()))
                    typeSet.add(ObjectType.component.name());
            }
            if((typeSet.contains(ObjectType.equipment.name()) || typeSet.contains(ObjectType.component.name())) && !typeSet.contains(ObjectType.property.name()))
                typeSet.add(ObjectType.property.name());
        }
        if(cqc.getNodata()){
            getNodata(pjId, idSet, cqc);
            return new JSONArray();
        }
        QueryObjects queryObjects = QueryObjects.get(pjId);
        String[] tmp = new String[typeSet.size()];
        typeSet.toArray(tmp);
        Map<String, FinalJSONObjectMap> objects = queryObjects.getFinalJSONObjectMap(tmp);
        if(objects.size() == 0)
            throw new Exception("数据库连接异常或没数据!");
        ObjectTableObjectMap objectMap = QueryObjects.getObjectTableMap(pjId);
        Map<String, String> link = queryObjects.getEquipToPropertyLink();

        Set<String> idTypeSet = new HashSet<>();
        for(String id: idSet) {
            String type = objectMap.getObjectTableMap().get(id).getSubType();
            String mainType = objectMap.getObjectTableMap().get(id).getObjType();
            if(type!= null && !idTypeSet.contains(type))
                idTypeSet.add(type);
            else if(mainType != null && !idTypeSet.contains(mainType))
                idTypeSet.add(mainType);
        }
        if(idTypeSet.size() == 0)
            return objectArr;
        String[] typeArr = new String[idTypeSet.size()];
        idTypeSet.toArray(typeArr);
        HashMap<String, HashMap<String, InfoPoint>> infoMaps = InfoCodeUtil.getWholeInfosWithCustomMap(pjId, typeArr);
        for(String id: idSet) {
            JSONObject single = getJSONObjectById(pjId, objects, id, cqc, objectMap, link, infoMaps);
            if(single != null) {
                if(cqc.isFilterReturnInfos()){
                    Set<String> returnInfos = cqc.getReturnInfos();
                    JSONObject infos = single.getJSONObject("infos");
                    List<String> rmKeys = infos.keySet().stream().filter(key -> !returnInfos.contains(key)).collect(Collectors.toList());
                    rmKeys.forEach(key -> infos.remove(key));
                }
                objectArr.add(single);
            }
        }
        if(!cqc.isNoInfo() && cqc.isVenderInfo()) {
            // 补充从厂商库获取的信息点
            VendersInfoUtil.addVenderInfo(CommonMethods.getProject(pjId, true), objectArr);
        }
        return objectArr;
    }

    private static JSONObject getJSONObjectById(String pjId, Map<String, FinalJSONObjectMap> objects, String id, CommonQueryCriteria cqc, ObjectTableObjectMap objectMap, Map<String, String> link, HashMap<String, HashMap<String, InfoPoint>> infoMaps) {
        String type = id.startsWith("VO") ? id.substring(0, 4) : id.substring(0, 2);
        ObjectType ot = getObjectTypeByIdPrefix(pjId, type);
        FinalJSONObjectMap objectJsonMap = objects.get(ot.name());
        if(objectJsonMap == null)
            return null;
        JSONObject retObj = (JSONObject) objectJsonMap.getIdToJSONObject().get(id).clone();
        if(retObj == null || objectMap.getObjectTableMap().get(id) == null )
            return null;
        // 过滤valid
        if(cqc.getValid() != null && !objectMap.getObjectTableMap().get(id).getValid().equals(cqc.getValid())){
            return null;
        }
        // 过滤CTime
        if(!isCtimeSatisfy(cqc.getCtime() == null? null : cqc.getCtime().toString(), objectMap.getObjectTableMap().get(id).getCtime())){
            return null;
        }
        JSONObject originInfoNode = retObj.getJSONObject("infos");
        String peId = link.get(id);
        if(peId != null)
            retObj.put("linkId", peId);
        // 不返回信息点内容
        if(cqc.isNoInfo()){
            retObj.put("infos", new JSONObject());
            return retObj;
        }
        JSONObject infoNode = null;
        HashMap<String, InfoPoint> infoMap = infoMaps.get(objectMap.getObjectTableMap().get(id).getSubType());
        // 资产或者岗位 获取linkInfos
        try {
            infoNode = (JSONObject) originInfoNode.clone();
            retObj.put("infos", infoNode);
            if (cqc.isLinkInfos()) {
//                if (ot.equals(ObjectType.equipment) || ot.equals(ObjectType.property)) {
                if (ot.equals(ObjectType.equipment)) {
                    // 必须是true
                    complementInfos(objects, id, objectMap, infoNode, infoMap, peId, ObjectType.property);
                } else if (ot.equals(ObjectType.property)) {
                    String eqOrEcId = retObj.getJSONObject("relation") == null ? null : retObj.getJSONObject("relation").getString("link");
                    if(eqOrEcId != null && eqOrEcId.length() > 0)
                    complementInfos(objects, id, objectMap, infoNode, infoMap, eqOrEcId,
                            eqOrEcId.startsWith(Const.OBJ_TYPE_EQUIPMENT)? ObjectType.equipment : ObjectType.component);
                }
            }
        }catch (Exception ignore){
            ignore.printStackTrace();
        }

        if(infoNode != null){
            List<String> hisList = new ArrayList<>();
            for(String infoCode : infoNode.keySet()){
                // 过滤history, 是否显示
                if(!cqc.isHistoryInfos() && infoCode.endsWith("_his")) {
                        hisList.add(infoCode);
                        continue;
                }
                // 过滤自定义信息点
                if(!cqc.isCustomInfo() && infoCode.startsWith(InfoCodeUtil.prefix)){
                    hisList.add(infoCode);
                    continue;
                }
            }
            for(int i = 0; i < hisList.size(); ++i){
                if(infoNode.containsKey(hisList.get(i))){
                    infoNode.remove(hisList.get(i));
                }
            }
        }
        return retObj;
    }

    private static void complementInfos(Map<String, FinalJSONObjectMap> objects, String id, ObjectTableObjectMap objectMap, JSONObject infoNode, HashMap<String, InfoPoint> infoMap, String peId, ObjectType ot) {
        if (peId != null && objectMap.getObjectTableMap().get(id) != null && objectMap.getObjectTableMap().get(id).getValid().equals(true)) {
            FinalJSONObjectMap complementObjMap = objects.get(ot.name());
            if (complementObjMap != null) {
                JSONObject complementObject = complementObjMap.getIdToJSONObject().get(peId);//
                if (complementObject != null) {
                    JSONObject complementInfoNode = complementObject.getJSONObject("infos");
                    for(String complementInfoCode : complementInfoNode.keySet()){
                        String infoCodeWithoutHis = complementInfoCode;
                        if(complementInfoCode.endsWith("_his"))
                            infoCodeWithoutHis = infoCodeWithoutHis.substring(0, complementInfoCode.length() - 4);
                        if(infoMap.containsKey(infoCodeWithoutHis) && !infoNode.containsKey(infoCodeWithoutHis) &&!infoNode.containsKey(complementInfoCode)){
                            infoNode.put(complementInfoCode, complementInfoNode.get(complementInfoCode));
                        }
                    }
                }
            }
        }
    }

    private static void getNodata(String pjId, Set<String> idSet, CommonQueryCriteria cqc) {
        ObjectTableObjectMap objectMap = QueryObjects.getObjectTableMap(pjId);
        int count = 0;
        for(String id : idSet){
            ObjectTableObject obj = objectMap.getObjectTableMap().get(id);
            boolean isPass = true;
            if(obj == null)
                continue;
            if(cqc.getValid() != null && !cqc.getValid().equals(obj.getValid()))
                isPass = false;
            if(cqc.getCtime() != null){
                if(!isCtimeSatisfy(cqc.getCtime() == null ? null : cqc.getCtime().toString(), obj.getCtime())){
                    isPass = false;
                }
            }
            if(isPass)
                ++count;
        }
        cqc.setCount((long) count);
    }
    private static boolean isCtimeSatisfy(String s, String ctime){
        if(s == null)
            return true;
        JSONObject ctimeObject = JSONObject.parseObject(s);
        for(String key : ctimeObject.keySet()){
            String value = ctimeObject.getString(key);
            switch (key){
                case "$gte":
                    if(ctime.compareTo(value) < 0)
                        return false;
                    break;
                case "$lte":
                    if(ctime.compareTo(value) > 0)
                        return false;
                    break;
                case "gt":
                    if(ctime.compareTo(value) <= 0)
                        return false;
                    break;
                case "lt":
                    if(ctime.compareTo(value) >= 0)
                        return false;
                    break;
            }
        }
        return true;
    }

    private static Set<String> getTypesByIdSet(String pjId, Set<String> idset){
        Set<String> typeSet = new HashSet<>();
        for(String id : idset){
            ObjectType ot = getObjectTypeByIdPrefix(pjId, id.startsWith("VO")?id.substring(0,4) : id.substring(0, 2));
            if(ot != null && !typeSet.contains(ot.name())){
                typeSet.add(ot.name());
            }
        }
        return typeSet;
    }

    public static ObjectType getObjectTypeByIdPrefix(String pjId, String prefix){
        // project, building, floor, space, ispace, equipment, component, system, VOBd, VO, property, shaft,
        //    VOCu, VOEi, VOTn, VOZn, VOGp, VOCt, VOBc, VOSe
        switch (prefix){
            case Const.OBJ_TYPE_PROJECT:
                return ObjectType.project;
            case Const.OBJ_TYPE_BUILDING:
                return ObjectType.building;
            case Const.OBJ_TYPE_FLOOR:
                return ObjectType.floor;
            case Const.OBJ_TYPE_SPACE:
                return ObjectType.space;
            case Const.OBJ_TYPE_ISPACE:
                return ObjectType.ispace;
            case Const.OBJ_TYPE_EQUIPMENT:
                return ObjectType.equipment;
            case Const.OBJ_TYPE_EQUIPMENT_COMPONENT:
                return ObjectType.component;
            case Const.OBJ_TYPE_SYSTEM:
                return ObjectType.system;
            case Const.OBJ_TYPE_CONSUMABLE:
                return ObjectType.consumable;
            case Const.OBJ_TYPE_TOOL:
                return ObjectType.tool;
            case Const.OBJ_TYPE_VOBD:
                return ObjectType.VOBd;
//            case Const.OBJ_TYPE_VO:
//                return ObjectType.VO;
            case Const.OBJ_TYPE_SHAFT:
                return ObjectType.shaft;
            case Const.OBJ_TYPE_PROPERTY:
                return ObjectType.property;
            case Const.OBJ_TYPE_VOCU:
                return ObjectType.VOCu;
            case Const.OBJ_TYPE_VOEI:
                return ObjectType.VOEi;
            case Const.OBJ_TYPE_VOTn:
                return ObjectType.VOTn;
            case Const.OBJ_TYPE_VOZn:
                return ObjectType.VOZn;
            case Const.OBJ_TYPE_VOGp:
                return ObjectType.VOGp;
            case Const.OBJ_TYPE_VOCt:
                return ObjectType.VOCt;
            case Const.OBJ_TYPE_VOBc:
                return ObjectType.VOBc;
            case Const.OBJ_TYPE_VOSe:
                return ObjectType.VOSe;
            case Const.OBJ_TYPE_VOSc:
                return ObjectType.VOSc;
            case Const.OBJ_TYPE_VOSh:
                return ObjectType.VOSh;
            case Const.OBJ_TYPE_VOSw:
                return ObjectType.VOSw;
            case Const.OBJ_TYPE_VOSg:
                return ObjectType.VOSg;
            case Const.OBJ_TYPE_VOSf:
                return ObjectType.VOSf;
            case Const.OBJ_TYPE_VOSv:
                return ObjectType.VOSv;
            case Const.OBJ_TYPE_VOBr:
                return ObjectType.VOBr;
            case Const.OBJ_TYPE_VOMt:
                return ObjectType.VOMt;
        }
        if(CsStaticInfo.getCode2name().keySet().contains(prefix)){
            return ObjectType.consumable;
        }
        if(TlStaticInfo.getCode2name().keySet().contains(prefix)){
            return ObjectType.tool;
        }
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        if(eqStaticInfo.getSysSet().contains(prefix)){
            return ObjectType.system;
        }
        if(eqStaticInfo.getEqSet().contains(prefix)){
            return ObjectType.equipment;
        }
        if(eqStaticInfo.getEcSet().contains(prefix)){
            return ObjectType.component;
        }
        if(eqStaticInfo.getFamilySet().contains(prefix))
            return ObjectType.property;
        if(PhysicalObject.bussinessSpaceTypeMap.containsKey(prefix))
            return ObjectType.space;
        return null;
    }

    public static String getIdPrefixByObjectType(String objectType){
        // project, building, floor, space, ispace, equipment, component, system, VOBd, VO, property, shaft,
        //    VOCu, VOEi, VOTn, VOZn, VOGp, VOCt, VOBc, VOSe
        switch (objectType){
            case "project":
                return Const.OBJ_TYPE_PROJECT;
            case "building":
                return Const.OBJ_TYPE_BUILDING;
            case "floor":
                return Const.OBJ_TYPE_FLOOR;
            case "space":
                return Const.OBJ_TYPE_SPACE;
            case "ispace":
                return Const.OBJ_TYPE_ISPACE;
            case "equipment":
                return Const.OBJ_TYPE_EQUIPMENT;
            case "component":
                return Const.OBJ_TYPE_EQUIPMENT_COMPONENT;
            case "system":
                return Const.OBJ_TYPE_SYSTEM;
            case "shaft":
                return Const.OBJ_TYPE_SHAFT;
            case "property":
                return Const.OBJ_TYPE_PROPERTY;
            case "consumable":
                return Const.OBJ_TYPE_CONSUMABLE;
            case "tool":
                return Const.OBJ_TYPE_TOOL;
            case Const.OBJ_TYPE_VOCU:
            case Const.OBJ_TYPE_VOBD:
            case Const.OBJ_TYPE_VOEI:
            case Const.OBJ_TYPE_VOTn:
            case Const.OBJ_TYPE_VOZn:
            case Const.OBJ_TYPE_VOGp:
            case Const.OBJ_TYPE_VOCt:
            case Const.OBJ_TYPE_VOBc:
            case Const.OBJ_TYPE_VOSe:
            case Const.OBJ_TYPE_VOSc:
            case Const.OBJ_TYPE_VOSh:
            case Const.OBJ_TYPE_VOSw:
            case Const.OBJ_TYPE_VOSg:
            case Const.OBJ_TYPE_VOSf:
            case Const.OBJ_TYPE_VOSv:
            case Const.OBJ_TYPE_VOBr:
            case Const.OBJ_TYPE_VOMt:
                return objectType;
        }
        return objectType;
    }
}






























