package com.tofly.analyse.util.analysis;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.supermap.analyst.networkanalyst.FacilityAnalyst;
import com.supermap.analyst.networkanalyst.FacilityAnalystResult;
import com.supermap.data.CursorType;
import com.supermap.data.DatasetVector;
import com.supermap.data.Recordset;
import com.tofly.analyse.entity.LayerFiledConfig;
import com.tofly.analyse.entity.analyse.BurstResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;


/**
 * 爆管分析
 *
 * @author zhoux
 */
@Component
public class BurstPipeAnalysis {

    @Autowired
    public ConnectionAnalysis connectionAnalysis;

    @Autowired
    private AnalystConfig facilityAnalystConfig;


    public BurstResult BurstPipeAnalysis(String sid, FacilityAnalyst facilityAnalystParam, LayerFiledConfig layfiledConfig, List<Integer> sourceIds,String sids) {
        BurstResult brResult = new BurstResult();
        List<String> affectedEdge = new ArrayList<>();
        List<Object> affectedNode = new ArrayList<>();
        List<Object> mustCloseNode = new ArrayList<>();
        Map<String, Object> stringObjectMap = connectionAnalysis(facilityAnalystParam.getAnalystSetting().getNetworkDataset().getName(), layfiledConfig, sid, true, null);
        if (CollUtil.isNotEmpty(stringObjectMap)) {
            List<Integer> barrierNodeIds = (List<Integer>) stringObjectMap.get("barrierNodeIds");
            List<String> edgeSids = (List<String>) stringObjectMap.get("edgeSids");
            List<Object> tracedNode = (List<Object>) stringObjectMap.get("tracedNode");
            List<Object> barrierNodes = (List<Object>) stringObjectMap.get("barrierNodes");
            Map<Integer, Object> barrierNodeConc = (Map<Integer, Object>) stringObjectMap.get("barrierNodeConc");

            affectedEdge = edgeSids;
            affectedNode = tracedNode;
            List<Integer> needAnalyNodeIds = new ArrayList<>();
            if(StringUtils.isNotBlank(sids)){
                //分析每个障碍点是否连通源点，如果都不连通源，说明形成了一个闭合区域，那么其连通性分析的管线管点就是它的影响范围
                getMustNode(facilityAnalystParam, sourceIds, mustCloseNode, barrierNodeIds, needAnalyNodeIds, barrierNodeConc,sids);
                if (CollUtil.isEmpty(mustCloseNode) ) {
                    List<Integer> analyNodeIds = new ArrayList<>();
                    mustCloseNode=barrierNodes;
                    for (Integer d : needAnalyNodeIds) {
                        Object o = barrierNodeConc.get(d);
                        if(o!=null){
                            if(sids.contains(o.toString())){
                                analyNodeIds.add(d);
                            }
                        }
                    }
                    needAnalyNodeIds=analyNodeIds;
                }
                if(CollUtil.isNotEmpty(needAnalyNodeIds)) {
                    getAnalystData(facilityAnalystParam, layfiledConfig, affectedEdge, affectedNode, edgeSids, needAnalyNodeIds);
                }
            }else{
                //分析每个障碍点是否连通源点，如果都不连通源，说明形成了一个闭合区域，那么其连通性分析的管线管点就是它的影响范围
                getMustNode(facilityAnalystParam, sourceIds, mustCloseNode, barrierNodeIds, needAnalyNodeIds, barrierNodeConc,null);
                //如果闭关阀不为空，则说明不是闭合管段，要对连接阀、支流阀进行扩展分析，有明确流向做下游分析，不确定流向查找障找出连通阀不存在于连通范围内的边进行无障碍范围分析
                if (CollUtil.isNotEmpty(mustCloseNode) && CollUtil.isNotEmpty(needAnalyNodeIds)) {
                    getAnalystData(facilityAnalystParam, layfiledConfig, affectedEdge, affectedNode, edgeSids, needAnalyNodeIds);
                }else{
                    mustCloseNode=barrierNodes;
                }
            }
        }
        brResult.setAffectedEdge(affectedEdge);
        brResult.setAffectedNode(affectedNode);
        brResult.setMustCloseNode(mustCloseNode);
        return brResult;
    }

