package com.tofly.analyse.util.analysis;

import com.supermap.analyst.networkanalyst.*;
import com.supermap.data.*;
import com.tofly.analyse.entity.analyse.NetEdge;
import com.tofly.analyse.entity.analyse.NetNode;
import org.springframework.stereotype.Component;

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



/**
 * 追踪分析
 * @author zhoux
 *
 */
@Component
public class FormTraceAnalyst {
	
	
	    
    /**
     * 
     * @param _layerAnalysting  进行分析的图层
     * @param _ftrOrgEdge  排水追踪分析起始管线
     * @param _flowQuery  1、上游分析、 2下游分析
     */
    public HashMap<String,Object> formTraceAnalyst(FacilityAnalyst facilityAnalyst ,DatasetVector __vecPNetwork ,int __iEdgeId,Integer _flowQuery) throws Exception{
    	    	   	  
    	HashMap<String,Object> formTraceAnalystMap = new HashMap<String,Object>();
    	List<Geometry>  __lstWaterOutletPoint =  null;
    	
        try{        	

            List<NetEdge> __arrTracedEdges = null;
            List<NetNode> __arrTracedNodes = null;
            FacilityAnalystResult __resultTraceFlow = null;

            //无流向或流向不确定（按数据中存储的流向进行分析）
            if (__resultTraceFlow == null){
                if (_flowQuery==1){                	
                	HashMap<String,Object> resMap = TraceUpFlow2(facilityAnalyst,__iEdgeId);
                	
                	__arrTracedEdges = (List<NetEdge>)resMap.get("tracedEdges");
                	__arrTracedNodes = (List<NetNode>)resMap.get("tracedNodes");
                	
                	formTraceAnalystMap.put("tracedEdges", __arrTracedEdges);
                	formTraceAnalystMap.put("tracedNodes", __arrTracedNodes);
                
                }else{
                	HashMap<String,Object> resMap = TraceDownFlow2(facilityAnalyst,__iEdgeId);                	
                	__arrTracedEdges = (List<NetEdge>)resMap.get("tracedEdges");
                	__arrTracedNodes = (List<NetNode>)resMap.get("tracedNodes");
                	
                	formTraceAnalystMap.put("tracedEdges", __arrTracedEdges);
                	formTraceAnalystMap.put("tracedNodes", __arrTracedNodes);
                }
            }

            if ((__resultTraceFlow != null && __resultTraceFlow.getEdges().length > 0) || __arrTracedEdges != null){
            	__lstWaterOutletPoint = new ArrayList<Geometry>();
                List<Integer> __lstResultArcIDs = new ArrayList<Integer>();
                
                HashMap<String,String> __dtWaterOutlet_Header  = new HashMap<String,String>();
                HashMap<String,String> __dtWaterOutlet_Data  = new HashMap<String,String>();
                

                if (__resultTraceFlow != null){
                	__lstResultArcIDs  = Arrays.stream(__resultTraceFlow.getEdges()).boxed().collect(Collectors.toList());
                }
                
                if (__arrTracedEdges != null){                	
                	__lstResultArcIDs = __arrTracedEdges.stream().map(NetEdge::getEdgeId).collect(Collectors.toList());
                }
                
                String __strSQL = facilityAnalyst.getAnalystSetting().getNodeIDField() + 
                		" in ("+String.join(",",__arrTracedNodes.stream().map( s -> String.valueOf(s.getNodeId())).collect(Collectors.toList()))+" ) "
                				+ " and POINT_TYPE='出水口'";                                                
                
                Recordset __recWaterOutlet = __vecPNetwork.getChildDataset().query(__strSQL, CursorType.DYNAMIC);
                
                if (__recWaterOutlet.getRecordCount() > 0){
                	
                    FieldInfos __fldsNode = __vecPNetwork.getChildDataset().getFieldInfos();
                    
                    for(int i=0;i<__fldsNode.getCount();i++) {
                    	 if (__fldsNode.get(i).getName().toLowerCase().startsWith("sm"))
                         {
                             continue;
                         }
                    	 __dtWaterOutlet_Header.put(__fldsNode.get(i).getName(), __fldsNode.get(i).getCaption());
                    }
                    __recWaterOutlet.moveFirst();                    
                    while (__recWaterOutlet.isEOF() == false){
                    	
                        __lstWaterOutletPoint.add(__recWaterOutlet.getGeometry());
                        
                        for (Map.Entry<String, String> entry : __dtWaterOutlet_Header.entrySet()) {  
                        	__dtWaterOutlet_Data.put(entry.getKey(), __recWaterOutlet.getString(entry.getKey()));
                        }
                        __recWaterOutlet.moveNext();
                    }
                    formTraceAnalystMap.put("waterOutletPoint", __lstWaterOutletPoint);
                }
            }else{            	
            	throw new Exception("选择的管网节点处无流向，无法进行追踪分析。");
            }
        }catch (Exception ex){
        	throw new Exception("分析失败："+ex.getMessage());
        }
        
        return formTraceAnalystMap;
    }   
    
    
   
    
    
