package com.persagy.proxy.object.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Sets;
import com.persagy.dmp.basic.model.QueryCriteria;
import com.persagy.dmp.basic.utils.JsonNodeUtils;
import com.persagy.dmp.common.constant.CommonConstant;
import com.persagy.dmp.common.context.AppContext;
import com.persagy.dmp.common.helper.SpringHelper;
import com.persagy.dmp.common.model.response.CommonResult;
import com.persagy.dmp.define.entity.ObjectTypeDefine;
import com.persagy.dmp.digital.client.DigitalObjectFacade;
import com.persagy.dmp.digital.client.DigitalRelationProjectCalFacade;
import com.persagy.dmp.digital.entity.ObjectDigital;
import com.persagy.dmp.digital.entity.ObjectRelation;
import com.persagy.dmp.simple.client.DigitalObjectSimpleFacade;
import com.persagy.proxy.adm.annotations.CascadeColumn;
import com.persagy.proxy.adm.constant.*;
import com.persagy.proxy.adm.request.AdmDCSQueryRequest;
import com.persagy.proxy.adm.request.AdmQueryCriteria;
import com.persagy.proxy.adm.request.AdmResponse;
import com.persagy.proxy.adm.service.IAdmRelationService;
import com.persagy.proxy.adm.service.impl.AbstractAdmBaseServiceImpl;
import com.persagy.proxy.adm.utils.AdmContextUtil;
import com.persagy.proxy.adm.utils.AdmEntityTransferUtil;
import com.persagy.proxy.adm.utils.AdmQueryCriteriaHelper;
import com.persagy.proxy.calculation.service.AdmRelCalService;
import com.persagy.proxy.common.client.DmpRwdClient;
import com.persagy.proxy.common.entity.DmpResult;
import com.persagy.proxy.common.entity.InstanceUrlParam;
import com.persagy.proxy.common.entity.RelationDTO;
import com.persagy.proxy.object.model.AdmEquipment;
import com.persagy.proxy.object.model.AdmSpace;
import com.persagy.proxy.object.model.AdmSystem;
import com.persagy.proxy.object.service.IAdmEquipmentService;
import com.persagy.proxy.object.service.IAdmSpaceService;
import com.persagy.proxy.object.service.IAdmSystemService;
import com.persagy.proxy.report.service.IRelationReportService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * ADM 空间 实现类
 * @author lvxy
 * @date 2021/8/18
 */
@Slf4j
@Service
public class AdmSpaceServiceImpl extends AbstractAdmBaseServiceImpl<AdmSpace> implements IAdmSpaceService {
    @Autowired
    private DmpRwdClient rwdClient;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private IAdmRelationService relationService;
    @Autowired
    private IAdmEquipmentService equipmentService;
    @Autowired
    private IAdmSystemService systemService;
    @Autowired
    private IRelationReportService relationReportService;
    @Autowired
    private AdmRelCalService admRelCalService;

    @Override
    public AdmResponse doQuery(InstanceUrlParam context, AdmQueryCriteria request, Class<AdmSpace> clazz) {
        AdmResponse response = super.doQuery(context, request, clazz);
        // 系统需要补充分类名称属性
        ensureSpecialValues(context, (List<AdmSpace>) response.getContent());
        return response;
    }

    @Override
    public List<AdmSpace> doInsertExt(InstanceUrlParam context, Class<AdmSpace> clazz, List<AdmSpace> voList) {
        Map<String, List<AdmSpace>> spaceMapByFlId = voList.stream()
                .filter(admSpace -> StringUtils.isNotEmpty(admSpace.getFloorId()))
                .collect(Collectors.groupingBy(AdmSpace::getFloorId));
        //查询空间中floorId 对应的floor
        if(CollUtil.isNotEmpty(spaceMapByFlId)){
            List<ObjectNode> floors = queryFloorsByFloorIds(context, spaceMapByFlId.keySet());
            if(CollUtil.isNotEmpty(floors)){
                //ArrayList<AdmFloor> floorList = CollUtil.newArrayList(JSONUtil.toList(floors.getData().toString(),AdmFloor.class));
                //space.height = floor.infos.height
                voList = processHeight(spaceMapByFlId, floors);
            }
        }
        //插入空间
        List<AdmSpace> vosR = doInsert(context, clazz, voList);
        //添加绑定关系
        processRelations(vosR);
        //处理关系标记
        SpringHelper.getBean(IAdmSpaceService.class).processRelationType(context,vosR);
        return vosR;
    }

    @Override
    public AdmResponse doQueryType(InstanceUrlParam context, AdmDCSQueryRequest request) {
        //查询定义类型
        ObjectNode criteriaEq = JsonNodeFactory.instance.objectNode();
        criteriaEq.put("parentCode", "space");
        DmpResult<JSONArray> resultDef = queryDefineType(context, criteriaEq);
        List<JSONObject> defineList = null;
        if(resultDef.getResult().equals(DmpResult.SUCCESS)){
            defineList = JSONUtil.toList(resultDef.getData().toString(), JSONObject.class);
            //获取实际空间对象的数量
            //根据classCode floorId 查询查询实际存在的空间
            assembleDefineTypes(context, defineList, request.getFloorId());
            // 设置返回值
            AdmResponse response = AdmResponse.success(defineList, request);
            Long total = resultDef.getCount() == null ? null : resultDef.getCount().longValue();
            response.setTotal(total);
            return response;
        }else{
            return null;
        }
    }

