package com.yeejoin.equipmanage.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.component.feign.utils.FeignUtil;
import com.yeejoin.amos.feign.morphic.Morphic;
import com.yeejoin.amos.feign.morphic.model.ResourceDTO;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.amos.feign.systemctl.model.DictionarieValueModel;
import com.yeejoin.equipmanage.common.entity.*;
import com.yeejoin.equipmanage.common.entity.dto.BuildIsRiskDTO;
import com.yeejoin.equipmanage.common.entity.dto.BuildSearchDTO;
import com.yeejoin.equipmanage.common.entity.vo.*;
import com.yeejoin.equipmanage.common.enums.GroupCodeEnum;
import com.yeejoin.equipmanage.common.enums.GroupTypeEnum;
import com.yeejoin.equipmanage.common.enums.IndustryEnum;
import com.yeejoin.equipmanage.common.enums.StroageTankEnum;
import com.yeejoin.equipmanage.common.utils.EnumsUtils;
import com.yeejoin.equipmanage.common.utils.StringUtil;
import com.yeejoin.equipmanage.common.vo.AlarmDataVO;
import com.yeejoin.equipmanage.common.vo.BuildingTreeAndEquipVO;
import com.yeejoin.equipmanage.common.vo.BuildingTreeVo;
import com.yeejoin.equipmanage.context.SpringContextHolder;
import com.yeejoin.equipmanage.event.SyncRiskEvent;
import com.yeejoin.equipmanage.mapper.*;
import com.yeejoin.equipmanage.operation.GroupTypeOperator;
import com.yeejoin.equipmanage.operation.PageOperation;
import com.yeejoin.equipmanage.operation.SyncRiskOperator;
import com.yeejoin.equipmanage.operation.factory.PageOperatorFactory;
import com.yeejoin.equipmanage.remote.RemoteSecurityService;
import com.yeejoin.equipmanage.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.typroject.tyboot.core.foundation.exception.BaseException;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ZeHua Li
 * @date 2020/11/12 15:48
 * @since v2.0
 */
@Slf4j
@Service
public class BuildingServiceImpl extends ServiceImpl<BuildingMapper, Building> implements IBuilldService {

    @Autowired
    ISystemDicService systemDicService;

    @Autowired
    private IFormGroupService iFormGroupService;

    @Autowired
    private ISourceFileService iSourceFileService;

    @Autowired
    private RemoteSecurityService remoteSecurityService;

    @Autowired
    private FireFightingSystemServiceImpl fireFightingSystemService;

    @Autowired
    private IFormInstanceService iFormInstanceService;

    @Autowired
    private FormInstanceMapper formInstanceMapper;

    @Autowired
    FireFightingSystemMapper fireFightingSystemMapper;

    @Autowired
    IWarehouseStructureService iWarehouseStructureService;

    @Autowired
    StockDetailMapper stockDetailMapper;
    @Autowired
    ISourceSceneService sourceSceneService;

    @Value("${morphic.projectSeq}")
    private Long projectSeq;

    @Value("${mqtt.scene.host}")
    private String sceneUrl;

    @Value("${equip.point.equipmentdata.topic}")
    private String wsTopic;

    @Value("${systemctl.dict.allow-operation}")
    private String allowOperation;

    @Value("${systemctl.dict.build-type}")
    private String buildType;

    @Value("${systemctl.dict.build-use-type}")
    private String buildUseType;

    @Value("${systemctl.dict.building-structure-type}")
    private String buildingStructureType;

    @Value("${systemctl.sync.switch}")
    private Boolean syncSwitch;

    @Autowired
    private SourceSceneMapper sourceSceneMapper;

    @Autowired
    VideoMapper videoMapper;

    @Autowired
    EquipmentSpecificRelationMapper equipmentSpecificRelationMapper;

    @Autowired
    private ISyncDataService syncDataService;

    @Autowired
    @Lazy
    private IVideoService videoService;
    
    @Value("${building.detail}")
    private String address;
    
    @Value("${building.floor.detail}")
    private String apiUrl;
    
    @Value("${firefightingsystem.equip.alarms.url}")
    private String ffsEquipAlarmsUrl;

    /**
     * @param groupCode
     * @Description 根据groupCode查询allowOperation对应的操作菜单
     * @Return List<DictionarieValueModel>
     * @Date 2020/12/18 10:13
     */
    @Override
    public List<DictionarieValueModel> rightClickMenu(String groupCode) {
        FeignClientResult<List<DictionarieValueModel>> dictValues = Systemctl.dictionarieClient.dictValues(allowOperation);
        Optional.ofNullable(dictValues).orElseThrow(() -> new BadRequest("查询字段数据为空"));
        log.info("字典数据：{}", dictValues.getResult().toString());
        FormGroup formGroup = iFormGroupService.allowOperationByGroupCode(groupCode);
        String[] array = formGroup.getAllowOperation().split(",");
        List<DictionarieValueModel> values = dictValues.getResult();
        List<DictionarieValueModel> models = new ArrayList<>();
        Arrays.stream(array).forEach(item -> {
            models.addAll(values.stream()
                    .filter(o -> o.getDictDataKey().equals(item))
                    .collect(Collectors.toList()));
        });
        return models;
    }