    /// <summary>
    /// 上游追踪路径分析（通过流向标识）
    /// </summary>
    /// <param name="edgeId">分析起始边Id</param>
    /// <param name="tracedEdges">追踪到的边对象集合</param>
    /// <param name="tracedNodes">追踪到的节点对象集合</param>
    /// <returns></returns>
    public HashMap<String,Object> TraceUpFlow2(FacilityAnalyst facilityAnalyst,int edgeId) throws Exception{
    	    	
    	HashMap<String,Object> resMap =new HashMap<String,Object>();
    	

        List<NetEdge> __lstTracedEdge = new ArrayList<NetEdge>();
        List<NetNode> __lstTracedNode = new ArrayList<NetNode>();        
        List<String> __lstUpFlowNodeIds = new ArrayList<String>();//上游节点

        Recordset __recEdge = facilityAnalyst.getAnalystSetting().getNetworkDataset().query(new int[] { edgeId }, CursorType.DYNAMIC);
        if (__recEdge.getRecordCount() == 0){
            throw new Exception("未在管线二维网络数据集中找到指定管线");
        }
        __recEdge.moveFirst();
                
        NetEdge netEdge=  new NetEdge();    
        netEdge.setEdgeId(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getEdgeIDField()));
        netEdge.setFNode(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getFNodeIDField()));
        netEdge.setTNode(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
        
        __lstTracedEdge.add(netEdge);
                   
        String __strFlowDir = __recEdge.getString("FLOWDIR");
        //同向
        if (__strFlowDir.equals("1")){
            __lstUpFlowNodeIds.add(__recEdge.getString("s_point"));
            NetNode netNode=  new NetNode(); 
            netNode.setNodeId(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
            __lstTracedNode.add(netNode);
        //反向    
        }else if (__strFlowDir.equals("2")){
            __lstUpFlowNodeIds.add(__recEdge.getString("e_point"));            
            NetNode netNode= new NetNode();
            netNode.setNodeId(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
            __lstTracedNode.add(netNode);
        }
        
        __recEdge.close();
        __recEdge.dispose();
        
        //循环进行上游分析
        while (__lstUpFlowNodeIds.size() > 0){
        	
        	String FlowNodeIds=String.join("','", __lstUpFlowNodeIds); 	
        	String querySql = "s_point in ( '"+FlowNodeIds+"' ) or e_point in ('"+FlowNodeIds+"')";        	        	
        	Recordset __recUpFlowEdge = facilityAnalyst.getAnalystSetting().
        			getNetworkDataset().query(querySql, CursorType.DYNAMIC);

            __lstUpFlowNodeIds.clear();
            if (__recUpFlowEdge.getRecordCount() > 0){
            	
                __recUpFlowEdge.moveFirst();
                while (__recUpFlowEdge.isEOF() == false){
                	
                    int __iUpFlowEdge = __recUpFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getEdgeIDField());
                      
                    //确保不是已追踪边
                    if (!__lstTracedEdge.stream().anyMatch(edge ->  edge.getEdgeId() == __iUpFlowEdge)){
                        
                    	String __strFlowDir2 = __recUpFlowEdge.getString("FLOWDIR");
                    	//同向
                        if (__strFlowDir2.equals("1")){
                        	
                            int __iUpFlowNode = __recUpFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getFNodeIDField());
                            
                            //上游节点未被追踪
                            if (!__lstTracedNode.stream().anyMatch(node ->  node.getNodeId() == __iUpFlowNode)){
                            	 	
                            	NetEdge traceNetEdge = new NetEdge();
                            	traceNetEdge.setEdgeId(__recUpFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getEdgeIDField()));
                            	traceNetEdge.setFNode(__recUpFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getFNodeIDField()));
                            	traceNetEdge.setTNode(__recUpFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
                            	__lstTracedEdge.add(traceNetEdge);
              
                            	NetNode netNode = new NetNode();
                            	netNode.setNodeId(__iUpFlowNode);
                            	__lstTracedNode.add(netNode);
                            	__lstUpFlowNodeIds.add(__recUpFlowEdge.getString("s_point"));
                            	
                            }
                        }
                        //反向
                        else if (__strFlowDir2.equals("2")){
                        	
                            int __iUpFlowNode = __recUpFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField());
                            //上游节点未被追踪
                            if (!__lstTracedNode.stream().anyMatch(node ->  node.getNodeId() == __iUpFlowNode)){
                            	
                            	NetEdge traceNetEdge= new NetEdge();
                            	
                            	traceNetEdge.setEdgeId(__recUpFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getEdgeIDField()));
                            	traceNetEdge.setFNode(__recUpFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getFNodeIDField()));
                            	traceNetEdge.setTNode(__recUpFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
                            	__lstTracedEdge.add(traceNetEdge);
                            	
                            	NetNode netNode = new NetNode();
                            	netNode.setNodeId(__iUpFlowNode);
                            	__lstTracedNode.add(netNode);                               
                                __lstUpFlowNodeIds.add(__recUpFlowEdge.getString("e_point"));
                            }
                        }
                    }

                    __recUpFlowEdge.moveNext();
                }
            }
            __recUpFlowEdge.close();
            __recUpFlowEdge.dispose();
        }
        
        resMap.put("tracedEdges", __lstTracedEdge);
        resMap.put("tracedNodes", __lstTracedNode);
        
        __lstTracedEdge.clear();
        __lstTracedNode.clear();
        
        return resMap;
    }
    
    
    /// <summary>
    /// 下游追踪路径分析（通过流向标识）
    /// </summary>
    /// <param name="edgeId">分析起始边Id</param>
    /// <param name="tracedEdges">追踪到的边对象集合</param>
    /// <param name="tracedNodes">追踪到的节点对象集合</param>
    /// <returns></returns>
    public HashMap<String,Object> TraceDownFlow2(FacilityAnalyst facilityAnalyst,int edgeId) throws Exception{

    	
    	HashMap<String,Object> resMap =new HashMap<String,Object>();

        List<NetEdge> __lstTracedEdge = new ArrayList<NetEdge>();
        List<NetNode> __lstTracedNode = new ArrayList<NetNode>();
        List<String> __lstDownFlowNodeIds = new ArrayList<String>();//下游节点

        Recordset __recEdge = facilityAnalyst.getAnalystSetting().getNetworkDataset().query(new int[] { edgeId }, CursorType.DYNAMIC);
        
        if (__recEdge.getRecordCount() == 0){
            throw new Exception("未在管线二维网络数据集中找到指定管线");
        }
        __recEdge.moveFirst();
        
        NetEdge netEdge=  new NetEdge();    
        netEdge.setEdgeId(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getEdgeIDField()));
        netEdge.setFNode(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getFNodeIDField()));
        netEdge.setTNode(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
        
        __lstTracedEdge.add(netEdge);
        
        String __strFlowDir = __recEdge.getString("FLOWDIR");
        //同向
        if (__strFlowDir.equals("1")){
            __lstDownFlowNodeIds.add(__recEdge.getString("e_point"));
            
            NetNode netNode=  new NetNode(); 
            netNode.setNodeId(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
            __lstTracedNode.add(netNode);
            
        }
        //反向
        else if (__strFlowDir.equals("2")){
        	
            __lstDownFlowNodeIds.add(__recEdge.getString("s_point"));
            NetNode netNode= new NetNode();
            netNode.setNodeId(__recEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
            __lstTracedNode.add(netNode);
        }
        
        
        __recEdge.close();
        __recEdge.dispose();

        
        //循环进行下游分析
        while (__lstDownFlowNodeIds.size() > 0){
        	
        	
        	String DownFlowNodeIds=String.join("','", __lstDownFlowNodeIds); 	
        	String querySql = "s_point in ( '"+DownFlowNodeIds+"' ) or e_point in ( '"+DownFlowNodeIds+"' )";        	        	
        	Recordset __recDownFlowEdge = facilityAnalyst.getAnalystSetting().
        			getNetworkDataset().query(querySql, CursorType.DYNAMIC);
        	System.out.println(__recDownFlowEdge.getRecordCount());

            __lstDownFlowNodeIds.clear();
            if (__recDownFlowEdge.getRecordCount() > 0){
            	
                __recDownFlowEdge.moveFirst();
                while (__recDownFlowEdge.isEOF() == false){


                    int __iDownFlowEdge = __recDownFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getEdgeIDField());
                    //确保不是已追踪边

                    if (!__lstTracedEdge.stream().anyMatch(edge ->  edge.getEdgeId() == __iDownFlowEdge)){
                    	
                        String __strFlowDir2 = __recDownFlowEdge.getString("FLOWDIR");
                        
                        //同向
                        if (__strFlowDir2.equals("1")){
                        	
                            int __iDownFlowNode = __recDownFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField());
                            
                            
                            //下游节点未被追踪
                            if (!__lstTracedNode.stream().anyMatch(node ->  node.getNodeId() == __iDownFlowNode)){
                            	
                            	
                            	NetEdge netTraceEdge = new NetEdge();
                            	netTraceEdge.setEdgeId(__recDownFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getEdgeIDField()));
                            	netTraceEdge.setFNode(__recDownFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getFNodeIDField()));
                            	netTraceEdge.setTNode(__recDownFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
                            	__lstTracedEdge.add(netTraceEdge);
                            	
                            	NetNode netTraceNode = new NetNode();
                            	netTraceNode.setNodeId(__iDownFlowNode);
                            	__lstTracedNode.add(netTraceNode);
                                __lstDownFlowNodeIds.add(__recDownFlowEdge.getString("e_point"));
                            }
                        }
                        //反向
                        else if (__strFlowDir2.equals("2")){
                        	
                            int __iDownFlowNode = __recDownFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getFNodeIDField());
                            
                            //下游节点未被追踪
                            
                            if (!__lstTracedNode.stream().anyMatch(node ->  node.getNodeId() == __iDownFlowNode)){
                            	NetEdge netTraceEdge = new NetEdge();
                            	netTraceEdge.setEdgeId(__recDownFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getEdgeIDField()));
                            	netTraceEdge.setFNode(__recDownFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getFNodeIDField()));
                            	netTraceEdge.setTNode(__recDownFlowEdge.getInt32(facilityAnalyst.getAnalystSetting().getTNodeIDField()));
                            	__lstTracedEdge.add(netTraceEdge);
                            	
                            	NetNode netTraceNode = new NetNode();
                            	netTraceNode.setNodeId(__iDownFlowNode);
                            	__lstTracedNode.add(netTraceNode);
                                __lstDownFlowNodeIds.add(__recDownFlowEdge.getString("s_point"));
                            }
                        }
                    }

                    __recDownFlowEdge.moveNext();
                }
            }
            
            __recDownFlowEdge.close();
            __recDownFlowEdge.dispose();
        }

        resMap.put("tracedEdges", __lstTracedEdge);
        resMap.put("tracedNodes", __lstTracedNode);

        
        return resMap;
    }
    
    /// <summary>
    /// 加载设施网络分析模型
    /// </summary>
    /// <param name="networkPipe">进行分析的管线网络数据集</param>
    /// <param name="useBarrier">是否启用障碍</param>
    public FacilityAnalyst LoadModel2(DatasetVector networkPipe, boolean useBarrier){
    	FacilityAnalyst facilityAnalyst = new FacilityAnalyst();
    	try{    
    		
    		FacilityAnalystSetting facilityAnalystSetting = new FacilityAnalystSetting();
    		facilityAnalystSetting.setNetworkDataset((DatasetVector) networkPipe);
    		// facilityAnalystSetting.setDirectionField("Flow_D".toLowerCase());
    		facilityAnalystSetting.setEdgeIDField("SmEdgeID"); //SMEDGEID
    		facilityAnalystSetting.setNodeIDField("SmNodeID");
    		facilityAnalystSetting.setFNodeIDField("SmFNode"); 		//SMFNODE		ssfnode
    		facilityAnalystSetting.setTNodeIDField("SmTNode");		 //SMTNODE		sstnode
    		facilityAnalystSetting.setTolerance(0.001);
            if(networkPipe.getName().contains("PSPS")){
                facilityAnalystSetting.setDirectionField("FLOWDIR");
            }else{
                facilityAnalystSetting.setDirectionField("Direction");
            }
    		WeightFieldInfo weightFieldInfo = new WeightFieldInfo();
    		weightFieldInfo.setName("Length");
    		weightFieldInfo.setFTWeightField("SmLength");
    		weightFieldInfo.setTFWeightField("SmLength");
    		WeightFieldInfos weightFieldInfos = new WeightFieldInfos();
    		weightFieldInfos.add(weightFieldInfo);
    		facilityAnalystSetting.setWeightFieldInfos(weightFieldInfos);
    	
    		
    		
    		if (useBarrier && networkPipe.getName().contains("_PSPS_") == false){
	            List<Integer> __lstBrrierNode = new ArrayList<Integer>();
	            DatasetVector __vecPNetworkNode = (DatasetVector) networkPipe;
	            Recordset __recNodeBarrier = __vecPNetworkNode.getChildDataset().query("ADJUNCT='阀门' or SUBTYPE='阀门'",  CursorType.DYNAMIC);
	            
	            __recNodeBarrier.moveFirst();
	            while (__recNodeBarrier.isEOF() == false){
	            	if(__recNodeBarrier.getID()>0) {
	            		__lstBrrierNode.add(__recNodeBarrier.getID());
	            	}
	                __recNodeBarrier.moveNext();
	            }
	            System.out.println(__lstBrrierNode.stream().mapToInt(Integer::intValue).toArray().length+"###");
	            facilityAnalystSetting.setBarrierNodes(__lstBrrierNode.stream().mapToInt(Integer::intValue).toArray());
	            __recNodeBarrier.close();
	            __recNodeBarrier.dispose();
    		}
        	facilityAnalyst.setAnalystSetting(facilityAnalystSetting);
            
            
    		Boolean blLoadResult = facilityAnalyst.load();
    		System.out.println(blLoadResult);
            
        }catch (Exception ex){
            ex.printStackTrace();
        }
    	return facilityAnalyst;
    }
    
}