package de.frajul.endlessroll.entities.collision;

import de.frajul.endlessroll.data.Vector;
import de.frajul.endlessroll.entities.collision.geometry.Circle;
import de.frajul.endlessroll.entities.collision.geometry.Triangle;

/**
 * Created by Julian on 28.02.2016.
 */
public class CircleTriangleCollisionDetector {

    public boolean circleTriangleCollision(Circle circle, Triangle triangle) {
        if (circleIntersectingWithTriangleVertices(circle, triangle))
            return true;

        if (circleCenterInsideTriangle(circle, triangle))
            return true;

        if (circleIntersectingWithTriangleEdges(circle, triangle))
            return true;
        return false;
    }

    private boolean circleIntersectingWithTriangleEdges(Circle circle, Triangle triangle) {
        Vector edge1 = triangle.getVertex1().vectorTo(triangle.getVertex2());
        Vector edge2 = triangle.getVertex2().vectorTo(triangle.getVertex3());
        Vector edge3 = triangle.getVertex3().vectorTo(triangle.getVertex1());

        boolean intersectingWithEdge1 = circleIntersectingWithTriangleEdge(circle, triangle.getVertex1(), edge1);
        boolean intersectingWithEdge2 = circleIntersectingWithTriangleEdge(circle, triangle.getVertex2(), edge2);
        boolean intersectingWithEdge3 = circleIntersectingWithTriangleEdge(circle, triangle.getVertex3(), edge3);
        return intersectingWithEdge1 || intersectingWithEdge2 || intersectingWithEdge3;
    }

    private boolean circleIntersectingWithTriangleEdge(Circle circle, Vector vertex, Vector edge) {
        Vector vertexToCenter = vertex.vectorTo(circle.getCenter());
        Vector kVector = new Vector(vertexToCenter).mul(edge);
        float k = kVector.x + kVector.y;

        if (k > 0) {
            float length = edge.length();
            k = k / length;

            if (k < length)
                if (Math.sqrt(vertexToCenter.x * vertexToCenter.x + vertexToCenter.y * vertexToCenter.y - k * k) <= circle.getRadius())
                    return true;
        }
        return false;
    }

    private boolean circleCenterInsideTriangle(Circle circle, Triangle triangle) {
        Vector vertex1To2 = triangle.getVertex1().vectorTo(triangle.getVertex2());
        Vector vertex2To3 = triangle.getVertex2().vectorTo(triangle.getVertex3());
        Vector vertex3To1 = triangle.getVertex3().vectorTo(triangle.getVertex1());
        Vector vertex1ToCenter = triangle.getVertex1().vectorTo(circle.getCenter());
        Vector vertex2ToCenter = triangle.getVertex2().vectorTo(circle.getCenter());
        Vector vertex3ToCenter = triangle.getVertex3().vectorTo(circle.getCenter());

        boolean centerInsideV1V2 = vertex1To2.y * vertex1ToCenter.x - vertex1To2.x * vertex1ToCenter.y < 0;
        boolean centerInsideV2V3 = vertex2To3.y * vertex2ToCenter.x - vertex2To3.x * vertex2ToCenter.y < 0;
        boolean centerInsideV3V1 = vertex3To1.y * vertex3ToCenter.x - vertex3To1.x * vertex3ToCenter.y < 0;

        return centerInsideV1V2 && centerInsideV2V3 && centerInsideV3V1;
    }

    private boolean circleIntersectingWithTriangleVertices(Circle circle, Triangle triangle) {
        boolean intersectingWithVertex1 = circleIntersectingWithTriangleVertex(circle, triangle.getVertex1());
        boolean intersectingWithVertex2 = circleIntersectingWithTriangleVertex(circle, triangle.getVertex2());
        boolean intersectingWithVertex3 = circleIntersectingWithTriangleVertex(circle, triangle.getVertex3());
        return intersectingWithVertex1 || intersectingWithVertex2 || intersectingWithVertex3;
    }

    private boolean circleIntersectingWithTriangleVertex(Circle circle, Vector vertex) {
        Vector centerToVertex = circle.getCenter().vectorTo(vertex);
        return centerToVertex.length() <= circle.getRadius();
    }

}