    @Override
    public Map<String, String> createMorphic(Map<String, String> model) {
        ResourceDTO resourceDTO = new ResourceDTO();
        resourceDTO.setSubjectId(projectSeq);
        resourceDTO.setSubjectid(projectSeq);
        resourceDTO.setName(model.get("name"));
        // 为首次 添加的画布添加mqtt 相关数据
        String content = "{\"layout\":\"\",\"boardConfig\":{\"modeType\":\"custom\",\"orientation\":\"lengthways\",\"autoRefresh\":true,\"name\":\"1\",\"showMode\":\"actual\",\"paperSize\":\"1280X900\"},\"boardStyle\":{\"backgroundImage\":\"\"},\"dataConfig\":{}}";
        Map parse = (Map) JSON.parse(content);
        Map<String, Object> dataConfig = new HashMap<>();
        dataConfig.put("msgType", "mqtt");
        dataConfig.put("wsUrl", sceneUrl);
        dataConfig.put("wsTopic", wsTopic);
        parse.put("dataConfig", dataConfig);
        content = JSONObject.toJSONString(parse);
        resourceDTO.setContent(content);
        ResourceDTO morphic = Morphic.morphicSubjectClient.create(resourceDTO).getResult();
        model.put("sceneId", String.valueOf(morphic.getId()));
//        model.put("id", String.valueOf(System.currentTimeMillis()));
//        model.put("projectId", String.valueOf(projectSeq));
//        model.put("creatorId", userId);
//        this.baseMapper.insetSourceScene(model);
        return model;
    }

    @Override
    @Transactional
    public ResourceDTO updateMorphic(ResourceDTO resourceDTO) {
        try {
            resourceDTO.setSubjectId(projectSeq);
            resourceDTO.setSubjectid(projectSeq);
            String content = resourceDTO.getContent();
            Map parse = (Map) JSON.parse(content);
            Map<String, Object> dataConfig = new HashMap<>();
            dataConfig.put("msgType", "mqtt");
            dataConfig.put("wsUrl", sceneUrl);
            dataConfig.put("wsTopic", wsTopic);
            parse.put("dataConfig", dataConfig);
            content = JSONObject.toJSONString(parse);
            resourceDTO.setContent(content);
            FeignUtil.remoteCall(() -> Morphic.morphicSubjectClient.update(resourceDTO));
            //获取画布id
            Long sceneId = resourceDTO.getId();
            SourceScene sourceScene = sourceSceneMapper.selectOne(new QueryWrapper<SourceScene>().eq("scene_id", sceneId));
            if (sourceScene == null) {
                String userId = remoteSecurityService.getAgencyUser().getUserId();
                Map<String, Object> model = new HashMap<>();
                model.put("sceneId", sceneId);
                model.put("id", String.valueOf(System.currentTimeMillis()));
                model.put("projectId", String.valueOf(projectSeq));
                model.put("creatorId", userId);
                model.put("instanceId", resourceDTO.getCode());
                model.put("name", resourceDTO.getName());
                this.baseMapper.insetSourceScene(model);
            }
            //获取画布下 绑定的装备点
            List<Map> children = (List<Map>) parse.get("children");
            String pointInScene = "";
            String videoInScene = "";
            if (!CollectionUtils.isEmpty(children)) {
                for (Map<String, String> map : children) {
                    String key = map.get("key");
                    if (!"".equals(key) && "equipment".equals(key)) {
                        pointInScene = "".equals(pointInScene) ? map.get("sequenceNbr") : pointInScene + "," + map.get("sequenceNbr");
                    }
                    if (!"".equals(key) && "video".equals(key)) {
                        videoInScene = "".equals(videoInScene) ? map.get("sequenceNbr") : videoInScene + "," + map.get("sequenceNbr");
                    }
                }
            }
            this.baseMapper.setSceneId(sceneId, pointInScene, videoInScene);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BadRequest("保存画布失败");
        }
        return resourceDTO;
    }

    @Override
    public Boolean isDeleteCanvas(Long id) {
        SourceScene sourceScene = sourceSceneMapper.selectOne(new QueryWrapper<SourceScene>().eq("scene_id", id));
        if (sourceScene != null) {
            return true;
        } else {
            FeignUtil.remoteCall(() -> Morphic.morphicSubjectClient.delete(id));
            return false;
        }
    }

    @Override
    public List<SourceScene> getScenesList(Long id, String groupType) {
        List<SourceScene> list;
        try {
            if (groupType.equals("room")) {
                // 获取房间绑定关系，如为建筑，返回建筑id，否则返回null
                Long buildingId = this.baseMapper.isBuildingRoom(id);
                if (buildingId != null) {
                    id = buildingId;
                    groupType = "building";
                }
            }
            list = this.baseMapper.getScenesList(id, groupType);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BadRequest("查询失败");
        }
        return list;
    }

    @Override
    public List<EquiplistSpecificBySystemVO> getEquipBySceneId(Long id) {
        String pointInScene = this.baseMapper.getPointInScene(id);
        String vPointInScene = this.baseMapper.getVPointInScene(id);
        if (("".equals(pointInScene) || pointInScene == null) && ("".equals(vPointInScene) || vPointInScene == null)) {
            return new ArrayList<>();
        }
        String[] ids = pointInScene.split(",");
        String[] vids = vPointInScene.split(",");
        List<EquiplistSpecificBySystemVO> list = new ArrayList<>();
        list.addAll(this.baseMapper.getEquipBySceneId(ids));
        list.addAll(this.baseMapper.getVideoBySceneId(vids));

        return list;
    }

    @Override
    public Object saveForm(String groupCode, String companyCode, Map<String, Object> map) {
        final String instanceId = "instanceId";
        //1.保存表单数据
        Map<String, Object> formKeyMap = iFormInstanceService.createByMap(groupCode, companyCode, map);
        if (formKeyMap.get(instanceId) != null) {
            //2.保存图片
            this.saveFiles(Long.parseLong(formKeyMap.get("instanceId").toString()), map);
            synWarehouse(formKeyMap);
            // 新增储罐类型，保存不需要风险
            if(!"storageTank".equals(groupCode)) {
                // 发布风险区域同步操作事件
                map.put("instanceId", formKeyMap.get("instanceId"));
                map.put("code", formKeyMap.get("code"));
                map.put("name", formKeyMap.get("name"));
                map.put("companyCode", companyCode);
                SpringContextHolder.publishEvent(new SyncRiskEvent(this, map, SyncRiskOperator.ADD.getType()));
            }
        }
        return formKeyMap;
    }

