using System.Collections.Generic;
using TriangleNet.Geometry;
using TriangleNet.Meshing;
using UnityEngine;
using NetMesh = TriangleNet.Meshing.IMesh;
using NetPoly = TriangleNet.Geometry.Polygon;
using NetTriangle = TriangleNet.Geometry.ITriangle;

/*
 * This class is only used to provide a triangulate method
 * (Note that we must use TriangleNet.Geometry, in order to have access to it, 
 *  and thus cannot remove this class, as TriangleNet.Geometry cannot be used everywhere)
*/
public abstract class Triangulation {
    public static void triangulateForDisplay(GamePolygon polygon, float z, out List<int> outIndices, out List<Vector3> outVertices) {
        Set<Triangle> triangles = new Set<Triangle>();
		Set<GameVertex> vertices = new Set<GameVertex>();

        QualityOptions opt = new QualityOptions();
        //opt.MaximumArea = 4000000.0f;
        //opt.MinimumAngle = 34.0;

        foreach (CheesePolygon cheesePolygon in polygon.getSlicedPolygon().getDisjointCheesePolygons()) {
            NetMesh mesh = cheesePolygon.toNetPoly().Triangulate(opt);

            //collect all vertices
            foreach (NetTriangle t in mesh.Triangles) {
				GameVertex v1 = new GameVertex(Converter.netVertexToVector(t.GetVertex(2)));
				GameVertex v2 = new GameVertex(Converter.netVertexToVector(t.GetVertex(1)));
				GameVertex v3 = new GameVertex(Converter.netVertexToVector(t.GetVertex(0)));

                v1 = vertices.getUnique(v1);
                v2 = vertices.getUnique(v2);
                v3 = vertices.getUnique(v3);

                triangles.add(new Triangle(v1, v2, v3));
            }
        }

        outIndices = new List<int>();

		List<GameVertex> listVertices = vertices.toList();
        outVertices = listVertices.ConvertAll<Vector3>(x => x.getVector());

        foreach (Triangle triangle in triangles) {
            outIndices.Add(listVertices.IndexOf(triangle[0]));
            outIndices.Add(listVertices.IndexOf(triangle[1]));
            outIndices.Add(listVertices.IndexOf(triangle[2]));
        }
    }

    public static void triangulateForTerrain(MapPolygon polygon, Set<TerrainVertex> terrainVertices, Set<TerrainSegment> terrainSegments, Set<TerrainTriangle> terrainTriangles) {
        QualityOptions opt = new QualityOptions();
        opt.MaximumArea = 4000000.0f;
        opt.MinimumAngle = 34.0;

        foreach (CheesePolygon cheesePolygon in polygon.getSlicedPolygon().getDisjointCheesePolygons()) {
            NetMesh mesh = cheesePolygon.toNetPoly().Triangulate(opt);

            foreach (NetTriangle t in mesh.Triangles) {
                TerrainVertex v1 = new TerrainVertex(Converter.netVertexToVector(t.GetVertex(2)));
                TerrainVertex v2 = new TerrainVertex(Converter.netVertexToVector(t.GetVertex(1)));
                TerrainVertex v3 = new TerrainVertex(Converter.netVertexToVector(t.GetVertex(0)));

                v1 = terrainVertices.getUnique(v1);
                v2 = terrainVertices.getUnique(v2);
                v3 = terrainVertices.getUnique(v3);

                TerrainSegment s1 = new TerrainSegment(v1, v2);
                TerrainSegment s2 = new TerrainSegment(v2, v3);
                TerrainSegment s3 = new TerrainSegment(v3, v1);

                s1 = terrainSegments.getUnique(s1);
                s2 = terrainSegments.getUnique(s2);
                s3 = terrainSegments.getUnique(s3);

                TerrainTriangle terrainTriangle = new TerrainTriangle(v1, v2, v3, polygon.getTerrain());

                v1.link(s1);
                v1.link(s3);

                v2.link(s1);
                v2.link(s2);

                v3.link(s2);
                v3.link(s3);

                terrainTriangle.link(s1);
                terrainTriangle.link(s2);
                terrainTriangle.link(s3);

                s1.link(terrainTriangle);
                s2.link(terrainTriangle);
                s3.link(terrainTriangle);

                terrainTriangles.add(terrainTriangle);
            }
        }
    }
}