    @Override
    public AdmResponse doQuerySpaces(InstanceUrlParam context, AdmDCSQueryRequest request) {
        request.setName(AdmSpace.OBJ_TYPE);
        String classCodeFilter = "";
        if(StrUtil.isNotEmpty(request.getZoneType())){
            classCodeFilter = " classCode = '"+request.getZoneType()+"'";
        }else if (CollUtil.isNotEmpty(request.getZoneTypeList())){
            classCodeFilter = " classCode in ['"+ String.join("', '",request.getZoneTypeList()) + "']";
        }
        String filters = request.getFilters();
        if(StrUtil.isBlank(filters)){
            request.setFilters(classCodeFilter);
        }else{
            request.setFilters(filters+"; "+classCodeFilter);
        }
        if(StrUtil.isNotEmpty(request.getBuildingId()) && StrUtil.isNotEmpty(request.getFloorId()) && !request.getFloorId().equals("isnull")){
            //明确建筑，明确楼层
            request.setFilters(request.getFilters()+" ; buildingId = '"+request.getBuildingId()+"' ; floorId='"+request.getFloorId()+"' ;");
            /*response = doQuery(context,request,AdmSpace.class);
            return response;*/
        }else if(StrUtil.isNotEmpty(request.getBuildingId()) && StrUtil.isNotEmpty(request.getFloorId()) && request.getFloorId().equals("isnull")){
        	//查询此建筑下未关联楼层的空间
            request.setFilters(request.getFilters()+" ; buildingId = '"+request.getBuildingId()+"' ; floorId isnull");
        	/*response = this.query(request);
            return response;*/
        }else if(StrUtil.isNotEmpty(request.getBuildingId()) && StrUtil.isEmpty(request.getFloorId()) && !request.getBuildingId().equals("isnull")){
            //查询建筑下的空间
            request.setFilters(request.getFilters()+" ; buildingId = '"+request.getBuildingId()+"' ; ");
        }else if(StrUtil.isNotEmpty(request.getBuildingId()) && StrUtil.isEmpty(request.getFloorId()) && request.getBuildingId().equals("isnull")){
            //未明确建筑下的空间
            //查询建筑下的空间
            request.setFilters(request.getFilters()+" ; buildingId isnull");
        }else if(StrUtil.isEmpty(request.getBuildingId()) && StrUtil.isEmpty(request.getFloorId())){
        }
        AdmResponse response = this.doQuery(context,request,AdmSpace.class);
        response.setPageNumber(request.getPageNumber() == null ? 50 : request.getPageNumber());
        response.setPageSize(request.getPageSize() == null ? 1 : request.getPageSize());
        return response;
    }

    @Override
    public void ensureSpecialValues(InstanceUrlParam context, List<AdmSpace> vos) {
        if(CollUtil.isEmpty(vos)) {
            return;
        }
        // 1. 收集空间的设备对象，扩展设备对象赋值
        List<AdmEquipment> equipmentList = new ArrayList<>();
        for(AdmSpace vo:vos) {
            // 收集设备对象
            if(CollUtil.isEmpty(vo.getEquipment()) && CollUtil.isEmpty(vo.getEquipmentFor())) {
                continue;
            }
            if(CollUtil.isNotEmpty(vo.getEquipment())) {
                equipmentList.addAll(vo.getEquipment());
            }
            if(CollUtil.isNotEmpty(vo.getEquipmentFor())) {
                equipmentList.addAll(vo.getEquipmentFor());
            }
        }
        // 对象扩展属性赋值
        equipmentService.ensureSpecialValues(context, equipmentList);

        //2.收集空间的系统 扩展系统、及系统下设备对象赋值
        List<AdmSystem> admSystemList = new ArrayList<>();
        for(AdmSpace vo:vos) {
            // 收集设备对象
            if(CollUtil.isEmpty(vo.getGeneralSystem())) {
                continue;
            }
            admSystemList.addAll(vo.getGeneralSystem());
        }
        // 3.对部分infos值在infos中也放置一份
        Map<String, Field> objFieldMap = JsonNodeUtils.getFieldMap(ObjectDigital.class);
        Map<String, Field> fieldMap = JsonNodeUtils.getFieldMap(AdmSpace.class);
        Set<String> fields = fieldMap.keySet();
        for (AdmSpace space : vos) {
            Map<String, Object> infos = space.getInfos();
            if (MapUtil.isEmpty(infos)){
                infos = new HashMap<>();
            }
            for (String fieldKey : fields) {
                if (fieldMap.get(fieldKey).isAnnotationPresent(CascadeColumn.class)
                        || objFieldMap.containsKey(fieldKey)){
                    continue;
                }
                // 重新放置一下height的值
                infos.put(fieldKey,ReflectUtil.getFieldValue(space,fieldKey));
            }
            space.setInfos(infos);
        }
        // 对象扩展属性赋值
        systemService.ensureSpecialValues(context, admSystemList);
    }

    @Override
    public List<AdmSpace> querySpaceInShaft(InstanceUrlParam context, String shaftId, String spaceType) {
        AdmQueryCriteria request = new AdmQueryCriteria();
        request.setName(AdmSpace.OBJ_TYPE);
        request.resetRelationCond(false, "ArchSubset", "Sh2Sp", spaceType, shaftId, true);
        AdmResponse rs = query(request);
        return (List<AdmSpace>) rs.getContent();
    }