    private void synWarehouse(Map<String, Object> formKeyMap) {
        String parentId = (String) formKeyMap.get("parentId");
        if ("0".equals(parentId)) {
            formKeyMap.put("address", formKeyMap.get("name"));
        } else {
            String stuctureName = formInstanceMapper.getStuctureName(parentId);
            formKeyMap.put("address", stuctureName + "-" + formKeyMap.get("name"));
        }
        formInstanceMapper.saveStucture(formKeyMap);

    }

    @Override
    @Transactional(rollbackFor = {Exception.class, BaseException.class})
    public Object updateForm(Long instanceId, String orgCode, Map<String, Object> map) {
        Long id = formInstanceMapper.getStructureParentId(String.valueOf(instanceId));
        //1.保存图片
        this.saveFiles(instanceId, map);
        //2.修改仓库对应数据
        String beforFullName = formInstanceMapper.getStuctureName(String.valueOf(instanceId));
        String stuName = formInstanceMapper.getStuName(String.valueOf(instanceId));
        String name = (String) map.get("name");
        String parentId = (String) map.get("parentId");
        String fullName = name;
        String code =  (String) map.get("code");
        String parentName = formInstanceMapper.getStuctureName(parentId);
        if (!"0".equals(parentId)) {
            fullName = parentName + '-' + name;
        }
        formInstanceMapper.updateStr(instanceId, name, fullName, parentId, code);
        //3.修改仓库对应子数据
        fullName = "0".equals(parentId) ? name + "-" : "-" + name;
        name = beforFullName + "-";
        if (!"0".equals(parentId)) {
            name = "-" + stuName;
        }
        formInstanceMapper.updateStrFullName(instanceId, name, fullName);
        //4.保存表单数据
        if (map.get("isRisk").equals("false")) {
            map.remove("riskPointId");
        }
        Map<String, Object> formKeyMap = iFormInstanceService.updateInstance(instanceId, orgCode, map);
        // 同步统计表数据
        if (!Long.valueOf(parentId).equals(id)) {
            List<SourceScene> bySourceId = sourceSceneService.findBySourceId(instanceId);
            if (bySourceId != null && bySourceId.size() > 0) {
                String equipIds = bySourceId.get(0).getPointInScene();
                List<String> equipIdList = new ArrayList<>();
                if (StringUtil.isNotEmpty(equipIds)) {
                    if (-1 != equipIds.indexOf(",")) {
                        equipIdList = Arrays.asList(equipIds.split(","));
                    } else {
                        equipIdList.add(equipIds);
                    }
                }
            }
        }
        // 发布风险区域同步操作事件
        map.put("instanceId", formKeyMap.get("instanceId"));
        map.put("code", formKeyMap.get("code"));
        map.put("name", formKeyMap.get("name"));
        map.put("companyCode", orgCode);
        SpringContextHolder.publishEvent(new SyncRiskEvent(this, map, SyncRiskOperator.UPDATE.getType()));
        return formKeyMap;
    }

    @Override
    public List<BuildingTreeVo> getBuildingTree() {
        List<BuildingTreeVo> allListVo = getBuildingTreeVos();
        return allListVo.stream().filter(s -> "-1".equals(s.getParentId())).map(s -> {
            BuildingTreeVo t = new BuildingTreeVo();
            Bean.copyExistPropertis(s, t);
            t.setChildren(this.getChildren(t.getInstanceId(), allListVo));
            t.setDetailPaneApi(address);
            t.setApiUrl(apiUrl);
            return t;
        }).collect(Collectors.toList());
    }

    private List<BuildingTreeVo> getBuildingTreeVos() {
        FormGroup formGroup = iFormGroupService.getByUniqueKey(GroupCodeEnum.ALL_BUILDING.getGroupCode());
        List<Map<String, Object>> allList = iFormInstanceService.getSpecialChildrenList(null);
        List<BuildingTreeVo> allListVo = buildBuildingData(formGroup, allList);
        Map<Long, String> absolutePositionMap = getBuildingAbsolutePosition(allListVo);
        allListVo.forEach(s -> s.setAbsolutePosition(absolutePositionMap.get(s.getId())));
        return allListVo;
    }

    @Override
    public List<BuildingTreeVo> getBuildingTierTree(Integer tier) {
        if (tier != null) {
            List<BuildingTreeVo> list = getBuildingTreeVos();
            if (!CollectionUtils.isEmpty(list)) {
                if (tier == 1) {
                    List<BuildingTreeVo> collect = list.stream().filter(x -> "-1".equals(x.getParentId()) || "building".equalsIgnoreCase(x.getGroupType())).collect(Collectors.toList());
                    final List<BuildingTreeVo> collect1 = collect.stream().filter(s -> "-1".equals(s.getParentId())).collect(Collectors.toList());
                    final List<BuildingTreeVo> collect2 = list.stream().filter(s -> "-1".equals(s.getParentId())).collect(Collectors.toList());
                    return collect.stream().filter(s -> "-1".equals(s.getParentId())).map(s -> {
                        BuildingTreeVo t = new BuildingTreeVo();
                        Bean.copyExistPropertis(s, t);
                        t.setChildren(this.getChildren(t.getInstanceId(), collect));
                        t.setDetailPaneApi(address);
                        t.setApiUrl(apiUrl);
                        return t;
                    }).collect(Collectors.toList());
                } else if (tier == 2) {
                    List<BuildingTreeVo> collect = list.stream().filter(x -> !"room".equalsIgnoreCase(x.getGroupType())).collect(Collectors.toList());
                    return list.stream().filter(s -> "-1".equals(s.getParentId())).map(s -> {
                        BuildingTreeVo t = new BuildingTreeVo();
                        Bean.copyExistPropertis(s, t);
                        t.setChildren(this.getChildren(t.getInstanceId(), collect));
                        t.setDetailPaneApi(address);
                        t.setApiUrl(apiUrl);
                        return t;
                    }).collect(Collectors.toList());
                } else {
                    return getBuildingTree();
                }
            }
            return Lists.newArrayList();
        } else {
            return getBuildingTree();
        }
    }

