package com.tofly.analyse.util.analysis;

import cn.hutool.core.collection.CollUtil;
import com.supermap.analyst.networkanalyst.FacilityAnalyst;
import com.tofly.analyse.entity.LayerFiledConfig;
import com.tofly.analyse.entity.analyse.NetEdge;
import com.tofly.analyse.entity.analyse.Network;
import com.tofly.analyse.mapper.AnalysisMapper;
import com.tofly.analyse.mapper.PipelineMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * 联通性分析
 *
 * @author zhoux
 */
@Component
public class ConnectionAnalysis {

    @Autowired
    private AnalysisMapper analysisMapper;

    @Autowired
    private PipelineMapper pipelineMapper;


    /// <summary>
    /// 连通性分析
    /// </summary>
    /// <param name="nodeId">分析起点</param>
    /// <returns name="barrierNodes">分析到的障碍点</returns>
    /// <returns name="tracedNode">追踪到的节点</returns>
    /// <returns>连通的边ID数组</returns>
    public Map<String, Object> connectionAnalysis(int[] nodes, FacilityAnalyst facilityAnalyst, LayerFiledConfig layfiledConfig) {

        Map<String, Object> res = new HashMap<String, Object>();

        List<Object> barrierNodes = new ArrayList<Object>();
        List<Object> tracedNode = new ArrayList<Object>();
        List<Network> arrConnectedEdgesList = new ArrayList<Network>();
        List<Object> barrierNodeIds = new ArrayList<Object>();


        //当前存在bug（不返回障碍点连接的边）
        int[] arrConnectedEdges = facilityAnalyst.findConnectedEdgesFromNodes(nodes);

        if (arrConnectedEdges.length > 0) {

            List<Integer> lstTracedNode = new ArrayList<Integer>();
            List<NetEdge> lstTracedEdge = new ArrayList<NetEdge>();

            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < arrConnectedEdges.length; i++) {
                sb.append(arrConnectedEdges[i] + ",");
            }
            String strEdgeIds = sb.toString().substring(0, sb.toString().length() - 1);

            String params = "(" + facilityAnalyst.getAnalystSetting().getEdgeIDField() +
                    " in (" + strEdgeIds + ")" + " )";
            List<Network> networkData = analysisMapper.getNetworkData(facilityAnalyst.getAnalystSetting().getNetworkDataset().getName(),facilityAnalyst.getAnalystSetting().getNetworkDataset().getName()+"_NODE", params);

            if(CollUtil.isNotEmpty(networkData)){
                arrConnectedEdgesList=networkData;
                for (Network d:networkData){
                    if(d.getSmEdgeId()!=null){
                        NetEdge netEdge = new NetEdge();
                        netEdge.setEdgeId(d.getSmEdgeId());
                        netEdge.setFNode(d.getSmFNode());
                        netEdge.setTNode(d.getSmTNode());
                        if(!lstTracedEdge.contains(netEdge)){
                            lstTracedEdge.add(netEdge);
                        }
                        if(!lstTracedNode.contains(netEdge.getFNode())){
                            lstTracedNode.add(netEdge.getFNode());
                            tracedNode.add(d.getFSid());
                        }
                        if(!lstTracedNode.contains(netEdge.getTNode())){
                            lstTracedNode.add(netEdge.getTNode());
                            tracedNode.add(d.getTSid());
                        }
                    }
                }
                if(!facilityAnalyst.getAnalystSetting().getNetworkDataset().getName().contains("PSPS")){
                    //移除立管边
                    for (Iterator<NetEdge> i = lstTracedEdge.iterator(); i.hasNext(); ) {
                        NetEdge o = i.next();
                        if (o.getFNode().equals(o.getTNode())) {
                            i.remove();
                        }
                    }

                    StringBuffer sb1 = new StringBuffer();
                    for (int k = 0; k < lstTracedNode.size(); k++) {
                        sb1.append(lstTracedNode.get(k) + ",");
                    }
                    String lstTracedNodeStr = sb1.toString().substring(0, sb1.toString().length() - 1);
                    String param=null;
                    if(layfiledConfig.getSubtypeValue().contains(",")){
                        String[] split = layfiledConfig.getSubtypeValue().split(",");
                        List<String> strings = Arrays.asList(split);
                        StringBuffer lsb=new StringBuffer();
                        for(int i=0;i<strings.size();i++){
                            if(i!= strings.size()-1){
                                lsb.append(layfiledConfig.getSubtype());
                                lsb.append("=");
                                lsb.append("'");
                                lsb.append(strings.get(i));
                                lsb.append("'");
                                lsb.append(" or ");
                            }else{
                                lsb.append(layfiledConfig.getSubtype());
                                lsb.append("=");
                                lsb.append("'");
                                lsb.append(strings.get(i));
                                lsb.append("'");
                            }
                        }
                        param=lsb.toString();
                    }else{
                        param=layfiledConfig.getSubtype()+"= '"+layfiledConfig.getSubtypeValue()+"'";
                    }
                    //查找障碍点
                    String strBarrierEdge = "(SmNodeID in (" + lstTracedNodeStr + ") and (" + param+"))";
                    List<Network> networkNodeData = analysisMapper.getNetworkNodeData(facilityAnalyst.getAnalystSetting().getNetworkDataset().getName() + "_NODE", strBarrierEdge);
                    for (Network d : networkNodeData) {
                        if(!barrierNodes.contains(d.getSId())){
                            barrierNodes.add(d.getSId());
                        }
                        if(!barrierNodes.contains(d.getSmNodeId())){
                            barrierNodeIds.add(d.getSmNodeId());
                        }
                    }
                }
            }
        }