    @Override
    public List<AdmSpace> querySpaceInBuilding(InstanceUrlParam context, String buildingId, String spaceType) {
        AdmQueryCriteria request = new AdmQueryCriteria();
        request.setName(AdmSpace.OBJ_TYPE);
        request.resetRelationCond(false, "ArchSubset", "Bd2Sp", spaceType, buildingId, true);
        AdmResponse rs = query(request);
        return (List<AdmSpace>) rs.getContent();
    }

    @Override
    public Map<String, List<String>> querySpaceMapInFloors(InstanceUrlParam context, List<String> floorIds, String spaceType) {
        QueryCriteria queryRequest = new QueryCriteria();
        ObjectNode criteriaRel = JsonNodeFactory.instance.objectNode();
        criteriaRel.put("graphCode", "ArchSubset");
        criteriaRel.put("relCode", "Fl2Sp");
        criteriaRel.put("relValue", spaceType);
        ArrayNode objNode = criteriaRel.putArray("objFrom");
        floorIds.forEach(floorId -> objNode.add(floorId));
        queryRequest.setCriteria(criteriaRel);
        List<ObjectRelation> relations = relationService.queryByCondition(context, queryRequest);
        if(CollUtil.isEmpty(relations)) {
            return null;
        }
        return relations.stream().collect(Collectors.groupingBy(ObjectRelation::getObjFrom,
                Collectors.mapping(ObjectRelation::getObjTo, Collectors.toList())));
    }

    @Override
    public Map<String, Set<String>> queryTrafficSpaceMap(InstanceUrlParam context, Iterable<String> spaceIds, String spaceType) {
        Map<String, Set<String>> result = new HashMap<>();
        loadTrafficSpace(context, spaceIds, spaceType, true, result);
        loadTrafficSpace(context, spaceIds, spaceType, false, result);
        return result;
    }
    /***
     * Description: 查询多建筑楼层下的空间id
     * @param request : 请求参数
     * @return : java.util.Set<java.lang.String>
     * @author : lijie
     * @date :2021/10/28 17:56
     * Update By lijie 2021/10/28 17:56
     */
    @Override
    public Set<String> queryMultiBuildingOrFloorSpaceIds(HttpServletRequest request) {
        String groupCode = AppContext.getContext().getGroupCode();
        String projectId = AppContext.getContext().getProjectId();
        // 1.查询楼层下的空间的关系统计数据
        CommonResult<List<ObjectRelation>> floorCountByObjIds = DigitalObjectSimpleFacade
                .queryRelationCountByObjIds(groupCode, projectId, AdmCommonConstant.APP_ID, AdmCommonConstant.USER_ID,
                        getMultiBuildingOrFloorQueryWrapper(request,RelCodeEnum.Fl2Sp.name()));
        List<ObjectRelation> floorSpaceData = floorCountByObjIds.getData();
        // 2.查询建筑下的空间的关系统计数据
        CommonResult<List<ObjectRelation>> buildingCountByObjIds = DigitalObjectSimpleFacade
                .queryRelationCountByObjIds(groupCode, projectId, AdmCommonConstant.APP_ID, AdmCommonConstant.USER_ID,
                        getMultiBuildingOrFloorQueryWrapper(request, RelCodeEnum.Bd2Sp.name()));
        List<ObjectRelation> buildingSpaceData = buildingCountByObjIds.getData();
        Set<String> spaceIds = CollUtil.newHashSet(CollUtil.isNotEmpty(floorSpaceData), floorSpaceData
                .stream().filter(objectRelation -> objectRelation.getCount()>1)
                .map(ObjectRelation::getObjTo).collect(Collectors.toSet()));
        spaceIds.addAll(CollUtil.newHashSet(CollUtil.isNotEmpty(buildingSpaceData),
                buildingSpaceData.stream().filter(objectRelation -> objectRelation.getCount()>1)
                        .map(ObjectRelation::getObjTo).collect(Collectors.toSet())));
        return spaceIds;
    }
    /***
     * Description: 查询多建筑楼层下的空间列表
     * @param request : 请求参数
     * @return : java.util.Set<java.lang.String>
     * @author : lijie
     * @date :2021/10/28 17:56
     * Update By lijie 2021/10/28 17:56
     */
    @Override
    public AdmResponse queryMultiBuildingOrFloorSpaces(HttpServletRequest request) {
        // 1.查询多建筑楼层下的空间id列表
        Set<String> spaceIds = queryMultiBuildingOrFloorSpaceIds(request);
        AdmQueryCriteria spaceCriteria = new AdmQueryCriteria();
        String filters = " id in ['"+ String.join("', '", spaceIds) +"'] ";
        spaceCriteria.setFilters(filters);
        AdmQueryCriteria floorCriteria = new AdmQueryCriteria();
        floorCriteria.setName("floorList");
        AdmQueryCriteria buildingCriteria = new AdmQueryCriteria();
        buildingCriteria.setName("building");
        floorCriteria.setCascade(CollUtil.newArrayList(buildingCriteria));
        spaceCriteria.setCascade(CollUtil.newArrayList(floorCriteria));
        return super.doQuery(AdmContextUtil.toDmpContext(), spaceCriteria, AdmSpace.class);
    }
    /***
     * Description: 根据查询条件查询空间统计数据
     * @param request : 请求参数
     * @return : com.persagy.proxy.adm.request.AdmResponse
     * @author : lijie
     * @date :2021/10/28 21:07
     * Update By lijie 2021/10/28 21:07
     */
    @Override
    public AdmResponse query(AdmQueryCriteria request) {
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        AdmResponse response = super.doQuery(context, request, AdmSpace.class);
        // 系统需要补充分类名称属性
        ensureSpecialValues(context, (List<AdmSpace>) response.getContent());
        return response;
    }