    private List<BuildingTreeVo> buildBuildingData(FormGroup formGroup, List<Map<String, Object>> allList) {
        List<BuildingTreeVo> allListVo = Bean.listMap2ListBean(allList, BuildingTreeVo.class);
        BuildingTreeVo treeNode = new BuildingTreeVo();
        treeNode.setDetailPaneApi(address);
        treeNode.setApiUrl(apiUrl);
        treeNode.setInstanceId(formGroup.getId());
        treeNode.setInstanceName(formGroup.getGroupName());
        treeNode.setParentId("-1");
        treeNode.setGroupType(formGroup.getGroupType());
        treeNode.setGroupCode(formGroup.getGroupCode());
        allListVo.add(treeNode);
        return allListVo;
    }

    private List<BuildingTreeVo> getChildren(Long parentId, List<BuildingTreeVo> allListVo) {
        List<BuildingTreeVo> children = new ArrayList<>();
        allListVo.stream().filter(a -> a.getParentId().equals(String.valueOf(parentId))).forEach(s -> {
            s.setChildren(this.getChildren(s.getInstanceId(), allListVo));
            s.setDetailPaneApi(address);
            s.setApiUrl(apiUrl);
            s.setDetailListPaneApi(ffsEquipAlarmsUrl);
            children.add(s);
        });
        return children;
    }

    @Override
    public List<PointTreeVo> getBuildTree() {
        List<PointTreeVo> responses = this.baseMapper.getBuildList();
        // id为null 避免查询时按系统点位图逻辑查询
        return fireFightingSystemService.transferListToPointTree(responses, null);
    }

    @Override
    public List<PointTreeVo> get3dBuildTree() {
        List<PointTreeVo> responses = this.baseMapper.getBuildList();
        return fireFightingSystemService.transferListTo3dPointTree(responses);
    }

    @Override
    public Map<String, Object> buildingDetail(Long instanceId) {
        return iFormInstanceService.queryForMap(instanceId);
    }

