package cz.fidentis.analyst.tests;

import cz.fidentis.analyst.face.HumanFace;
import cz.fidentis.analyst.kdtree.KdTree;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.symmetry.SymmetryConfig;
import cz.fidentis.analyst.symmetry.Plane;
import cz.fidentis.analyst.symmetry.SymmetryEstimator;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * A class for testing the efficiency of algorithms.
 * 
 * @author Radek Oslejsek
 */
public class EfficiencyTests {
    
    private static File girlFile = new File("src/test/resources/cz/fidentis/analyst/average_girl_17-20.obj");
    private static File boyFile = new File("src/test/resources/cz/fidentis/analyst/average_boy_17-20.obj");
    private static File faceFile2 = new File("src/test/resources/cz/fidentis/analyst/00002_01_ECA.obj");
    private static File faceFile4 = new File("/home/oslejsek/GIT/HCI/analyst2/GUI/src/test/resources/cz/fidentis/analyst/00004_01_ECA.obj");
    private static File basicFaceFile = new File("src/test/resources/cz/fidentis/analyst/basic-model-04.obj");
    
    private static HumanFace face1;
    private static HumanFace face2;
    
    /**
     * Main method 
     * @param args Input arguments 
     * @throws IOException on IO error
     */
    public static void main(String[] args) throws IOException, ClassNotFoundException, Exception {
        face1 = printFaceLoad(faceFile4);
        face2 = printFaceLoad(faceFile2);
        
        face1.getMeshModel().simplifyModel();
        face2.getMeshModel().simplifyModel();
        
        //for (int i = 0; i < 10; i++) {
        //    printFaceDump(face1);
        //}
        
        boolean relativeDist = false;
        boolean printDetails = false;
        
        
        //face1.getMeshModel().compute(new GaussianCurvature()); // initialize everything, then measure
        
        System.out.println("Symmetry plane calculation:");
        //printSymmetryPlane(face1, true, CurvatureAlg.MEAN);
        //printSymmetryPlane(face1, true, CurvatureAlg.GAUSSIAN);
        //printSymmetryPlane(face1, false, CurvatureAlg.MEAN);
        //printSymmetryPlane(face1, false, CurvatureAlg.GAUSSIAN);
        
        System.out.println();
        System.out.println(measureKdTreeCreation(face1) + "\tmsec:\tKd-tree creation of first face");
        System.out.println(measureKdTreeCreation(face2) + "\tmsec:\tKd-tree creation of second face");
        
        System.out.println();
        System.out.println("Hausdorff distance sequentially:");
        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT, relativeDist, false), printDetails);
        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT_DISTANCE_ONLY, false, false), printDetails);
        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT, relativeDist, false), printDetails);
        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_TRIANGLE_APPROXIMATE, relativeDist, false), printDetails);

        System.out.println();
        System.out.println("Hausdorff distance concurrently:");
        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT_DISTANCE_ONLY, false, true), printDetails);
        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT, relativeDist, true), printDetails);
        testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_TRIANGLE_APPROXIMATE, relativeDist, true), printDetails);
    }
    
    protected static void testAndPrint(HumanFace face, HausdorffDistance vis, boolean printDetails) {
        long startTime = System.currentTimeMillis();
        face.getMeshModel().compute(vis);
        long endTime = System.currentTimeMillis();
        
        System.out.println(
                (endTime-startTime) + 
                "\tmsec: " + 
                //"\t" + (vis.inParallel() ? "concurrently" : "sequentially") +
                "\t" + (vis.relativeDistance()? "relative" : "absolute") +
                "\t" + vis.getStrategy()
        );
        
        if (printDetails) {
            Map<MeshFacet, List<Double>> results = vis.getDistances();
            for (MeshFacet facet: results.keySet()) {
                System.out.println(results.get(facet));
            }
        }
    }
    
    private static long measureKdTreeCreation(HumanFace face) {
        long startTime = System.currentTimeMillis();
        KdTree kdTree = new KdTree(face.getMeshModel().getFacets());
        return System.currentTimeMillis() - startTime;
    }
    
    private static void printSymmetryPlane(HumanFace face, boolean concurrently) {
        long startTime = System.currentTimeMillis();
        SymmetryEstimator est = new SymmetryEstimator(new SymmetryConfig());
        face.getMeshModel().compute(est, false);
        Plane plane = est.getSymmetryPlane(concurrently);
        long endTime =  System.currentTimeMillis();
        
        System.out.println(
                (endTime-startTime) + 
                "\tmsec: " + 
                "\t" + (concurrently ? "concurrently" : "sequentially") +
//                "\t" + curvatureAlg + " curvature    " +
                "\t" + plane.getNormal() + ", " + plane.getDistance()
        );
    }

    private static void printFaceDump(HumanFace face) throws IOException, ClassNotFoundException, Exception {
        long startTime = System.currentTimeMillis();
        File file = face.dumpToFile();
        long endTime =  System.currentTimeMillis();
        System.out.println("Human face dumping:\t " +(endTime-startTime) + " msec");
        
        startTime = System.currentTimeMillis();
        HumanFace f = HumanFace.restoreFromFile(file);
        endTime =  System.currentTimeMillis();
        System.out.println("Human face restore:\t " +(endTime-startTime) + " msec");
    }
    
    private static HumanFace printFaceLoad(File file) throws IOException {
        long startTime = System.currentTimeMillis();
        HumanFace face = new HumanFace(file);
        long endTime =  System.currentTimeMillis();
        System.out.println("Human face loading:\t " +(endTime-startTime) + " msec");
        return face;
    }
    
}