    /**
     * 更新轮廓线
     * @param vos
     * @return
     */
    @Override
    public AdmResponse updateOutLine(List<AdmSpace> vos) {
        InstanceUrlParam context = AdmContextUtil.toDmpContext();
        vos = super.doUpdate(context,  AdmSpace.class, vos);
        SpringHelper.getBean(IAdmSpaceService.class).processRelationType(context,vos);
        return AdmResponse.success(vos);
    }

    @Override
    public AdmResponse doUpdate(List<AdmSpace> vos) {
        if(CollUtil.isNotEmpty(vos)) {
            AdmRelationTypeEnum typeEnumBd = AdmRelationTypeEnum.BD2SP;
            AdmRelationTypeEnum typeEnumFl = AdmRelationTypeEnum.FL2SP;
            QueryCriteria criteria = new QueryCriteria();
            ObjectNode node = JsonNodeFactory.instance.objectNode();

            List<RelationDTO> relationDTOList = new ArrayList<>(vos.size());
            vos.forEach(admSpace -> {
                //处理建筑 楼层信息点
                int removeflBd = 0 ;//关系处理 0:不删除; 1:删除bd; 2:删除fl; 3:都删除;
                List<String> nullList = CollUtil.newArrayList(admSpace.getNullList());
                if(CollUtil.isNotEmpty(nullList)){
                   if(nullList.contains("flowBuild")){
                       removeflBd = 3;
                       Map<String, Object> infos = new HashMap<>(16);
                       infos.put("$remove", Arrays.asList("floorId","buildingId"));
                   }
                }
                if(StrUtil.isNotEmpty(admSpace.getFlowBuild())){
                    String flowBuild = admSpace.getFlowBuild();
                    if(!flowBuild.contains("-")){
                        if(flowBuild.startsWith("Bd")){
                            admSpace.setBuildingId(flowBuild);
                            if(StrUtil.isNotEmpty(admSpace.getFloorId())){
                                Map<String, Object> infos = new HashMap<>(16);
                                infos.put("$remove", Arrays.asList("floorId"));
                                admSpace.setInfos(infos);
                                removeflBd = 2;
                            }
                        }
                    }else {
                        String[] str = flowBuild.split("-");
                        if(str[0].startsWith("Bd")){
                            admSpace.setBuildingId(str[0]);
                            admSpace.setFloorId(str[1]);
                        }else{
                            admSpace.setBuildingId(str[1]);
                            admSpace.setFloorId(str[0]);
                        }
                        removeflBd = 3;
                    }
                    admSpace.setFlowBuild(null);
                }
                //删除关系 然后重建
                if(removeflBd == 3 || removeflBd == 2){
                    node.put("relCode", typeEnumFl.getRelCode());
                    node.put("objTo",  admSpace.getId());
                    node.put("graphCode", typeEnumFl.getGraphCode());
                    criteria.setCriteria(node);
                    relationService.doDelete(AdmContextUtil.toDmpContext(), criteria);
                }
                if(removeflBd == 3 || removeflBd == 1){
                    node.put("relCode", typeEnumBd.getRelCode());
                    node.put("objTo", admSpace.getId());
                    node.put("graphCode", typeEnumBd.getGraphCode());
                    criteria.setCriteria(node);
                    relationService.doDelete(AdmContextUtil.toDmpContext(), criteria);
                }
            });
            vos.stream().forEach(space -> {
                if (StrUtil.isNotEmpty(space.getBuildingId())) {
                    RelationDTO relationBd = new RelationDTO(null, typeEnumBd.getGraphCode(), typeEnumBd.getRelCode(), null, space.getBuildingId(), space.getId());
                    relationDTOList.add(relationBd);
                }
                if (StrUtil.isNotEmpty(space.getFloorId())) {
                    RelationDTO relationFl = new RelationDTO(null, typeEnumFl.getGraphCode(), typeEnumFl.getRelCode(), null, space.getFloorId(), space.getId());
                    relationDTOList.add(relationFl);
                }
            });
            if (CollUtil.isNotEmpty(relationDTOList)) {
                relationService.doSave(AdmContextUtil.toDmpContext(), relationDTOList);
            }
            vos = super.doUpdate(AdmContextUtil.toDmpContext(), AdmSpace.class, vos);
        }
        return AdmResponse.success(vos);
    }

