package ch.harmen.spaceproject;

import static ch.harmen.geomatics.Coordinates.coordinates;
import static com.google.common.base.Throwables.propagate;
import static java.lang.Math.PI;
import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.powermock.reflect.Whitebox;
import ch.harmen.geomatics.Coordinates;

/**
 * Tests the functionality of {@link DefaultBankingAngleCalculator}.
 */
public final class DefaultBankingAngleCalculatorTest {

    private final BankingAngleCalculator bankingAngleCalculator = new DefaultBankingAngleCalculator();

    /**
     * Tests the functionality of {@link DefaultBankingAngleCalculator#calculateEttaAngleInRadian(Coordinates,
     * Coordinates, double)}.
     */
    @Test
    public void testCalculateEttaAngleInRadianReturnsTheCorrectResult() {
        assertEquals("Wrong etta angle returned.",
                     0,
                     calculateEttaAngleInRadian(// target position
                                                coordinates("10.0",
                                                            "0.0"),
                                                //current position
                                                coordinates("0.0",
                                                            "0.0"),
                                                // yaw in radian
                                                0),
                     0);

        assertEquals("Wrong etta angle returned.",
                     PI / 4,
                     calculateEttaAngleInRadian(// target position
                                                coordinates("10.0",
                                                            "10.0"),
                                                //current position
                                                coordinates("0.0",
                                                            "0.0"),
                                                // yaw in radian
                                                0),
                     0.001);
        assertEquals("Wrong etta angle returned.",
                     PI / 2,
                     calculateEttaAngleInRadian(// target position
                                                coordinates("0.0",
                                                            "10.0"),
                                                //current position
                                                coordinates("0.0",
                                                            "0.0"),
                                                // yaw in radian
                                                0),
                     0.001);
        assertEquals("Wrong etta angle returned.",
                     PI * 3 / 4,
                     calculateEttaAngleInRadian(// target position
                                                coordinates("-10.0",
                                                            "10.0"),
                                                //current position
                                                coordinates("0.0",
                                                            "0.0"),
                                                // yaw in radian
                                                0),
                     0.001);

        assertEquals("Wrong etta angle returned.",
                     -PI / 4,
                     calculateEttaAngleInRadian(// target position
                                                coordinates("10.0",
                                                            "-10.0"),
                                                //current position
                                                coordinates("0.0",
                                                            "0.0"),
                                                // yaw in radian
                                                0),
                     0.001);
        assertEquals("Wrong etta angle returned.",
                     -PI / 2,
                     calculateEttaAngleInRadian(// target position
                                                coordinates("0.0",
                                                            "-10.0"),
                                                //current position
                                                coordinates("0.0",
                                                            "0.0"),
                                                // yaw in radian
                                                0),
                     0.001);
        assertEquals("Wrong etta angle returned.",
                     -PI * 3 / 4,
                     calculateEttaAngleInRadian(// target position
                                                coordinates("-10.0",
                                                            "-10.0"),
                                                //current position
                                                coordinates("0.0",
                                                            "0.0"),
                                                // yaw in radian
                                                0),
                     0.001);

        assertEquals("Wrong etta angle returned.",
                     PI,
                     calculateEttaAngleInRadian(// target position
                                                coordinates("-10.0",
                                                            "0.0"),
                                                //current position
                                                coordinates("0.0",
                                                            "0.0"),
                                                // yaw in radian
                                                0),
                     0.001);
    }

    /**
     * Invokes the private {@link DefaultBankingAngleCalculator#calculateEttaAngleInRadian(Coordinates, Coordinates,
     * double)} using reflection.
     */
    private double calculateEttaAngleInRadian(final Coordinates targetPosition,
                                              final Coordinates currentPosition,
                                              final double yawInRadian) {
        try {
            return Whitebox.invokeMethod(bankingAngleCalculator,
                                         "calculateEttaAngleInRadian",
                                         targetPosition,
                                         currentPosition,
                                         yawInRadian);
        } catch (Exception e) {
            throw propagate(e);
        }
    }

}
