package cz.fidentis.analyst.procrustes;

import cz.fidentis.analyst.face.HumanFace;
import cz.fidentis.analyst.face.HumanFaceFactory;
import cz.fidentis.analyst.feature.FeaturePoint;
import cz.fidentis.analyst.feature.services.FeaturePointImportService;
import cz.fidentis.analyst.feature.utils.FileResourcesUtils;
import cz.fidentis.analyst.mesh.core.MeshPoint;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import javax.vecmath.Point3d;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.zip.DataFormatException;

public class ProcrustesAnalysisTest {
    private static final Path TEST_FILE_DIRECTORY = Paths.get(
            "src", "test", "resources", "cz", "fidentis", "analyst", "comparison", "procrustesAnalysis");

    private static final String FP_HEAD_01 = "0002_01_landmarks.csv";
    private static final String FP_HEAD_02 = "0002_02_landmarks.csv";
    private static final String HEAD_01 = "0002_01_ECA.obj";
    private static final String HEAD_02 = "0002_02_ECA.obj";


    @Test
    void procrustesAnalysisSuperImposeTest() throws URISyntaxException, DataFormatException, IOException {

        FileResourcesUtils fru = new FileResourcesUtils();
        HumanFaceFactory factory = new HumanFaceFactory();
        FeaturePointImportService featurePointImportService = new FeaturePointImportService();

        List<FeaturePoint> fpList01 = featurePointImportService.importFeaturePoints(
                TEST_FILE_DIRECTORY.toString(), FP_HEAD_01);
        List<FeaturePoint> fpList02 = featurePointImportService.importFeaturePoints(
                TEST_FILE_DIRECTORY.toString(), FP_HEAD_02);
        HumanFace face1 = factory.getFace(factory.loadFace(
                fru.getFile(TEST_FILE_DIRECTORY.toString(), HEAD_01)));
        HumanFace face2 = factory.getFace(factory.loadFace(
                fru.getFile(TEST_FILE_DIRECTORY.toString(), HEAD_02)));

        face1.setFeaturePoints(fpList01);
        face2.setFeaturePoints(fpList02);

        ProcrustesAnalysis pa = new ProcrustesAnalysis(face1, face2);
        pa.superImpose();
        Point3d expectedCentroid1 = new Point3d(-0.7689281702041626, 14.009615898132324, -59.499977111816406);
        Point3d expectedCentroid2 = new Point3d(-0.040306758135557175, 16.00124168395996, -59.67900848388672);

        Assertions.assertEquals(expectedCentroid1.x, pa.modelCentroid1.x);
        Assertions.assertEquals(expectedCentroid1.y, pa.modelCentroid1.y);
        Assertions.assertEquals(expectedCentroid1.z, pa.modelCentroid1.z);
        Assertions.assertEquals(expectedCentroid2.x, pa.modelCentroid2.x);
        Assertions.assertEquals(expectedCentroid2.y, pa.modelCentroid2.y);
        Assertions.assertEquals(expectedCentroid2.z, pa.modelCentroid2.z);

    }

    @Test
    void calculateScalingValueTest() throws DataFormatException, IOException {
        FileResourcesUtils fru = new FileResourcesUtils();
        HumanFaceFactory factory = new HumanFaceFactory();
        FeaturePointImportService featurePointImportService = new FeaturePointImportService();

        List<FeaturePoint> fpList01 = featurePointImportService.importFeaturePoints(
                TEST_FILE_DIRECTORY.toString(), FP_HEAD_01);
        List<FeaturePoint> fpList02 = featurePointImportService.importFeaturePoints(
                TEST_FILE_DIRECTORY.toString(), FP_HEAD_02);
        HumanFace face1 = factory.getFace(factory.loadFace(
                fru.getFile(TEST_FILE_DIRECTORY.toString(), HEAD_01)));
        HumanFace face2 = factory.getFace(factory.loadFace(
                fru.getFile(TEST_FILE_DIRECTORY.toString(), HEAD_02)));

        face1.setFeaturePoints(fpList01);
        face2.setFeaturePoints(fpList02);

        ProcrustesAnalysis pa = new ProcrustesAnalysis(face1, face2, true);
        double scaleFactor = pa.calculateScalingValue(fpList01, fpList02);
        Assertions.assertEquals(0.9918273923138605, scaleFactor);
    }

    @Test
    void procrustesAnalysisAnalyseTest() throws DataFormatException, IOException {
        FileResourcesUtils fru = new FileResourcesUtils();
        HumanFaceFactory factory = new HumanFaceFactory();
        FeaturePointImportService featurePointImportService = new FeaturePointImportService();

        List<FeaturePoint> fpList01 = featurePointImportService.importFeaturePoints(
                TEST_FILE_DIRECTORY.toString(), FP_HEAD_01);
        List<FeaturePoint> fpList02 = featurePointImportService.importFeaturePoints(
                TEST_FILE_DIRECTORY.toString(), FP_HEAD_02);
        HumanFace face1 = factory.getFace(factory.loadFace(
                fru.getFile(TEST_FILE_DIRECTORY.toString(), HEAD_01)));
        HumanFace face2 = factory.getFace(factory.loadFace(
                fru.getFile(TEST_FILE_DIRECTORY.toString(), HEAD_02)));

        face1.setFeaturePoints(fpList01);
        face2.setFeaturePoints(fpList02);

        ProcrustesAnalysis pa = new ProcrustesAnalysis(face1, face2);

        pa.analyze();

        MeshPoint v0 = face2.getMeshModel().getFacets().get(0).getVertices().get(0);
        MeshPoint v5 = face2.getMeshModel().getFacets().get(0).getVertices().get(5);
        Point3d expectedV0 = new Point3d(3.5674604453564664, -5.024528152075607, 112.59416675280146);
        Point3d expectedV5 = new Point3d(4.08419737898887, -3.5408847908259893, 111.87431099579298);
        /*
        Assertions.assertEquals(expectedV0.x, v0.getX());
        Assertions.assertEquals(expectedV0.y, v0.getY());
        Assertions.assertEquals(expectedV0.z, v0.getZ());
        Assertions.assertEquals(expectedV5.x, v5.getX());
        Assertions.assertEquals(expectedV5.y, v5.getY());
        Assertions.assertEquals(expectedV5.z, v5.getZ());
        */
        
        FeaturePoint fp0 = face2.getFeaturePoints().get(0);
        Point3d expectedFp0 = new Point3d(-42.71984496683351, 27.159522893612994, 27.40995332843569);
        FeaturePoint fp5 = face2.getFeaturePoints().get(5);
        Point3d expectedFp5 = new Point3d(35.88895800465637, 30.10663264467767, 34.788164810540685);
        Assertions.assertEquals(expectedFp0.x, fp0.getX());
        Assertions.assertEquals(expectedFp0.y, fp0.getY());
        Assertions.assertEquals(expectedFp0.z, fp0.getZ());
        Assertions.assertEquals(expectedFp5.x, fp5.getX());
        Assertions.assertEquals(expectedFp5.y, fp5.getY());
        Assertions.assertEquals(expectedFp5.z, fp5.getZ());
    }
}