    @Override
    @Transactional
    public Boolean deleteBuilding(Long instanceId) {
        List<StockDetail> list = stockDetailMapper.selectList(new QueryWrapper<StockDetail>().eq("warehouse_structure_id", instanceId));
        if (list != null && list.size() > 0) {
            throw new BadRequest("该建筑存在入库装备，无法直接删除");
        }
        stockDetailMapper.clearWareHouse(instanceId);
        Boolean flag = iFormInstanceService.deleteInstanceById(instanceId);
        if (flag && syncSwitch) {
            //数据同步
            syncDataService.syncDeletedBuilding(Arrays.asList(instanceId));
            syncDataService.syncDeletedFloor(Arrays.asList(instanceId));
            syncDataService.syncDeletedRoom(Arrays.asList(instanceId));
        }
        List<SourceScene> bySourceId = sourceSceneService.findBySourceId(instanceId);
        if (bySourceId != null && bySourceId.size() > 0) {
            Long id = bySourceId.get(0).getId();
            Long sceneId = bySourceId.get(0).getSceneId();
            sourceSceneService.removeById(id);
            FeignUtil.remoteCall(() -> Morphic.morphicSubjectClient.delete(sceneId));
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("instanceId", instanceId);
        SpringContextHolder.publishEvent(new SyncRiskEvent(this, map, SyncRiskOperator.DELETE.getType()));
        return flag;
    }

    @Override
    public Map<String, Object> getAllPermission() {
        return iFormGroupService.getAllOperation();
    }

    @Override
    public Map<String, Object> getEveryCount(Long id, String groupType) {
        Map<String, Object> map = new HashMap<>();
        if ("".equals(groupType) || "allBuilding".equals(groupType) || groupType == null) {
            map.put("error", "类型填写错误");
            return map;
        }
        if ("allfloor".equals(groupType)) {
            List<FormInstance> allfloorCount = this.baseMapper.getAllfloorCount(id);
            map.put("res", allfloorCount);
            return map;
        }
        Long equipCount = this.baseMapper.getEquipmentCount(id, groupType);
        map.put("equipCount", equipCount);
        if ("room".equals(groupType)) {
            return map;
        }
        if ("floor".equals(groupType)) {
            Long roomCount = this.baseMapper.getFloorOrRoomCount(id, groupType);
            map.put("roomCount", roomCount);
        }
        if ("building".equals(groupType)) {
            Long floorCount = this.baseMapper.getFloorOrRoomCount(id, groupType);
            Long roomCount = this.baseMapper.getRoomCount(id);
            map.put("floorCount", floorCount);
            map.put("roomCount", roomCount);
        }
        return map;
    }

    /**
     * 保存图片
     * sourceId 数据拥有者
     *
     * @param map 集合
     */
    @Transactional(rollbackFor = {Exception.class, BaseException.class})
    public void saveFiles(Long sourceId, Map<String, Object> map) {
        List<SourceFile> sourceFiles = new ArrayList<>();
        String fileKey = "files";
        if (map.get(fileKey) != null) {
            sourceFiles = JSONObject.parseArray(JSONObject.toJSON(map.get(fileKey)).toString(), SourceFile.class);
            iSourceFileService.saveSourceFile(sourceId, sourceFiles);
        }
    }

    /**
     * @param dto 查询参数
     * @Description 分页查询
     * @Return Page
     * @Date 2020/12/19 11:47
     */
    @Override
    public Page buildingList(Page page, BuildSearchDTO dto) {
        Optional.ofNullable(dto.getInstanceId()).orElseThrow(() -> new BadRequest("instanceId参数不能为空"));
        Optional.ofNullable(dto.getGroupType()).orElseThrow(() -> new BadRequest("groupType参数不能为空"));
        // 根据不同的groupType 查询分页
        PageOperation targetOperation = PageOperatorFactory
                .getOperation(dto.getGroupType())
                .orElseThrow(() -> new BadRequest("Invalid Operator"));
        return targetOperation.apply(page, dto);
    }

    /**
     * @param dto 查询参数
     * @Description 建筑楼层分页查询
     * @Return Page
     * @Date 2020/12/19 11:47
     */
    @Override
    public Page floorPage(Page page, BuildSearchDTO dto) {
        Page pageData = iFormInstanceService.roomPage(page, dto);
        pageData.getRecords().parallelStream().forEach(item -> {
            Map<String, Object> map = (Map<String, Object>) item;
            Long eqTotalNum = equipmentTotal(Long.valueOf(String.valueOf(map.get("instanceId").toString())), GroupTypeEnum.ROOM.getType());
            this.files(map);
            this.sourceBuild(map);
            map.put("equipmentTotal", eqTotalNum);
        });
        return pageData;
    }

    /**
     * @param page
     * @param dto
     * @Description 房间
     * @Return Page
     * @Date 2020/12/22 13:55
     */
    @Override
    public Page roomPage(Page page, BuildSearchDTO dto) {
        Page pageData = iFormInstanceService.roomPage(page, dto);
        pageData.getRecords().parallelStream().forEach(item -> {
            Map<String, Object> map = (Map<String, Object>) item;
            Long eqTotalNum = equipmentTotal(Long.valueOf(String.valueOf(map.get("instanceId").toString())), GroupTypeEnum.ROOM.getType());
            this.files(map);
            this.sourceBuild(map);
            map.put("equipmentTotal", eqTotalNum);
        });
        return pageData;
    }

    /**
     * @param instanceId
     * @Description 构建设备，房间，建筑所属
     * @Description 构建设备，房间，建筑所属
     * @Return int
     * @Date 2020/12/21 13:55
     */
    @Override
    public Long equipmentTotal(Long instanceId, String groupType) {
        Map<String, Object> map = getEveryCount(instanceId, groupType);
        return Long.parseLong(String.valueOf(map.get("equipCount")));
    }

    public Map<String, Object> getAllOperation() {
        return iFormGroupService.getAllOperation();
    }

    /**
     * @param map
     * @Description 所属楼层
     * @Date 2020/12/22 11:29
     */
    @Override
    public void sourceBuild(Map<String, Object> map) {
        Optional<GroupTypeOperator> m = EnumsUtils.getEnumObject(GroupTypeOperator.class,
                e -> e.getType().equals(String.valueOf(map.get("groupType"))));
        calculate(map, m.get());
    }

    public void calculate(Map<String, Object> map, GroupTypeOperator operator) {
        operator.apply(map);
    }

    /**
     * @param coll
     * @Description 统计房间数
     * @Date 2020/12/22 15:33
     */
    @Override
    public void roomNum(List<Map<String, Object>> coll, Map<String, Object> map) {
        //建筑底下的房间
        int roomNum = coll.parallelStream().filter(o -> o.get("groupType").equals(GroupTypeEnum.ROOM.getType())).collect(Collectors.toList()).size();
        //建筑底下楼层底下的房间
        List<Long> floorInstanceId = new ArrayList<>();
        coll.parallelStream().forEach(c -> {
            floorInstanceId.add(Long.parseLong(c.get("instanceId").toString()));
        });
        if (!CollectionUtils.isEmpty(floorInstanceId)) {
            List<Map<String, Object>> rooms = iFormInstanceService.queryFloorRoom(floorInstanceId);
            int floorRoomNum = rooms.parallelStream().filter(o -> o.get("groupType").equals(GroupTypeEnum.ROOM.getType())).collect(Collectors.toList()).size();
            map.put("roomNum", roomNum + floorRoomNum);
        } else {
            map.put("roomNum", roomNum);
        }
    }

    /**
     * @param map
     * @Description 文件
     * @Return
     * @Exception
     * @Date 2020/12/22 19:39
     */
    @Override
    public void files(Map<String, Object> map) {
        List<SourceFile> sourceFiles = iSourceFileService.findBySourceId(Long.parseLong(String.valueOf(map.get("instanceId"))));
        map.put("files", sourceFiles);
    }

    @Override
    public List<BuildingTreeVo> getBuildingVideoTree() {
        FormGroup formGroup = iFormGroupService.getByUniqueKey(GroupCodeEnum.ALL_BUILDING.getGroupCode());
        List<Map<String, Object>> allList = iFormInstanceService.getBuildVideoListCount();
        List<BuildingTreeVo> allListVo = buildColaBuildingData(formGroup, allList);
        // tree 统计处理
        return allListVo.stream().filter(s -> "-1".equals(s.getParentId())).map(s -> {
            BuildingTreeVo t = new BuildingTreeVo();
            Bean.copyExistPropertis(s, t);
            Map<String, Object> childrenTotal = this.getChildrenTotal(t.getInstanceId(), allListVo);
            t.setChildren((List<BuildingTreeVo>) childrenTotal.get("list"));
            t.setTotal((Long) childrenTotal.get("total"));
            t.setDetailPaneApi(address);
            return t;
        }).collect(Collectors.toList());
    }

    private List<BuildingTreeVo> buildColaBuildingData(FormGroup formGroup, List<Map<String, Object>> allList) {
        List<BuildingTreeVo> allListVo = Bean.listMap2ListBean(allList, BuildingTreeVo.class);
        BuildingTreeVo treeNode = new BuildingTreeVo();
        treeNode.setDetailPaneApi(address);
        treeNode.setInstanceId(formGroup.getId());
        treeNode.setInstanceName(formGroup.getGroupName());
        treeNode.setParentId("-1");
        treeNode.setGroupType(formGroup.getGroupType());
        treeNode.setGroupCode(formGroup.getGroupCode());
        allListVo.add(treeNode);
        return allListVo;
    }

    /**
     * 子集统计求和
     *
     * @param parentId  父级id
     * @param allListVo 所属有数据
     * @return
     */
    private Map<String, Object> getChildrenTotal(Long parentId, List<BuildingTreeVo> allListVo) {
        if (parentId == null || (allListVo == null && allListVo.size() == 0)) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        List<BuildingTreeVo> children = new ArrayList<>();
        BigDecimal total = BigDecimal.ZERO;
        List<BuildingTreeVo> childrenFilter = new ArrayList<>();
        for (BuildingTreeVo buildingTreeVo : allListVo) {
            if (buildingTreeVo.getParentId().equals(String.valueOf(parentId))) {
                childrenFilter.add(buildingTreeVo);
            }
        }
        if (childrenFilter.size() > 0) {
            total = BigDecimal.ZERO;
            for (BuildingTreeVo s : childrenFilter) {
                Map<String, Object> childrenTotal = this.getChildrenTotal(s.getInstanceId(), allListVo);
                List<BuildingTreeVo> childrens = (List<BuildingTreeVo>) childrenTotal.get("list");
                s.setChildren(childrens);
                if (childrens.size() > 0) {
                    s.setTotal(new BigDecimal(s.getTotal().toString()).add(new BigDecimal(childrenTotal.get("total").toString())).longValue());
                }
                children.add(s);
                total = total.add(new BigDecimal(s.getTotal().toString()));
            }
        }
        map.put("list", children);
        map.put("total", total.longValue());
        return map;
    }

    @Override
    public Page<BuildingVideoVO> buildingVideoList(Page page, BuildingVideoListVO dto) {
        Page<BuildingVideoVO> pages = videoService.pageBuildingVideo(page, dto);
        if (0 < pages.getRecords().size()) {
            pages.getRecords().forEach(x -> {
                if (StringUtil.isNotEmpty(x.getLocation()) && StringUtil.isNotEmpty(x.getAddress())) {
                    x.setLocation(x.getLocation() + '-' + x.getAddress());
                } else {
                    if (!StringUtil.isNotEmpty(x.getLocation())) {
                        x.setLocation(x.getAddress());
                    }
                }
                x.setUrl(videoService.getVideoUrl(x.getName(), x.getPresetPosition(), x.getUrl(), x.getCode()));
            });
        }
        return pages;
    }

    @Override
    public List<BuildingListVO> getFireEquipByVideoId(Long videoId) {
        return videoService.getFireEquipByVideoId(videoId);
    }

    @Override
    public List<BuildingListVO> getPowerEquipByVideoId(Long videoId) {
        return videoService.getPowerEquipByVideoId(videoId);
    }

    @Override
    public List<BuildIsRiskDTO> getChildrenNotIsRiskList(String instanceId) {
        return formInstanceMapper.getChildrenNotIsRiskList(instanceId);
    }

    @Override
    public void unbindRelation(Long instanceId) {
        iFormInstanceService.unbindRegionRelation(instanceId);
    }

    @Override
    public List<BuildingTreeVo> getBuildingVideoColaTree() {
        FormGroup formGroup = iFormGroupService.getByUniqueKey(GroupCodeEnum.ALL_BUILDING.getGroupCode());
        BuildingVideoListVO dto = new BuildingVideoListVO();
        dto.setMonitorCodes(videoService.getSecurityCodeList());
        List<Map<String, Object>> allList = iFormInstanceService.getColaBuildVideoListCount(dto);
        List<BuildingTreeVo> allListVo = buildBuildingColaData(formGroup, allList);
        // tree 统计处理
        return allListVo.stream().filter(s -> "-1".equals(s.getParentId())).map(s -> {
            BuildingTreeVo t = new BuildingTreeVo();
            Bean.copyExistPropertis(s, t);
            Map<String, Object> childrenTotal = this.getColaChildrenTotal(t.getInstanceId(), allListVo);
            t.setChildren((List<BuildingTreeVo>) childrenTotal.get("list"));
            t.setTotal((Long) childrenTotal.get("total"));
            t.setDetailPaneApi(address);
            return t;
        }).collect(Collectors.toList());
    }

    private List<BuildingTreeVo> buildBuildingColaData(FormGroup formGroup, List<Map<String, Object>> allList) {
        List<BuildingTreeVo> allListVo = Bean.listMap2ListBean(allList, BuildingTreeVo.class);
        BuildingTreeVo treeNode = new BuildingTreeVo();
        treeNode.setDetailPaneApi(address);
        treeNode.setInstanceId(formGroup.getId());
        treeNode.setInstanceName(formGroup.getGroupName());
        treeNode.setParentId("-1");
        treeNode.setGroupType(formGroup.getGroupType());
        treeNode.setGroupCode(formGroup.getGroupCode());
        allListVo.add(treeNode);
        return allListVo;
    }

    /**
     * 安防消防建筑树子集统计求和
     *
     * @param parentId  父级id
     * @param allListVo 所属有数据
     * @return
     */
    private Map<String, Object> getColaChildrenTotal(Long parentId, List<BuildingTreeVo> allListVo) {
        if (parentId == null || (allListVo == null && allListVo.size() == 0)) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        List<BuildingTreeVo> children = new ArrayList<>();
        BigDecimal total = BigDecimal.ZERO;
        List<BuildingTreeVo> childrenFilter = new ArrayList<>();
        for (BuildingTreeVo buildingTreeVo : allListVo) {
            if (buildingTreeVo.getParentId().equals(String.valueOf(parentId))) {
                childrenFilter.add(buildingTreeVo);
            }
        }
        if (childrenFilter.size() > 0) {
            total = BigDecimal.ZERO;
            for (BuildingTreeVo s : childrenFilter) {
                Map<String, Object> childrenTotal = this.getChildrenTotal(s.getInstanceId(), allListVo);
                List<BuildingTreeVo> childrens = (List<BuildingTreeVo>) childrenTotal.get("list");
                s.setChildren(childrens);
                if (childrens.size() > 0) {
                    s.setTotal(new BigDecimal(s.getTotal().toString()).add(new BigDecimal(childrenTotal.get("total").toString())).longValue());
                }
                children.add(s);
                total = total.add(new BigDecimal(s.getTotal().toString()));
            }
        }
        map.put("list", children);
        map.put("total", total.longValue());
        return map;
    }

    @Override
    public Page<BuildingVideoVO> buildingColaVideoList(Page page, BuildingVideoListVO dto) {
        return videoService.pageColaBuildingVideo(page, dto);
    }

    @Override
    public List<BuildingListVO> getFireEquipment(Long id) {
        QueryWrapper<EquipmentSpecificRelation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("equipment_specific_id", id);
        queryWrapper.eq("type", IndustryEnum.EQUIP.getCode());
        List<EquipmentSpecificRelation> lists = equipmentSpecificRelationMapper.selectList(queryWrapper);
        List<BuildingListVO> result = new ArrayList<>();
        if (0 < lists.size()) {
            lists.forEach(x -> {
                BuildingListVO buildingListVO = new BuildingListVO();
                buildingListVO = videoMapper.getSecurityOrFireEquipment(x.getRelationEquipmentSpecificId());
                result.add(buildingListVO);
            });
        }
        return result;
    }

    @Override
    public List<BuildingListVO> getSecurityEquipment(Long id) {
        QueryWrapper<EquipmentSpecificRelation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("equipment_specific_id", id);
        queryWrapper.eq("type", IndustryEnum.SECURITY.getCode());
        List<EquipmentSpecificRelation> lists = equipmentSpecificRelationMapper.selectList(queryWrapper);
        List<BuildingListVO> result = new ArrayList<>();
        if (0 < lists.size()) {
            lists.forEach(x -> {
                BuildingListVO buildingListVO = new BuildingListVO();
                buildingListVO = videoMapper.getSecurityOrFireEquipment(x.getRelationEquipmentSpecificId());
                result.add(buildingListVO);
            });
        }
        return result;
    }

    @Override
    public List<BuildingTreeAndEquipVO> gettreeAndEquip() {
        return this.baseMapper.getBuildingtreeAndEquip();
    }

    @Override
    public Map<String, Object> getBuildDetaliByFloorId(String instanceId) {
        List<DictionarieValueModel> build_type = Systemctl.dictionarieClient.dictValues(buildType).getResult();
        Map<String, String> buildType = build_type.stream().collect(Collectors.toMap(DictionarieValueModel::getDictDataKey, DictionarieValueModel::getDictDataValue));

        List<DictionarieValueModel> build_use_type = Systemctl.dictionarieClient.dictValues(buildUseType).getResult();
        Map<String, String> buildUseType = build_use_type.stream().collect(Collectors.toMap(DictionarieValueModel::getDictDataKey, DictionarieValueModel::getDictDataValue));

        List<DictionarieValueModel> building_structure_type = Systemctl.dictionarieClient.dictValues(buildingStructureType).getResult();
        Map<String, String> buildingStructureType = building_structure_type.stream().collect(Collectors.toMap(DictionarieValueModel::getDictDataKey, DictionarieValueModel::getDictDataValue));

        List<FireFightingSystemEntity> system = fireFightingSystemService.list();
        Map<Long, String> systems = system.stream().collect(Collectors.toMap(FireFightingSystemEntity::getId, FireFightingSystemEntity::getName));

        Map<String, String> idAndType = formInstanceMapper.getIdAndType(instanceId);
        String id = idAndType.get("id");
        String type = idAndType.get("type");
        String addr = idAndType.get("address");
        Map<String, Object> map = iFormInstanceService.queryForMap(Long.valueOf(id));

        String userId = String.valueOf(map.get("dutyUser"));
        String dutyUser = "";
        if (userId != null && !"".equals(userId)) {
            dutyUser = remoteSecurityService.getUserById(userId).getRealName();
        }

        Map<String, Object> res = new LinkedHashMap<>();
        List<AlarmDataVO> list = new ArrayList<>();
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
        try {
            if ("building".equals(type)) {
                list.add(new AlarmDataVO("建构筑名称", String.valueOf(map.get("name")), true));
                list.add(new AlarmDataVO("责任人", dutyUser, false));
                list.add(new AlarmDataVO("责任人电话", String.valueOf(map.get("dutyUserPhone")), false));
                list.add(new AlarmDataVO("建（构）筑类别", buildType.get(map.get("buildType")), false));
                list.add(new AlarmDataVO("使用性质", buildUseType.get(map.get("buildUseType")), false));
                list.add(new AlarmDataVO("结构类型", buildingStructureType.get(map.get("structureType")), false));
            }
            if ("pool".equals(type)) {
                list.add(new AlarmDataVO("消防水池名称", String.valueOf(map.get("name")), true));
                list.add(new AlarmDataVO("责任人", dutyUser, false));
                list.add(new AlarmDataVO("维保单位", String.valueOf(map.get("maintenanceUnit")), false));
                list.add(new AlarmDataVO("储水量（m³）", String.valueOf(map.get("waterStorage")), false));
                list.add(new AlarmDataVO("容量（m³）", String.valueOf(map.get("volume")), false));
                list.add(new AlarmDataVO("建造日期", sd.format(sd.parse(String.valueOf(map.get("buildDate")))), false));
            }
            if ("fireFoamRoom".equals(type)) {
                list.add(new AlarmDataVO("消防泡沫间名称", String.valueOf(map.get("name")), true));
                list.add(new AlarmDataVO("责任人", dutyUser, false));
                list.add(new AlarmDataVO("面积（㎡）", String.valueOf(map.get("area")), false));
                list.add(new AlarmDataVO("维保单位", String.valueOf(map.get("maintenanceUnit")), false));
                list.add(new AlarmDataVO("保护对象", String.valueOf(map.get("protectedObjects")), false));
                list.add(new AlarmDataVO("泡沫灭火剂名称", String.valueOf(map.get("foamExtinguishingAgentName")), false));
            }
            if ("rainRoom".equals(type)) {
                list.add(new AlarmDataVO("雨淋阀间名称", String.valueOf(map.get("name")), true));
                list.add(new AlarmDataVO("面积（㎡）", String.valueOf(map.get("area")), false));
                list.add(new AlarmDataVO("所属系统", systems.get(Long.valueOf(String.valueOf(map.get("system")))), false));
                list.add(new AlarmDataVO("责任人", dutyUser, false));
            }
            if ("fireRoom".equals(type)) {
                list.add(new AlarmDataVO("消防小室名称", String.valueOf(map.get("name")), true));
                list.add(new AlarmDataVO("责任人", dutyUser, false));
                list.add(new AlarmDataVO("建造日期", sd.format(sd.parse(String.valueOf(map.get("buildDate")))), false));
                list.add(new AlarmDataVO("面积（㎡）", String.valueOf(map.get("area")), false));
                list.add(new AlarmDataVO("所属系统", systems.get(Long.valueOf(String.valueOf(map.get("system")))), false));
            }
            if ("fireControlRoom".equals(type)) {
                list.add(new AlarmDataVO("消控室名称", String.valueOf(map.get("name")), true));
                list.add(new AlarmDataVO("投用日期", sd.format(sd.parse(String.valueOf(map.get("useDate")))), false));
                list.add(new AlarmDataVO("责任人", dutyUser, false));
                list.add(new AlarmDataVO("维保单位", String.valueOf(map.get("maintenanceUnit")), false));
                list.add(new AlarmDataVO("每班人数", String.valueOf(map.get("personNum")), false));
                list.add(new AlarmDataVO("消防控制室操作人员持证数", String.valueOf(map.get("certificatesPersonNum")), false));
            }
        } catch (Exception e) {
            throw new BadRequest(e.toString());
        }
        list.add(new AlarmDataVO("详细地址", addr, false));
        res.put("items", list);
        res.put("title", "建筑简介");
        //TODO 组态使用接口，组态特殊接口形式修改-20210826
        Map<String, Object> state = new HashMap<>();
        Map<String, Object> detail = new HashMap<>();
        state.put("instanceId", id);
        state.put("groupCode", type);
        state.put("groupType", "building");
        state.put("parentId", "0");
        state.put("parentType", "building");
        detail.putAll(state);
        state.put("detail", detail);
        res.put("state", state);
        return res;
    }

    @Override
    public Map<Long, String> getBuildingAbsolutePosition() {
        FormGroup formGroup = iFormGroupService.getByUniqueKey(GroupCodeEnum.ALL_BUILDING.getGroupCode());
        List<Map<String, Object>> allList = iFormInstanceService.getSpecialChildrenList(null);
        List<BuildingTreeVo> allListVo = buildBuildingData(formGroup, allList);
        return getBuildingAbsolutePosition(allListVo);
    }

    @Override
    public Map<String, Long> getBuildingCodeKey() {
        Map<String, Long> resMap = new HashMap<>();
        List<Map<String, Object>> allList = iFormInstanceService.getSpecialChildrenList(null);
        if (!allList.isEmpty()) {
            allList.forEach(map -> resMap.put(String.valueOf(map.get("code")), Long.valueOf(String.valueOf(map.get("id")))));
        }
        return resMap;
    }

    private Map<Long, String> getBuildingAbsolutePosition(List<BuildingTreeVo> all) {
        Map<Long, String> res = new HashMap<>();
        if (!all.isEmpty()) {
            Map<Object, BuildingTreeVo> map = Bean.listToMap(all, "id", BuildingTreeVo.class);
            for (BuildingTreeVo build : all) {
                if (build == null || build.getId() == null) {
                    continue;
                }
                StringBuilder builder = new StringBuilder();
                Stack<String> stack = new Stack<String>();
                stitchName(map, stack, build);
                while (true) {
                    builder.append(stack.pop());
                    if (stack.isEmpty()) {
                        break;
                    } else {
                        builder.append("·");
                    }
                }
                res.put(build.getId(), builder.toString());
            }
        }
        return res;
    }

    private void stitchName(Map<Object, BuildingTreeVo> map, Stack<String> stack, BuildingTreeVo building) {
        stack.push(building.getName());
        if (building.getParentId() == null || !map.containsKey(Long.valueOf(building.getParentId()))) {
            return;
        }
        stitchName(map, stack, map.get(Long.valueOf(building.getParentId())));
    }

    @Override
    public Map<String, String> getStorageTankCodeByBelongUnitId(String belongUnitId,String groupCode) {
        Map<String,String> map = new HashMap<>();
        map.put("field_name", StroageTankEnum.SSDW.getCode());
        map.put("field_value", belongUnitId);
        List<Map<String, Object>> list = iFormInstanceService.queryForMapList(groupCode,map);
        if(list.size() > 0) {
            map.clear();
            map.put("storageTankCode",stroageTankCode(belongUnitId,list.size()+1));
        } else {
            map.clear();
            map.put("storageTankCode",belongUnitId+"0001");
        }
        return map;
    }

    // 生成四位流水号
   private String stroageTankCode(String belongUnitId, int num) {
        if(num < 10) {
            return belongUnitId + "000" + num;
        }

       if(num < 100 && num > 9) {
           return belongUnitId + "00" + num;
       }

       if(num < 1000 && num > 99) {
           return belongUnitId + "0" + num;
       }

       if(num < 10000 && num > 999) {
           return belongUnitId  + num;
       }
       throw new BadRequest("无流水号可生成");
   }

    // 需求958 导出模板需要列表获取建筑 by kongfm 2021-09-15
    @Override
    public List<LinkedHashMap<String, Object>> getAllBuilding() {
        return formInstanceMapper.getAllBuilding();
    }

	@Override
	public Map<String, String> getBuildingToLongitudeAndLatitude(String instanceId) {
		// TODO Auto-generated method stub
		return formInstanceMapper.getBuildingToLongitudeAndLatitude(instanceId);
	}
}