    /**
     * 触发关系计算
     * @param vos
     */
    @Async
    @Override
    public void processRelationType(InstanceUrlParam context,List<AdmSpace> vos) {
        // 2021年12月15日11:12:22 by lijie
        // 更改逻辑,改为原有逻辑:仅更新计算标记.而非进行关系计算
        // 1.根据关系枚举查询对应项目的关系计算数据
        List<AdmRelationTypeEnum> admRelationTypeEnums = CollUtil.newArrayList(
                AdmRelationTypeEnum.SP2SP_SPACENEIGHBORHOOD_5,
                AdmRelationTypeEnum.SP2SP_TRAFFICNETWORK_3,
                AdmRelationTypeEnum.SP2SP_CONVECTIONNETWORK_1,
                AdmRelationTypeEnum.SP2SP_RADIATIONNETWORK_1,
                AdmRelationTypeEnum.EQ2SP_IN);
        Set<String> graphCodes = admRelationTypeEnums.stream()
                .filter(admRelationTypeEnum -> StrUtil.isNotBlank(admRelationTypeEnum.getGraphCode()))
                .map(AdmRelationTypeEnum::getGraphCode)
                .collect(Collectors.toSet());
        Set<String> relCodes = admRelationTypeEnums.stream()
                .filter(admRelationTypeEnum -> StrUtil.isNotBlank(admRelationTypeEnum.getRelCode()))
                .map(AdmRelationTypeEnum::getRelCode)
                .collect(Collectors.toSet());
        QueryCriteria queryCriteria = new QueryCriteria();
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        ObjectNode criteria = objectMapper.createObjectNode();
        criteria.putPOJO(ObjectRelation.GRAPH_CODE_HUM,graphCodes);
        criteria.putPOJO(ObjectRelation.REL_CODE_HUM,relCodes);
        criteria.put(ObjectRelation.PROP_VALID,Boolean.TRUE);
        queryCriteria.setCriteria(criteria);
        CommonResult<List<ObjectNode>> commonResult = DigitalRelationProjectCalFacade
                .queryPrototype(AppContext.getContext().getGroupCode(),
                AppContext.getContext().getProjectId(), AppContext.getContext().getAppId(),
                AppContext.getContext().getAccountId(), queryCriteria);
        if (!CommonConstant.QUERY_SUCCESS.equals(commonResult.getResult())
                || CollUtil.isEmpty(commonResult.getData())){
            return;
        }
        List<ObjectNode> updateDatas = CollUtil.newArrayList();
        // 2.过滤及处理数据
        Set<String> graphRelSet = new HashSet<>();
        graphRelSet.add(AdmRelationTypeEnum.SP2SP_SPACENEIGHBORHOOD_5.getGraphCode()+StrUtil.UNDERLINE
                +AdmRelationTypeEnum.SP2SP_SPACENEIGHBORHOOD_5.getRelCode());
        graphRelSet.add(AdmRelationTypeEnum.SP2SP_TRAFFICNETWORK_3.getGraphCode()+StrUtil.UNDERLINE
                +AdmRelationTypeEnum.SP2SP_TRAFFICNETWORK_3.getRelCode());
        graphRelSet.add(AdmRelationTypeEnum.SP2SP_CONVECTIONNETWORK_1.getGraphCode()+StrUtil.UNDERLINE
                +AdmRelationTypeEnum.SP2SP_CONVECTIONNETWORK_1.getRelCode());
        graphRelSet.add(AdmRelationTypeEnum.SP2SP_RADIATIONNETWORK_1.getGraphCode()+StrUtil.UNDERLINE
                +AdmRelationTypeEnum.SP2SP_RADIATIONNETWORK_1.getRelCode());
        for (AdmSpace admSpace : vos) {
            String classCode = admSpace.getClassCode();
            if (StrUtil.isBlank(classCode)){
                continue;
            }
            graphRelSet.add(AdmRelationTypeEnum.EQ2SP_IN.getGraphCode()+StrUtil.UNDERLINE
                    +AdmRelationTypeEnum.EQ2SP_IN.getRelCode()+StrUtil.UNDERLINE+admSpace.getClassCode());
        }
        for (ObjectNode objectNode : commonResult.getData()) {
            if (!objectNode.has(ObjectRelation.GRAPH_CODE_HUM)
                    || !objectNode.get(ObjectRelation.GRAPH_CODE_HUM).isTextual()
                    || StrUtil.isBlank(objectNode.get(ObjectRelation.GRAPH_CODE_HUM).asText())
                    || !objectNode.has(ObjectRelation.REL_CODE_HUM)
                    || !objectNode.get(ObjectRelation.REL_CODE_HUM).isTextual()
                    || StrUtil.isBlank(objectNode.get(ObjectRelation.REL_CODE_HUM).asText())){
                continue;
            }
            String key = objectNode.get(ObjectRelation.GRAPH_CODE_HUM).asText()+StrUtil.UNDERLINE
                    +objectNode.get(ObjectRelation.REL_CODE_HUM).asText();
            if (graphRelSet.contains(key)){
                objectNode.put("computationalState","2");
                updateDatas.add(objectNode);
                continue;
            }
            if (!objectNode.has("zoneType")
                    || !objectNode.get("zoneType").isTextual()
                    || StrUtil.isBlank(objectNode.get("zoneType").asText())){
                continue;
            }
            key = key+StrUtil.UNDERLINE+objectNode.get("zoneType").asText();
            if (graphRelSet.contains(key)){
                objectNode.put("computationalState","2");
                updateDatas.add(objectNode);
            }
        }
        if (CollUtil.isNotEmpty(updateDatas)){
            // 3.批量更新数据
            DigitalRelationProjectCalFacade.update(AppContext.getContext().getGroupCode(),
                    AppContext.getContext().getProjectId(), AppContext.getContext().getAppId(),
                    AppContext.getContext().getAccountId(),updateDatas);
        }
    }

