package algorithmrepository.contouring;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;
import oneLinersForAlgoTests.algoAsciiMatrixFile;
import oneLinersForAlgoTests.algoBinaryMatrixFile;
import svg.SVGLineWriter;
import junit.framework.TestCase;

public class ContouringTests extends TestCase {
    
    int nx, ny;
    double x[], y[], f[][];
    double minf, maxf;
    double bbox[]; 
    Random randGen = new Random();
    
    /** Generates A. Meakins's test function */
    public void makeTestFunction(boolean random){
        if(random){
            nx = 50; //random field has LOTS of contours, so make a bit smaller
            ny = 50;
        }else{
            nx = 400;
            ny = 200;
        }
        
        x = new double[nx];
        y = new double[ny];
        f = new double[ny][nx];
        
        for(int i=0; i<ny; i++)
            y[i] = 10 * Math.PI +  (double)i / (ny - 1) * 2 * Math.PI;
        
        for(int j=0; j<nx; j++)
            x[j] = (double)j / (nx - 1) * 3.5 * Math.PI;
        
        //minf = Double.MAX_VALUE; maxf= Double.MIN_VALUE;
        for(int i=0; i<ny; i++)
            for(int j=0; j<nx; j++){
                if(random){
                            f[i][j] = randGen.nextGaussian(); 
                }else{
                    f[i][j] = Math.sin(y[i]) + Math.sin(x[j]);
                    //if(f[i][j] < minf) minf = f[i][j];
                    //if(f[i][j] > maxf) maxf = f[i][j];
                }
            }
        
        minf = -2; maxf = 2;
        
        bbox = new double[]{ x[0], y[0], x[x.length-1], y[y.length-1] };
        
        
    }
    /* for old scilab version
    public void testContouringGridHelpers(){
        
          double cf[][] = new double[][]{
            Contouring.getInterpolationCoefficients(0.5, 1.0/3.0), //~mid of top
            Contouring.getInterpolationCoefficients(1.0/3.0, 0.5), //~mid of left
            Contouring.getInterpolationCoefficients(2.0/3.0, 0.5), //~mid of right
            Contouring.getInterpolationCoefficients(0.5, 2.0/3.0), //~mid of bottom
            Contouring.getInterpolationCoefficients(0, 0),  //corner cases
            Contouring.getInterpolationCoefficients(1, 0),
            Contouring.getInterpolationCoefficients(0, 1),
            Contouring.getInterpolationCoefficients(1, 1),
            Contouring.getInterpolationCoefficients(0.5, 0.5),
        };
        
        double goodAnswers[][] = new double[][]{ 
            { 2.0/6.0, 2.0/6.0, 1.0/6.0,  1.0/6.0 },
            { 2.0/6.0, 1.0/6.0, 2.0/6.0,  1.0/6.0 },
            { 1.0/6.0, 2.0/6.0, 1.0/6.0,  2.0/6.0 },
            { 1.0/6.0, 1.0/6.0, 2.0/6.0,  2.0/6.0 },
            
            { 1, 0, 0, 0 },
            { 0, 1, 0, 0 },
            { 0, 0, 1, 0 },
            { 0, 0, 0, 1 },
            
            { 0.25, 0.25, 0.25, 0.25 },
        };
        
        double tolerance = 1e-5;
        for(int i=0;i<cf.length;i++){
            for(int j=0; j<4;j++)
                assertTrue("test "+i+", f_"+j, (cf[i][j] - goodAnswers[i][j]) < tolerance );
                
            //    System.out.print(cf[i][j]+", ");
            //System.out.println();            
        }
        
        //old scilab things
        //assertEquals(Contouring.whichTriangle(0.6, 0.1), 0); //top
        //assertEquals(Contouring.whichTriangle(0.2, 0.6), 1); //left
        //assertEquals(Contouring.whichTriangle(0.6, 0.5), 2); //right
        //assertEquals(Contouring.whichTriangle(0.9, 0.95), 3); //bottom
        //System.out.println("whichTriangle(centre)="+Contouring.whichTriangle(0.5, 0.5));
    } */
    
    /** Test contouing algorithm and contour collector */
    public void testContourCollector(){
        try{
            int nc = 21;
            String outPath = System.getProperty("java.io.tmpdir");
                   
            ContourCollector contours = new ContourCollector();
            
            makeTestFunction(false);
            
            Contouring cntr = new Contouring(contours, x, y, f);
            
            double c[] = new double[nc];
            for(int i=0; i<nc; i++)
                c[i] = minf + (maxf - minf)*(double)i/(double)(nc - 1.0);
            
            cntr.getAllContours(c);
                
            double dataOut[][] = contours.getPackedArrays(Contouring.RETURN_CLOSED);
            //double dataOut[][] = contours.getAllPoints1DArrays();
            algoBinaryMatrixFile.mustWrite(outPath + "/contour1.bin", dataOut, true);
            
            contours.writeSVGAllContours(outPath + "/contour1.svg", 
                            new double[]{ x[0], y[0], x[x.length-1], y[y.length-1] }, true);
            
            if(true)return;
            
            //try to throw it by running contours from places they don't exist
            contours.clear();
            
            cntr.clearFlags();
            
            cntr.contourFromSquare(5, 5, 0);
            
            contours.writeSVGAllContours(outPath + "/contourFail.svg", 
                new double[]{ x[0], y[0], x[x.length-1], y[y.length-1] }, true);

        }catch(RuntimeException e){ 
            e.printStackTrace(); //Arrg, why doesn't the unit test show the error?
            throw e;
        }
    }
    
