package com.rinkai.osm.service.routing;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.graphhopper.routing.util.FlagEncoder;
import com.graphhopper.storage.Graph;
import com.graphhopper.util.EdgeExplorer;
import com.graphhopper.util.EdgeIterator;

/**
 * 
 * call fixAllOneWayDeadEnds() once per encoder after the graph has been created.
 * 
 * It will disable any edges pointing to a node which is not reachable or which can not reach other nodes.
 * 
 * 
 *
 */
public class FixOneWayDeadEnds {
	
	static final Logger logger = LoggerFactory.getLogger(FixOneWayDeadEnds.class);
	   
	public static void fixAllOneWayDeadEnds(Graph graph,FlagEncoder flagEncoder,long flagEncoderDirectionMask){
		while(fixOneWayDeadEnds(graph, flagEncoder,flagEncoderDirectionMask)>0);
	}
	public static int fixOneWayDeadEnds(Graph graph,FlagEncoder flagEncoder,long flagEncoderDirectionMask){
		if (logger.isInfoEnabled())
			logger.info("fixOneWayDeadEnds()");
		
		// osmIdsExtendedStorage is just for debug
		//OsmIdsExtendedStorage osmIdsExtendedStorage=ChainedWeighting.getExtendedStorage((GraphStorage)graph, OsmIdsExtendedStorage.class);
		
		int oneWayDeadEnd=0;
		EdgeExplorer edgeExplorer=graph.createEdgeExplorer();
		int maxNodes=graph.getNodes();
		if (logger.isInfoEnabled())
			logger.info("maxNodes:"+maxNodes+"");

		
		// look for nodes
		for(int nodeIdx=0;nodeIdx<maxNodes;nodeIdx++){
			
			
			
			EdgeIterator edgeIterator=edgeExplorer.setBaseNode(nodeIdx);
			
			boolean atLeastOneWayOut=false;
			boolean atLeastOneWayIn=false;
			
			while(edgeIterator.next() && !(atLeastOneWayOut && atLeastOneWayIn) ){
				if (!atLeastOneWayOut && flagEncoder.isForward(edgeIterator.getFlags()))
					atLeastOneWayOut=true;
				if (!atLeastOneWayIn && flagEncoder.isBackward(edgeIterator.getFlags())){
					atLeastOneWayIn=true;
				}

			}
			
			if ((atLeastOneWayIn && !atLeastOneWayOut) || (!atLeastOneWayIn && atLeastOneWayOut) ){
				logger.warn("no way out or in from node "+ nodeIdx);
				edgeIterator=edgeExplorer.setBaseNode(nodeIdx);
				while(edgeIterator.next()){
					long oldFlags=edgeIterator.getFlags();
					long newFlags=oldFlags & (~flagEncoderDirectionMask);
					edgeIterator.setFlags(newFlags);

					int edgeIdx=edgeIterator.getEdge();
					logger.warn("disabled edgeIdx:"+ edgeIdx);//+"osmId:"+osmIdsExtendedStorage.getEdgeOsmId(edgeIdx));
					oneWayDeadEnd++;
				}
			}
			
		}
		if (logger.isInfoEnabled())
			logger.info("fixOneWayDeadEnds() found "+oneWayDeadEnd+" ways");
		return oneWayDeadEnd;
	}
}
