////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////

package pp.util;

import org.junit.Test;

import static java.lang.Math.min;
import static org.junit.Assert.assertEquals;
import static pp.util.FloatMath.DEG_TO_RAD;
import static pp.util.FloatMath.ZERO_TOLERANCE;
import static pp.util.FloatMath.cos;
import static pp.util.FloatMath.sin;

public class AngleTest {
    @Test
    public void compareAngles() {
        for (int i = 0; i < 360; i++) {
            final Angle u = Angle.fromDegrees(i);
            for (int j = 0; j < 360; j++) {
                final Angle v = Angle.fromDegrees(j);
                assertEquals("compare " + i + "° and " + j + "°", Integer.compare(i, j), (Object) u.compareTo(v));
            }
        }
    }

    @Test
    public void addAngles() {
        for (int i = 0; i < 360; i++) {
            final Angle u = Angle.fromDegrees(i);
            for (int j = 0; j < 360; j++) {
                final Angle v = Angle.fromDegrees(j);
                final Angle sum = u.plus(v);
                assertEquals(i + "° + " + j + "°, x coordinate", cos((i + j) * DEG_TO_RAD), sum.x, ZERO_TOLERANCE);
                assertEquals(i + "° + " + j + "°, y coordinate", sin((i + j) * DEG_TO_RAD), sum.y, ZERO_TOLERANCE);
            }
        }
    }

    @Test
    public void subtractAngles() {
        for (int i = 0; i < 360; i++) {
            final Angle u = Angle.fromDegrees(i);
            for (int j = 0; j < 360; j++) {
                final Angle v = Angle.fromDegrees(j);
                final Angle diff = u.minus(v);
                assertEquals(i + "° - " + j + "°, x coordinate", cos((i - j) * DEG_TO_RAD), diff.x, ZERO_TOLERANCE);
                assertEquals(i + "° - " + j + "°, y coordinate", sin((i - j) * DEG_TO_RAD), diff.y, ZERO_TOLERANCE);
            }
        }
    }

    @Test
    public void minAngle() {
        for (int i = 0; i < 360; i++) {
            final Angle u = Angle.fromDegrees(i);
            for (int j = 0; j < 360; j++) {
                final Angle v = Angle.fromDegrees(j);
                final Angle diff = Angle.min(u, v);
                assertEquals(i + "° - " + j + "°, x coordinate", cos(min(i, j) * DEG_TO_RAD), diff.x, ZERO_TOLERANCE);
                assertEquals(i + "° - " + j + "°, y coordinate", sin(min(i, j) * DEG_TO_RAD), diff.y, ZERO_TOLERANCE);
            }
        }
    }

    @Test
    public void bisector() {
        for (int right = 0; right < 360; right++) {
            final Angle rightAngle = Angle.fromDegrees(right);
            for (int add = 0; add < 360; add++) {
                final int left = right + add;
                final Angle bisector = Angle.fromDegrees(left).bisector(rightAngle);
                final float exp = (right + 0.5f * add) * DEG_TO_RAD;
                assertEquals("left=" + left + "° / right=" + right + "°, x coordinate", cos(exp), bisector.x, ZERO_TOLERANCE);
                assertEquals("left=" + left + "° / right=" + right + "°, y coordinate", sin(exp), bisector.y, ZERO_TOLERANCE);
            }
        }
    }

    @Test
    public void leftOf() {
        for (int right = 0; right < 360; right++) {
            final Angle rightAngle = Angle.fromDegrees(right);
            for (int add = 1; add < 360; add++)
                if (add != 180) {
                    final int left = right + add;
                    final Angle leftAngle = Angle.fromDegrees(left);
                    assertEquals(left + "° left of " + right + "°", add < 180, leftAngle.leftOf(rightAngle));
                }
        }
    }

    @Test
    public void rightOf() {
        for (int right = 0; right < 360; right++) {
            final Angle rightAngle = Angle.fromDegrees(right);
            for (int add = 1; add < 360; add++)
                if (add != 180) {
                    final int left = right + add;
                    final Angle leftAngle = Angle.fromDegrees(left);
                    assertEquals(left + "° right of " + right + "°", add > 180, leftAngle.rightOf(rightAngle));
                }
        }
    }
}