package cz.fidentis.analyst.visitors.mesh;
import java.util.List;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import cz.fidentis.analyst.mesh.core.CornerTableRow;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshFacetImpl;
import cz.fidentis.analyst.mesh.core.MeshModel;
import cz.fidentis.analyst.mesh.core.MeshPointImpl;
import cz.fidentis.analyst.symmetry.Plane;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
 * @author Dominik Racek
 */
public class CrossSectionTest {

    private MeshModel createModel() {
        MeshModel model = new MeshModel();

        MeshFacet facet = new MeshFacetImpl();
        facet.addVertex(new MeshPointImpl(new Point3d(0, 0, 0), null, null));
        facet.addVertex(new MeshPointImpl(new Point3d(1, 0, 0), null, null));
        facet.addVertex(new MeshPointImpl(new Point3d(1, 1, 0), null, null));
        facet.addVertex(new MeshPointImpl(new Point3d(0, 1, 0), null, null));
        facet.addVertex(new MeshPointImpl(new Point3d(1, 2, 0), null, null));
        facet.addVertex(new MeshPointImpl(new Point3d(0, 2, 0), null, null));
        facet.addVertex(new MeshPointImpl(new Point3d(1, 3, 0), null, null));

        facet.getCornerTable().addRow(new CornerTableRow(0, -1));
        facet.getCornerTable().addRow(new CornerTableRow(1, 5));
        facet.getCornerTable().addRow(new CornerTableRow(2, -1));
        facet.getCornerTable().addRow(new CornerTableRow(0, 8));
        facet.getCornerTable().addRow(new CornerTableRow(2, -1));
        facet.getCornerTable().addRow(new CornerTableRow(3, 1));
        facet.getCornerTable().addRow(new CornerTableRow(3, -1));
        facet.getCornerTable().addRow(new CornerTableRow(2, 11));
        facet.getCornerTable().addRow(new CornerTableRow(4, 3));
        facet.getCornerTable().addRow(new CornerTableRow(3, 13));
        facet.getCornerTable().addRow(new CornerTableRow(4, -1));
        facet.getCornerTable().addRow(new CornerTableRow(5, 7));
        facet.getCornerTable().addRow(new CornerTableRow(4, -1));
        facet.getCornerTable().addRow(new CornerTableRow(6, 9));
        facet.getCornerTable().addRow(new CornerTableRow(5, -1));

        model.addFacet(facet);
        return model;
    }

    /**
     * Unit test for CrossSectionZigZag visitor
     */
    @Test
    public void CrossSectionZigZag() {
        Plane cuttingPlane = new Plane(new Vector3d(1, 0, 0), -0.5);
        MeshModel model = createModel();

        CrossSectionZigZag cs = new CrossSectionZigZag(cuttingPlane);
        model.compute(cs);
        List<Point3d> points = cs.getPoints();

        //They can be ordered two ways, check both
        Assertions.assertEquals(points.size(), 6);
        if (points.get(0).equals(new Point3d(0.5, 0, 0))) {
            Assertions.assertEquals(points.get(0), new Point3d(0.5, 0, 0));
            Assertions.assertEquals(points.get(1), new Point3d(0.5, 0.5, 0));
            Assertions.assertEquals(points.get(2), new Point3d(0.5, 1, 0));
            Assertions.assertEquals(points.get(3), new Point3d(0.5, 1.5, 0));
            Assertions.assertEquals(points.get(4), new Point3d(0.5, 2, 0));
            Assertions.assertEquals(points.get(5), new Point3d(0.5, 2.5, 0));
        } else if (points.get(0).equals(new Point3d(0.5, 2.5, 0))) {
            Assertions.assertEquals(points.get(0), new Point3d(0.5, 2.5, 0));
            Assertions.assertEquals(points.get(1), new Point3d(0.5, 2, 0));
            Assertions.assertEquals(points.get(2), new Point3d(0.5, 1.5, 0));
            Assertions.assertEquals(points.get(3), new Point3d(0.5, 1, 0));
            Assertions.assertEquals(points.get(4), new Point3d(0.5, 0.5, 0));
            Assertions.assertEquals(points.get(5), new Point3d(0.5, 0, 0));
        } else {
            Assertions.fail();
        }
    }

    /**
     * Unit test for CrossSection visitor
     */
    @Test
    public void CrossSection() {
        Plane cuttingPlane = new Plane(new Vector3d(1, 0, 0), -0.5);
        MeshModel model = createModel();

        CrossSection cs = new CrossSection(cuttingPlane);
        model.compute(cs);
        List<Point3d> points = cs.getPoints();

        //They can be ordered two ways, check both
        //Flaw of the non-zigzag design: it can't detect first and last intersection,
        //since it only controls edges between two triangles.
        Assertions.assertEquals(points.size(), 4);
        if (points.get(0).equals(new Point3d(0.5, 0.5, 0))) {
            Assertions.assertEquals(points.get(0), new Point3d(0.5, 0.5, 0));
            Assertions.assertEquals(points.get(1), new Point3d(0.5, 1, 0));
            Assertions.assertEquals(points.get(2), new Point3d(0.5, 1.5, 0));
            Assertions.assertEquals(points.get(3), new Point3d(0.5, 2, 0));
        } else if (points.get(0).equals(new Point3d(0.5, 2, 0))) {
            Assertions.assertEquals(points.get(1), new Point3d(0.5, 2, 0));
            Assertions.assertEquals(points.get(2), new Point3d(0.5, 1.5, 0));
            Assertions.assertEquals(points.get(3), new Point3d(0.5, 1, 0));
            Assertions.assertEquals(points.get(4), new Point3d(0.5, 0.5, 0));
        } else {
            Assertions.fail();
        }
    }

}