    /***
     * Description: 根据查询条件查询空间统计数据，定制接口，后续可优化口
     * @param request : 请求参数
     * @return : com.persagy.proxy.adm.request.AdmResponse
     * @date :2021/10/28 21:07
     */
    private AdmResponse query(AdmDCSQueryRequest request) {
    	String orders = request.getOrders();
    	List<OrderItem> orderItem = AdmQueryCriteriaHelper.toOrderItem(orders);
    	Set<String> classCodes = StrUtil.isBlank(request.getZoneType()) ? request.getZoneTypeList() : Sets.newHashSet(request.getZoneType());
    	/*ObjectNode objectNode = objectMapper.createObjectNode();
    	ObjectNode condition = objectMapper.createObjectNode();
    	condition.put("$null", true);
    	objectNode.putPOJO("floorId", condition);*/
    	QueryCriteria queryCriteria = AdmQueryCriteriaHelper.toDmpCriteria(request);
    	ObjectNode criteria = queryCriteria.getCriteria();
    	List<ObjectNode> queryObjects = this.relationReportService.queryObjects(criteria, AppContext.getContext().getGroupCode(), AppContext.getContext().getProjectId(),
    			null, classCodes, Sets.newHashSet("space"), orderItem);
    	
        List<AdmSpace> admVOs = AdmEntityTransferUtil.toAdmMultiEntity(queryObjects, request.getProjection(), AdmSpace.class);
        // 级联查询
        processCascade(AdmContextUtil.toDmpContext(), admVOs, request.getName(), request.getCascade());
        // 设置返回值
        AdmResponse response = AdmResponse.success(admVOs);
        if(CollectionUtil.isEmpty(queryObjects)){
            response.setTotal(0L);
            response.setCount(0L);
        }else {
            response.setTotal((long) queryObjects.size());
        }
        response.setPageNumber(request.getPageNumber() == null ? 50 : request.getPageNumber());
        response.setPageSize(request.getPageSize() == null ? 1 : request.getPageSize());
        // 系统需要补充分类名称属性
        ensureSpecialValues(AdmContextUtil.toDmpContext(), admVOs);
        return response;
    }
    
    /***
     * Description: 子类重写,以便处理带buildingId
     * @param dmpRequest : 中台查询参数
     * @return : void
     * @author : lijie
     * @date :2021/10/28 20:25
     * Update By lijie 2021/10/28 20:25
     */
    @Override
    protected void processDmpCriteria(QueryCriteria dmpRequest) {
        ObjectNode criteria = dmpRequest.getCriteria();
        if (null==criteria){
            return;
        }
        
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        if (criteria.has("floorId")){
            // 有楼层id过滤
            if(!criteria.get("floorId").toString().contains("$null")) {
                ObjectNode relationTo = objectMapper.createObjectNode();
                relationTo.put("graphCode", GraphCodeEnum.ArchSubset.name());
                relationTo.put("relCode", RelCodeEnum.Fl2Sp.name());
                relationTo.set("objFrom", criteria.get("floorId"));
                criteria.set("relationTo", relationTo);
                criteria.remove("floorId");
                if (criteria.has("buildingId"))
                    criteria.remove("buildingId");
                return;
            }
        }
        if (criteria.has("buildingId")){
            // 有建筑id过滤
            ObjectNode relationTo = objectMapper.createObjectNode();
            relationTo.put("graphCode", GraphCodeEnum.ArchSubset.name());
            relationTo.put("relCode", RelCodeEnum.Bd2Sp.name());
            if(!criteria.get("buildingId").toString().contains("$null")) {
                relationTo.set("objFrom",criteria.get("buildingId"));
            }else{
                relationTo.put("$bindFlag", false);
            }
            criteria.set("relationTo",relationTo);
            criteria.remove("buildingId");
        }
    }

    /***
     * Description: 获得多建筑楼层下的空间的查询条件
     * @param request : 请求参数
     * @param relCode : 边类型
     * @return : com.fasterxml.jackson.databind.node.ObjectNode
     * @author : lijie
     * @date :2021/10/28 17:55
     * Update By lijie 2021/10/28 17:55
     */
    private ObjectNode getMultiBuildingOrFloorQueryWrapper(HttpServletRequest request,String relCode) {
        ObjectMapper objectMapper = SpringHelper.getBean(ObjectMapper.class);
        ObjectNode objectNode = objectMapper.createObjectNode();
        if (StrUtil.isNotBlank(AppContext.getContext().getProjectId())){
            objectNode.putPOJO("projectIds", Sets.newHashSet(AppContext.getContext().getProjectId()));
        }
        objectNode.putPOJO("graphCodes", Sets.newHashSet(GraphCodeEnum.ArchSubset.name()));
        objectNode.putPOJO("relCodes", Sets.newHashSet(relCode));
        objectNode.putPOJO("groups", Sets.newHashSet("objTo"));
        return objectNode;
    }

    /**
     * 装载交通关系
     * @param context
     * @param spaceIds
     * @param spaceType
     * @param isFrom
     * @param result
     */
    private void loadTrafficSpace(InstanceUrlParam context, Iterable<String> spaceIds, String spaceType, boolean isFrom, Map<String, Set<String>> result) {
        // 关系查询条件
        QueryCriteria queryRequest = new QueryCriteria();
        ObjectNode criteriaRel = JsonNodeFactory.instance.objectNode();
        criteriaRel.put("graphCode", "TrafficNetwork");
        criteriaRel.put("relValue", spaceType);
        ArrayNode objNode = criteriaRel.putArray(isFrom?"objFrom":"objTo");
        spaceIds.forEach(spaceId -> objNode.add(spaceId));
        queryRequest.setCriteria(criteriaRel);
        List<ObjectRelation> relations = relationService.queryByCondition(context, queryRequest);
        if(CollUtil.isEmpty(relations)) {
            return;
        }
        // 存入Map
        for(ObjectRelation relation:relations) {
            String key = isFrom ? relation.getObjFrom() : relation.getObjTo();
            String value = isFrom ? relation.getObjTo() : relation.getObjFrom();
            Set<String> valueList = result.get(key);
            if(CollUtil.isEmpty(valueList)) {
                valueList = new HashSet<>();
                result.put(key, valueList);
            }
            valueList.add(value);
        }
    }