    private void getAnalystData(FacilityAnalyst facilityAnalystParam, LayerFiledConfig layfiledConfig, List<String> affectedEdge, List<Object> affectedNode,
                                List<String> edgeSids, List<Integer> needAnalyNodeIds) {
        //找出需要补充的阀门不存在于连通范围内的边
        DatasetVector networkDataset = facilityAnalystParam.getAnalystSetting().getNetworkDataset();
        List<Map<String, String>> edgeList = new ArrayList<>();
        for (Integer d : needAnalyNodeIds) {
            List<Map<String,String>> sidList = new ArrayList<>();
            Recordset recValveNode = networkDataset.query("SmFNode=" + d + " or SmTNode=" + d, CursorType.STATIC);
            recValveNode.moveFirst();
            while (recValveNode.isEOF() == false) {
                Map<String,String> map=new HashMap<>();
                String sid1 = recValveNode.getString(layfiledConfig.getNo());
                String direction = recValveNode.getInt32(layfiledConfig.getDir())+"";
                String smID = recValveNode.getInt32("SmID")+"";
                String startSid = recValveNode.getString(layfiledConfig.getSPoint());
                String endSid = recValveNode.getString(layfiledConfig.getEPoint());
                map.put(layfiledConfig.getNo(),sid1);
                map.put("smid",smID);
                map.put(layfiledConfig.getDir(),direction);
                map.put(layfiledConfig.getSPoint(),startSid);
                map.put(layfiledConfig.getEPoint(),endSid);
                sidList.add(map);
                recValveNode.moveNext();
            }
            recValveNode.close();
            recValveNode.dispose();
            //排除掉已存在连通性分析得边
            List<Map<String, String>> filterEdge = sidList.stream().filter(s -> !edgeSids.contains(s.get(layfiledConfig.getNo()))).collect(Collectors.toList());
            edgeList.addAll(filterEdge);
        }
        if (CollUtil.isNotEmpty(edgeList)) {
            List<Integer> downList=new ArrayList<>();
            for (Map<String,String> s : edgeList) {
                String sid1 = s.get(layfiledConfig.getNo());
                Integer smId = Integer.valueOf(s.get("smid"));
                String direction = s.get(layfiledConfig.getDir());
                String startSid = s.get(layfiledConfig.getSPoint());
                String endSid = s.get(layfiledConfig.getEPoint());
                //如果是不确定流向，则做扩展连通性分析，扩展到下一个阀门点结束 0:正向 1:反向 2:不确定流向 3:无流向
                if(direction.equals("2") || direction.equals("3")){
                    Map<String, Object> stringObjectMap1 = connectionAnalysis(facilityAnalystParam.getAnalystSetting().getNetworkDataset().getName(), layfiledConfig, sid1, true, edgeSids);
                    List<String> connectedEdgesList1 = (List<String>) stringObjectMap1.get("edgeSids");
                    List<Object> tracedNode1 = (List<Object>) stringObjectMap1.get("tracedNode");
                    affectedEdge.addAll(connectedEdgesList1);
                    affectedNode.addAll(tracedNode1);
                }else{
                    //确定流向则做下游分析
                    FacilityAnalystResult resultSourceFromEdge = facilityAnalystParam.traceDownFromEdge(smId, "Length", true);
                    if (resultSourceFromEdge != null && resultSourceFromEdge.getEdges().length>0) {
                        List<Integer> collect = Arrays.stream(resultSourceFromEdge.getEdges()).boxed().collect(Collectors.toList());
                        downList.addAll(collect);
                    }
                }
                affectedEdge.add(sid1);
                affectedNode.add(startSid);
                affectedNode.add(endSid);
            }
            if(CollUtil.isNotEmpty(downList)){
                List<Integer> collect = downList.stream().distinct().collect(Collectors.toList());
                StringBuffer sb = new StringBuffer();
                for (int i = 0; i < collect.size(); i++) {
                    sb.append(collect.get(i) + ",");
                }
                String strEdgeIds = sb.toString().substring(0, sb.toString().length() - 1);
                Recordset recValveNode = networkDataset.query("SMID in ("+strEdgeIds+")", CursorType.STATIC);
                recValveNode.moveFirst();
                while (recValveNode.isEOF() == false) {
                    String sid = recValveNode.getString(layfiledConfig.getNo());
                    String startSid = recValveNode.getString(layfiledConfig.getSPoint());
                    String endSid = recValveNode.getString(layfiledConfig.getEPoint());
                    affectedEdge.add(sid);
                    affectedNode.add(startSid);
                    affectedNode.add(endSid);
                    recValveNode.moveNext();
                }
                recValveNode.close();
                recValveNode.dispose();
            }
        }
    }


    private void getMustNode(FacilityAnalyst facilityAnalystParam, List<Integer> sourceIds, List<Object> mustCloseNode,
                             List<Integer> barrierNodeIds, List<Integer> needAnalyNodeIds, Map<Integer, Object> barrierNodeConc,String sids) {
        if (CollUtil.isNotEmpty(barrierNodeIds)) {
            barrierNodeIds.forEach(d -> {
                Object o = barrierNodeConc.get(d);
                AtomicReference<Boolean> flag = new AtomicReference<>(false);
                sourceIds.forEach(s -> {
                    // 根据给定弧段查找源
                    FacilityAnalystResult resultSourceFromNode = facilityAnalystParam
                            .findPathFromNodes(d, s, "Length", true);
                    if (resultSourceFromNode != null) {
                        if (o != null) {
                            if (!mustCloseNode.contains(o)) {
                                mustCloseNode.add(o);
                                if(StringUtils.isNotBlank(sids)) {
                                    if (sids.contains(o.toString())) {
                                        needAnalyNodeIds.add(d);
                                    }
                                }
                            }
                        }
                        flag.set(true);
                        return;
                    }
                });
                if (!flag.get()) {
                    if(!needAnalyNodeIds.contains(d)){
                        needAnalyNodeIds.add(d);
                    }
                }
            });

        }
    }


    private Map<String, Object> connectionAnalysis(String tablename, LayerFiledConfig layfiledConfig, String sid, Boolean useBarrier, List<String> barrEdge) {
        Map<String, Object> arrAftEdges = connectionAnalysis.connectionAnalysis2(sid, tablename, layfiledConfig, useBarrier, barrEdge);//进行有障碍连通性分析
        return arrAftEdges;
    }


}