        res.put("connectedEdgesList", arrConnectedEdgesList);
        res.put("tracedNode", tracedNode);
        res.put("barrierNodes", barrierNodes);
        res.put("barrierNodeIds", barrierNodeIds);
        return res;
    }

    public Map<String, Object> connectionAnalysis2(String edgeId,String tableName,LayerFiledConfig layfiledConfig,boolean useBarrier,List<String> barrEdge) {

        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> edges = new ArrayList<>();
        Map<Integer, Object>  barrierNodeConc= new HashMap<>();
        List<String> edgeSids = new ArrayList<String>();
        List<Object> barrierNodeIds = new ArrayList<Object>();
        List<Object> barrierNodes = new ArrayList<Object>();
        List<Object> nodes = new ArrayList<>();
        List<Map<String, Object>> returnList = new ArrayList<>();

        if (layfiledConfig != null) {
            String sp = CamelToUtil.underlineToCamel(layfiledConfig.getSPoint());
            String ep = CamelToUtil.underlineToCamel(layfiledConfig.getEPoint());
            String no = CamelToUtil.underlineToCamel(layfiledConfig.getNo());

            Map<String, String> queryMap = new HashMap<String, String>();
            queryMap.put("pipePointNo", edgeId);
            queryMap.put("tableName", tableName);
            queryMap.put("no", layfiledConfig.getNo());
            queryMap.put("sPoint", layfiledConfig.getSPoint());
            queryMap.put("ePoint", layfiledConfig.getEPoint());
            List<Map<String, Object>> gisInfo = pipelineMapper.getPipeInfos(queryMap);
            if (gisInfo.size() != 0) {
                returnList.addAll(gisInfo);
                Map<String, Object> pipeInfo = gisInfo.get(0);
                String sPoint = pipeInfo.get(sp).toString();
                String ePonit = pipeInfo.get(ep).toString();
                String sid = pipeInfo.get(no).toString();
                List<Map<String, Object>> nextMaps=new ArrayList<>();
                Map<String, Object> newValueMap = new HashMap<String, Object>();
                newValueMap.put("nextPoint", sPoint);
                newValueMap.put("sid", sid);
                nextMaps.add(newValueMap);
                Map<String, Object> newValueMap2 = new HashMap<String, Object>();
                newValueMap2.put("nextPoint", ePonit);
                newValueMap2.put("sid", sid);
                nextMaps.add(newValueMap2);
                checkConnect(tableName, nextMaps, returnList, layfiledConfig,useBarrier,barrEdge);
            }
            if (CollUtil.isNotEmpty(returnList)) {
                edges = returnList.stream().distinct().collect(Collectors.toList());
                List<String> points = new ArrayList<>();
                edges.forEach(d -> {
                    edgeSids.add(d.get(no).toString());
                    Object sPoint = d.get(sp);
                    Object ePoint = d.get(ep);
                    if (sPoint != null) {
                        String s = sPoint.toString();
                        if (!points.contains(s)) {
                            points.add(s);
                        }
                    }
                    if (ePoint != null) {
                        String s = ePoint.toString();
                        if (!points.contains(s)) {
                            points.add(s);
                        }
                    }
                });
                if (CollUtil.isNotEmpty(points)) {
                    Map<String, Object> nodeMap = new HashMap<String, Object>();
                    nodeMap.put("points", points);
                    String strLayerCode = layfiledConfig.getNodeLayerName().substring(layfiledConfig.getNodeLayerName().indexOf("_") + 1, layfiledConfig.getNodeLayerName().indexOf("_") + 5);
                    String strPNetworkName = "NETWORK_" + strLayerCode + "_2D_NODE";
                    nodeMap.put("tableName", strPNetworkName);
                    nodeMap.put("no", layfiledConfig.getNodeNo());
                    nodeMap.put("code", layfiledConfig.getCode());
                    nodeMap.put("model", layfiledConfig.getSubtype());
                    List<Map<String, Object>> pointByExpNos = pipelineMapper.getPointsByExpNos(nodeMap);
                    if (CollUtil.isNotEmpty(pointByExpNos)) {
                        String model = CamelToUtil.underlineToCamel(layfiledConfig.getSubtype());
                        String nodeNo = CamelToUtil.underlineToCamel(layfiledConfig.getNo());
                        pointByExpNos.forEach(d->{
                            Object sid = d.get(nodeNo);
                            Object smNodeId = d.get("smnodeid");
                            if(null!=d.get(model) && layfiledConfig.getSubtypeValue().contains(d.get(model).toString())){
                                barrierNodes.add(sid);
                                barrierNodeIds.add(smNodeId);
                                barrierNodeConc.put(Integer.valueOf(smNodeId.toString()),sid);
                            }
                            nodes.add(sid);
                        });
                    }
                }
            }
        }
        map.put("barrierNodeConc", barrierNodeConc);
        map.put("edgeSids", edgeSids);
        map.put("connectedEdgesList", edges);
        map.put("tracedNode", nodes);
        map.put("barrierNodes", barrierNodes);
        map.put("barrierNodeIds", barrierNodeIds);
        return map;
    }


    public void checkConnect(String tableName, List<Map<String, Object>> nextMapList, List<Map<String, Object>> list, LayerFiledConfig layfiledConfig,Boolean useBarrier,List<String> barrEdge) {
        List<String> sids = nextMapList.stream().map(d -> d.get("sid").toString()).collect(Collectors.toList());
        List<String> nextPoints = nextMapList.stream().map(d -> d.get("nextPoint").toString()).collect(Collectors.toList());
        List<Map<String, Object>> nextMap = new ArrayList<>();

        String sp = CamelToUtil.underlineToCamel(layfiledConfig.getSPoint());
        String ep = CamelToUtil.underlineToCamel(layfiledConfig.getEPoint());
        String no = CamelToUtil.underlineToCamel(layfiledConfig.getNo());
        String model = CamelToUtil.underlineToCamel(layfiledConfig.getSubtype());


        Map<String, Object> startMap = new HashMap<String, Object>();
        startMap.put("tableName", tableName);
        startMap.put("nextPoints", nextPoints);
        startMap.put("no", layfiledConfig.getNo());
        startMap.put("sPoint", layfiledConfig.getSPoint());
        startMap.put("ePoint", layfiledConfig.getEPoint());
        startMap.put("model", layfiledConfig.getSubtype());
        startMap.put("tableNameNode", layfiledConfig.getNodeLayerName());
        if(CollUtil.isNotEmpty(barrEdge)){
            startMap.put("barrEdge",barrEdge);
        }
        //查找管线对应start和end节点
        List<Map<String, Object>> result = pipelineMapper.getPipeInfos(startMap);

        //删除查到的重复管线
        Iterator<Map<String, Object>> nextEndIterator = result.iterator();
        while (nextEndIterator.hasNext()) {
            Map<String, Object> ob = nextEndIterator.next();
            if(sids.contains(ob.get(no).toString())){
                nextEndIterator.remove();
            }
        }

        if(!result.isEmpty()){
            for (int i = 0; i < result.size(); i++) {
                String sid = result.get(i).get(no).toString();
                String startSid = null;
                if(nextPoints.contains(result.get(i).get(sp))){
                    startSid = result.get(i).get(ep).toString();
                }else{
                    startSid = result.get(i).get(sp).toString();
                }
                if(!list.contains(result.get(i))){
                    Map<String, Object> newValueMap = new HashMap<String, Object>();
                    if (result.get(i).get(model) != null) {
                        newValueMap.put("model",  result.get(i).get(model));
                    }
                    newValueMap.put("sid", sid);
                    newValueMap.put("nextPoint", startSid);
                    nextMap.add(newValueMap);
                    list.add(result.get(i));
                }
            }
        }

        if(CollUtil.isNotEmpty(nextMap)){
            List<Map<String, Object>> nextMapListNew = new ArrayList<>();
            nextMap.forEach(d->{
                if(useBarrier){
                    Object existModel = d.get("model");
                    if (existModel != null) {
                        if (layfiledConfig.getSubtypeValue().contains(existModel.toString())) {
                            return;
                        } else {
                            nextMapListNew.add(d);
                        }
                    }else{
                        nextMapListNew.add(d);
                    }
                }else{
                    nextMapListNew.add(d);
                }
            });
            if(CollUtil.isNotEmpty(nextMapListNew)){
                checkConnect(tableName, nextMapListNew, list, layfiledConfig,useBarrier,barrEdge);
            }
        }

    }
}