    /**
     * 空间的类型是根据项目自定义的
     * 参见中心
     * @Select("SELECT s.object_type as type,d.name  FROM zone_space_base s
     * LEFT JOIN dict.dict_space_project d ON s.object_type = d.id WHERE s.project_id = #{projectId} AND d.project_id = #{projectId}
     * GROUP BY object_type, d.name")
     * @param context
     * @return
     */
    @Override
    public List<JSONObject> doQuerySpaceTypes(InstanceUrlParam context) {
        //根据项目id查询空间类型
        Map<String, String> codeNameMap = queryProjectDefineType(context);
        if(CollUtil.isNotEmpty(codeNameMap)){
            //查询object
            JSONArray demObjs = queryAndDealObjs(context, codeNameMap.keySet());
            if(CollUtil.isNotEmpty(demObjs)){
                List<AdmSpace> spaceList = JSONArray.parseArray(JSONUtil.toJsonStr(demObjs), AdmSpace.class);
                Set<String> classCodes = spaceList.stream().map(space -> space.getClassCode()).collect(Collectors.toSet());
                if(CollUtil.isNotEmpty(classCodes)){
                    codeNameMap.keySet().removeIf(code -> !classCodes.contains(code));
                }
            }
        }
        if(CollUtil.isNotEmpty(codeNameMap)){
            List<JSONObject> list = new ArrayList<>(codeNameMap.size());
            codeNameMap.keySet().stream().forEach(code ->{
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("name",codeNameMap.get(code));
                jsonObject.put("code",code);
                list.add(jsonObject);
            });
            return  list;
        }else{
            return null;
        }
    }

    private List<ObjectNode> queryObject(InstanceUrlParam context, QueryCriteria criteriaObject){
        JSONObject paraPe = null;
    	String groupCode = AppContext.getContext().getGroupCode();
		String projectId = AppContext.getContext().getProjectId();
    	List<ObjectNode> query = DigitalObjectFacade.query(groupCode, projectId, AdmCommonConstant.APP_ID, AdmCommonConstant.USER_ID, criteriaObject);
    	return query;
    }
    
    private DmpResult<JSONArray> queryObj(InstanceUrlParam context, QueryCriteria criteriaObject){
        JSONObject paraPe = null;
        try {
            String paraStr = objectMapper.writeValueAsString(criteriaObject);
            paraPe = JSONObject.parseObject(paraStr);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("转换查询条件出错：" + e.getMessage());
        }
        return rwdClient.queryObject(context, paraPe);
    }

    private QueryCriteria ensureQueryCommParm(QueryCriteria dmpRequest, InstanceUrlParam context, Collection<String> classCodes, String objType){
        ObjectNode criteriaEq = null;
        if(JSONUtil.isNull(dmpRequest.getCriteria())){
            criteriaEq = JsonNodeFactory.instance.objectNode();
        }else{
            criteriaEq = dmpRequest.getCriteria();
        }
        if(CollUtil.isNotEmpty(classCodes)){
            ArrayNode array = criteriaEq.putObject("classCode").putArray("$in");
            classCodes.forEach(code -> array.add(code));
        }
        criteriaEq.put("objType", objType);
        dmpRequest.setCriteria(criteriaEq);
        return dmpRequest;
    }

    private JSONArray queryAndDealObjs(InstanceUrlParam context, Set<String> codes){
        QueryCriteria criteriaObject = ensureQueryCommParm(new QueryCriteria(), context, codes,AdmSpace.OBJ_TYPE);
        criteriaObject.setSize(50L);
        DmpResult<JSONArray> dmpResult = queryObj(context, criteriaObject);
        if(CollUtil.isEmpty(dmpResult.getData())){
            return null;
        }
        JSONArray demObjs = dmpResult.getData();
        if(dmpResult.getCount() > criteriaObject.getSize()){
            for(int page = 2; page < dmpResult.getCount()/criteriaObject.getSize()+1; page++){
                criteriaObject.setPage(page*1L);
                demObjs.addAll(queryObj(context, criteriaObject).getData());
            }
        }
        return demObjs;
    }

    private Map<String, String> queryProjectDefineType(InstanceUrlParam context){
        Map<String, String> codeNameMap = null;
        ObjectNode criteriaEq = JsonNodeFactory.instance.objectNode();
        criteriaEq.put("projectId", context.getProjectId());
        criteriaEq.put("objType", AdmSpace.OBJ_TYPE);
        DmpResult<JSONArray> resultDef = queryDefineType(context, criteriaEq);
        if(resultDef.getResult().equals(DmpResult.SUCCESS) && CollUtil.isNotEmpty(resultDef.getData())){
            List<ObjectTypeDefine> defineList = JSONUtil.toList(resultDef.getData().toString(), ObjectTypeDefine.class);
            codeNameMap = defineList.stream().collect(Collectors.toMap(ObjectTypeDefine::getCode, ObjectTypeDefine::getName, (k1,k2)->k1));
        }
        return codeNameMap;
    }

