using System;
using ClipperLib;
using UnityEngine;
using System.Collections.Generic;

/*
 * This class represents a triangle
*/
public class Triangle {
    protected GameVertex v1;
    protected GameVertex v2;
    protected GameVertex v3;
    protected List<Segment> segments;


    /*public Triangle(Contour points) {
        if (points.Count != 3) {
            throw new ArgumentException("Invalid number of points. Triangle = 3 points :)");
        }
        this.v1 = new GameVertex(points[0]);
        this.v1 = new GameVertex(points[1]);
        this.v1 = new GameVertex(points[2]);
        createSegments();
    }*/

    public Triangle(GameVertex v1, GameVertex v2, GameVertex v3) {
        this.v1 = v1;
        this.v2 = v2;
        this.v3 = v3;
        createSegments();
    }

    private void createSegments() {
        segments = new List<Segment>();
        segments.Add(new Segment(v1, v2));
        segments.Add(new Segment(v2, v3));
        segments.Add(new Segment(v3, v1));
    }

    public GameVertex this[int index] {
        get {
            if (index == 0) {
                return v1;
            }
            else if (index == 1) {
                return v2;
            }
            else if (index == 2) {
                return v3;
            }
            else {
                return null;
            }
        }
        set { //Cannot modify the vertices of a triangle
            return;
        }
    }

    public Contour getContour() {
        ContourBuilder builder = new ContourBuilder();

        builder.addVertex(v1);
        builder.addVertex(v2);
        builder.addVertex(v3);

        return builder.build();
    }

    private float sign(Vector2 p1, Vector2 p2, Vector2 p3) {
        return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
    }

    public bool isPointInside(GameVertex p) {
        bool b1, b2, b3;

        b1 = sign(p.getVector(), v1.getVector(), v2.getVector()) < 0.0f;
        b2 = sign(p.getVector(), v2.getVector(), v3.getVector()) < 0.0f;
        b3 = sign(p.getVector(), v3.getVector(), v1.getVector()) < 0.0f;

        return ((b1 == b2) && (b2 == b3));
    }

    //Returns null if they don't share any edge
    public Segment edgeShared(Triangle other) {
        Segment seg = null;

        foreach (Segment s in segments) {
            foreach (Segment otherS in other.segments) {
                if (s.Equals(otherS)) {
                    seg = s;
                }
            }
        }

        return seg;
    }

    //Returns false if they don't share any point
    public bool vertexShared(Triangle other, out GameVertex shared) {
        bool ret = false;
        shared = new GameVertex(new Vector2(float.NaN, float.NaN));

        if (v1 == other.v1) {
            shared = v1;
            ret = true;
        } else if (v1 == other.v2) {
            shared = v1;
            ret = true;
        } else if (v1 == other.v3) {
            shared = v1;
            ret = true;
        } else if (v2 == other.v1) {
            shared = v2;
            ret = true;
        } else if (v2 == other.v2) {
            shared = v2;
            ret = true;
        } else if (v2 == other.v3) {
            shared = v2;
            ret = true;
        } else if (v3 == other.v1) {
            shared = v3;
            ret = true;
        } else if (v3 == other.v2) {
            shared = v3;
            ret = true;
        } else if (v3 == other.v3) {
            shared = v3;
            ret = true;
        }

        return ret;
    }

    public float minDistanceTo(Segment seg) {
        float minVal = float.MaxValue;

        foreach (Segment s in segments) {
            minVal = Math.Min(minVal, s.distanceTo(seg));
        }

        return minVal;
    }

    public float maxDistanceTo(Segment seg) {
        float maxVal = float.MinValue;

        foreach (Segment s in segments) {
            maxVal = Math.Max(maxVal, s.distanceTo(seg));
        }

        return maxVal;
    }

    public float minDistanceTo(GameVertex pt) {
        float minVal = float.MaxValue;

        foreach (Segment s in segments) {
            minVal = Math.Min(minVal, s.distanceTo(pt));
        }

        return minVal;
    }

    public float maxDistanceTo(GameVertex pt) {
        float maxVal = float.MinValue;

        foreach (Segment s in segments) {
            maxVal = Math.Max(maxVal, s.distanceTo(pt));
        }

        return maxVal;
    }
}