    public void testWithRandomField(){
        int nc = 21;
        String outPath = System.getProperty("java.io.tmpdir");
               
        ContourCollector contours = new ContourCollector();
        
        makeTestFunction(true);
        
        Contouring cntr = new Contouring(contours, x, y, f);
        
        double c[] = new double[nc];
        for(int i=0; i<nc; i++)
            c[i] = minf + (maxf - minf)*(double)i/(double)(nc - 1.0);
        
        cntr.getAllContours(c);
        
        contours.writeSVGAllContours(outPath + "/contour-rand.svg", 
                        new double[]{ x[0], y[0], x[x.length-1], y[y.length-1] }, true);

    }
    
    /** Test contouring within a boundary */ 
    public void testBoundedContouring(){
        try{
            String outPath = System.getProperty("java.io.tmpdir");
            
            int nc = 21;
            
            ContourCollector contours = new ContourCollector();
            
           // double bx[] = new double[]{ 2,  1,  4,  5,  5,  12, 12 }; 
           // double by[] = new double[]{ 32, 35, 38, 38, 56, 35, 31 };
            double bx[] = new double[]{ 2,  2,    7,    7  };
            double by[] = new double[]{ 33, 37.5, 37.5, 33 };
            
            makeTestFunction(false);
            
            BoundedContouring cntr = new BoundedContouring(contours,
                                                            x[0], x[nx - 1], nx,
                                                            y[0], y[ny - 1], ny,
                                                            f, bx, by);        
           double c[] = new double[nc];
            for(int i=0; i<nc; i++)
                c[i] = minf + (maxf - minf)*(double)i/(double)(nc - 1.0);
        
            cntr.getAllGridContours(c);
            //cntr.getAllGridContours(new double[]{ -1.1 });
            //cntr.getBoundaryContours(-1.1);

            System.out.println(contours);
            
            //double bracket[] = cntr.getLastClosedContour(false, 10);
            //cntr.getAllGridContours(bracket);
                
            //double dataOut[][] = contours.getPackedArraysAllContours();
            double dataOut[][] = contours.getPointsArraysAllContours();
            //double dataOut[][] = contours.getPointsArrays(Contouring.RETURN_CLOSED);
            algoBinaryMatrixFile.mustWrite(outPath + "/contour2.bin", dataOut, true);
            
            dataOut = contours.getContourEnds();
            algoBinaryMatrixFile.mustWrite(outPath + "/contour2-ends.bin", dataOut, true);
            
            contours.writeSVGAllContours(outPath + "/boundcontours.svg", bbox, true);
            
            SVGLineWriter boundSVG = new SVGLineWriter(outPath + "/bound.svg", bbox);
            boundSVG.addLine(bx, by);
            boundSVG.destroy();
            
            
        }catch(RuntimeException e){ 
            e.printStackTrace(); //Arrg, why doesn't the unit test show the error?
            throw e;
        }
    }
    
    public void donttestContouringFailedGrid() throws IOException{
        String inPath = System.getProperty("java.io.tmpdir") + "/contourFail";
        
        double tmp[][];            
        tmp = algoAsciiMatrixFile.mustLoad(inPath+"/f.txt", false);
        double flatf[] = tmp[0];
        tmp = algoAsciiMatrixFile.mustLoad(inPath+"/x.txt", false);
        x = tmp[0];
        tmp = algoAsciiMatrixFile.mustLoad(inPath+"/y.txt", false);
        y = tmp[0];
        tmp = algoAsciiMatrixFile.mustLoad(inPath+"/done.txt", false);
        double done[] = tmp[0];
        
        
        double cval = Double.NaN; //get from /tmp/contourFail/cval.txt 
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(inPath+"/info.txt")));
        while(true){
            String line = reader.readLine();
            if (line == null)
                throw new RuntimeException("no CVAL= in info.txt"); 
            
            if (line.matches("^CVAL=.*")){
                cval = Double.parseDouble(line.replaceAll("^CVAL=", ""));
                break;
            }

        }               
        
        String outPath = System.getProperty("java.io.tmpdir");
        ContourCollector contours = new ContourCollector();
        
        Contouring cntr = new Contouring(contours, x, y, flatf);
        
        cntr.getAllContours(new double[]{ cval });
            
        double dataOut[][] = contours.getPackedArrays(Contouring.RETURN_CLOSED);
        //double dataOut[][] = contours.getAllPoints1DArrays();
        algoBinaryMatrixFile.mustWrite(outPath + "/contour1.bin", dataOut, true);
        
        contours.writeSVGAllContours(outPath + "/contour1.svg", 
                        new double[]{ x[0], y[0], x[x.length-1], y[y.length-1] }, true);
        
    }
    

}