    /**
     * 查询空间flooId对应的infos中height存在的 flool
     * @param context
     * @param floolIds
     * @return
     */
    private List<ObjectNode> queryFloorsByFloorIds(InstanceUrlParam context, Collection<String> floolIds){
        QueryCriteria queryCriteria = ensureQueryCommParm(new QueryCriteria(),context, CollUtil.newArrayList("floor"),"floor");
        ObjectNode criteriaPe = queryCriteria.getCriteria();
        if(CollUtil.isNotEmpty(floolIds)){
            ArrayNode array = criteriaPe.putObject("id").putArray("$in");
            floolIds.forEach(floorId -> array.add(floorId));
        }
        JSONObject height = new JSONObject();
        height.put("$gt", 0f);
        criteriaPe.putPOJO("height", height);
        queryCriteria.setCriteria(criteriaPe);
        queryCriteria.setWithoutCount(true);
        return queryObject(context, queryCriteria);
    }

    /**
     * space.height = floor.infos.height
     * @param spaceMapByFlId
     * @param floorList
     * @return
     */
    private List<AdmSpace> processHeight(Map<String, List<AdmSpace>> spaceMapByFlId, List<ObjectNode> floorList){
    	List<AdmSpace> resultList = new ArrayList<>();
    	floorList.forEach(node -> {
    		try {
    		    if (!node.has("id")
                        || !node.get("id").isTextual()){
    		        return;
                }
                List<AdmSpace> spaces = spaceMapByFlId.get(node.get("id").asText());
    		    if (CollUtil.isEmpty(spaces)){
    		        return;
                }
                if(node.has("height")){
                	String height = node.get("height").asText();
                	if (StrUtil.isNotBlank(height)) {
                        for (AdmSpace admSpace : spaces) {
                            admSpace.setHeight(Double.parseDouble(height));
                            resultList.add(admSpace);
                        }
					}
                }
			} catch (Exception e) {}
        });
        return resultList;
    }

    /**
     * 添加绑定关系
     */
    private void processRelations(List<AdmSpace> vosR){
        if(CollUtil.isNotEmpty(vosR)) {
            List<RelationDTO> relationDTOS = new ArrayList<>(vosR.size());
            vosR.forEach(admSpace -> {
                if (StrUtil.isNotEmpty(admSpace.getBuildingId())) {
                    relationDTOS.add(new RelationDTO("GtArchSubset001", "ArchSubset", "Bd2Sp", admSpace.getClassCode(), admSpace.getBuildingId(), admSpace.getId()));
                }
                if (StrUtil.isNotEmpty(admSpace.getFloorId())) {
                    relationDTOS.add(new RelationDTO("GtArchSubset001", "ArchSubset", "Fl2Sp", admSpace.getClassCode(), admSpace.getFloorId(), admSpace.getId()));
                }
            });
            if (CollUtil.isNotEmpty(relationDTOS)) {
                InstanceUrlParam context = AdmContextUtil.toDmpContext();
                relationService.doSave(context, relationDTOS);
            }
        }
    }

    /**
     * 转换为目标实体,并增加属性
     */
    private void assembleDefineTypes(InstanceUrlParam context, List<JSONObject> defineList, String floorId){
        boolean needCount = true;
        defineList.stream().forEach(defineType -> {
            //查询空间数量
            int count = needCount ? countSpace(context, defineType.getString("code"), floorId) : 0;
            //处理单个对象
            assembleDefineObj(defineType, count, context.getProjectId());
        });
    }

    /**
     * 单个转换为目标实体,并增加属性
     */
    private void assembleDefineObj(JSONObject defineType, int count, String projectId){
        defineType.put("count", count);
        defineType.put("projectId", projectId);
        defineType.remove("aliasName");
        defineType.remove("aliasCode");
        defineType.remove("valid");
        defineType.remove("objType");
        defineType.remove("groupCode");
        defineType.remove("parentCode");
        defineType.remove("id");
    }

    private void addRelationTo(QueryCriteria rwdQueryCriteria, String objFrom, String relCode){
        ObjectNode relationTO = JsonNodeFactory.instance.objectNode();
        relationTO.put("relCode", relCode);
        relationTO.put("graphCode", "ArchSubset");
        relationTO.put("objFrom", objFrom);
        ObjectNode criteria = rwdQueryCriteria.getCriteria();
        criteria.putPOJO("relationTo", relationTO);
        rwdQueryCriteria.setCriteria(criteria);
    }

    /**
     *  查询存在空间的数量
     * @param context
     * @param classCode
     * @param objFrom
     * @return
     */
    private int countSpace(InstanceUrlParam context, String classCode, String objFrom){
        QueryCriteria queryCriteriaSpace = new QueryCriteria();
        ObjectNode criteria = JsonNodeFactory.instance.objectNode();
        criteria.put("state", 1);
        queryCriteriaSpace.setCriteria(criteria);
        QueryCriteria queryCriteria = ensureQueryCommParm(queryCriteriaSpace, context, CollUtil.newArrayList(classCode),"space");
        addRelationTo(queryCriteria, objFrom,"Fl2Sp");
        queryCriteria.setOnlyCount(true);
        DmpResult<JSONArray> dmpResult = queryObj(context, queryCriteria);
        return dmpResult.getCount();
    }


    private DmpResult<JSONArray> queryDefineType(InstanceUrlParam context, ObjectNode criteriaEq){
        QueryCriteria criteriaObject = new QueryCriteria();
        criteriaObject.setCriteria(criteriaEq);
        JSONObject paraPe = null;
        try {
            String paraStr = objectMapper.writeValueAsString(criteriaObject);
            paraPe = JSONObject.parseObject(paraStr);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("查询公共定义的空间类型，转换查询条件出错：" + e.getMessage());
        }
        return rwdClient.queryDefClass(context, paraPe);
    }


}
