package algorithmrepository.contouring;

import algorithmrepository.Algorithms;

/** Contouring callback used by BoundedContouring */
public class BoundaryCheckCallback implements ContourCallback {
        public ContourCallback innerCallback;
        public OptimisedBoundaryHandler boundary;

        public double lastX, lastY;
        
        /** coordinates of search line */
        public double searchLine[][] = null;
        /** number of intersections of current contour with search line */
        public int sliCount;
        
        /** give us as soon as the boundary is hit, don't test for enter/exit */
        public boolean abortOnBoundary = false; 
        
        public BoundaryCheckCallback(ContourCallback innerCallback, OptimisedBoundaryHandler boundary) {
            this.innerCallback = innerCallback;
            this.boundary = boundary;
            lastX = Double.NaN; lastY = Double.NaN;
        }

        public boolean contourEnd(double contourValue, int terminationReason) {
            lastX = Double.NaN; lastY = Double.NaN;
            if(innerCallback == null)
                return true;
            else
                return innerCallback.contourEnd(contourValue, terminationReason); 
        }

       public boolean contourPoint(double contourValue, double x, double y) {
            if(!Double.isNaN(lastX)){
                double hitCoord[] = new double[2];
                
                if( searchLine != null ){
                    //if in progress, count intersections with search line (see getLastClosedContour() ) 
                    if( Algorithms.intersectionTwoLineSegments2D(searchLine[0][0], searchLine[1][0],
                                            searchLine[0][1], searchLine[1][1],
                                            lastX, lastY, x, y, null) )
                        sliCount++;
                }
                 
                if( boundary.isCrossing(lastX, lastY, x, y, hitCoord) ){
                    boolean ret;
                        
                    //call the inner callback with the contact point
                    if(innerCallback != null)
                        ret = innerCallback.contourPoint(contourValue, hitCoord[0], hitCoord[1]);
                    
                    if( abortOnBoundary ) //if requested, just stop there and don't start a new contour
                        return false;
                        
                    //otherwise we pretend this contour has ended on 'the boundary'
                    contourEnd(contourValue, Contouring.RETURN_HIT_GRID_BOUNDARY);
                    
                    //and don't abort but carry on. contourPoint will be called again
                    //now for the same point, making it the first point of the new contour
                    
                }
                
            } 
            lastX = x; lastY = y;
            if(innerCallback == null)
                return true;
            else
                return innerCallback.contourPoint(contourValue, x, y);
        }


}
