import java.util.HashSet;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

public class Aufgabe4Test {

    private NamedBodyForcePair sun2, mercury2, venus2, earth2, moon2, mars2, deimos2, phobos2, vesta2, pallas2, hygiea2, ceres2;

    public void resetBodies() {
        sun2 = new NamedBodyForcePair(SolSystem4.SUN_NAMED);
        earth2 = new NamedBodyForcePair(SolSystem4.EARTH_NAMED);
        moon2 = new NamedBodyForcePair(SolSystem4.MOON_NAMED);
        mars2 = new NamedBodyForcePair(SolSystem4.MARS_NAMED);
        deimos2 = new NamedBodyForcePair(SolSystem4.DEIMOS_NAMED);
        phobos2 = new NamedBodyForcePair(SolSystem4.PHOBOS_NAMED);
        mercury2 = new NamedBodyForcePair(SolSystem4.MERCURY_NAMED);
        venus2 = new NamedBodyForcePair(SolSystem4.VENUS_NAMED);
        vesta2 = new NamedBodyForcePair(SolSystem4.VESTA_NAMED);
        pallas2 = new NamedBodyForcePair(SolSystem4.PALLAS_NAMED);
        hygiea2 = new NamedBodyForcePair(SolSystem4.HYGIEA_NAMED);
        ceres2 = new NamedBodyForcePair(SolSystem4.CERES_NAMED);
    }

    @Test
    public void testEP2() {
        //test classes HierarchicalSystem and NamedBodyForcePair

        Body sun1 = new Body(SolSystem4.SUN);
        Body earth1 = new Body(SolSystem4.EARTH);
        Body moon1 = new Body(SolSystem4.MOON);
        Body mars1 = new Body(SolSystem4.MARS);
        Body deimos1 = new Body(SolSystem4.DEIMOS);
        Body phobos1 = new Body(SolSystem4.PHOBOS);
        Body mercury1 = new Body(SolSystem4.MERCURY);
        Body venus1 = new Body(SolSystem4.VENUS);
        Body vesta1 = new Body(SolSystem4.VESTA);
        Body pallas1 = new Body(SolSystem4.PALLAS);
        Body hygiea1 = new Body(SolSystem4.HYGIEA);
        Body ceres1 = new Body(SolSystem4.CERES);

        Body[] bodies = new Body[]{sun1, mercury1, venus1, earth1, moon1, mars1, deimos1, phobos1, vesta1, pallas1, hygiea1, ceres1};
        Vector3[] forceOnBody = new Vector3[bodies.length];
        resetBodies();
        NamedBodyForcePair[] pairs = new NamedBodyForcePair[]{sun2, mercury2, venus2, earth2, moon2, mars2, deimos2, phobos2, vesta2, pallas2, hygiea2, ceres2};

        // check basic functions of 'HierarchicalSystem'
        CosmicSystem earthSystem = new HierarchicalSystem(earth2, moon2);
        CosmicSystem marsSystem = new HierarchicalSystem(mars2, deimos2, phobos2);
        CosmicSystem solarSystem = new HierarchicalSystem(sun2, mercury2, venus2, earthSystem, marsSystem, vesta2, pallas2, hygiea2, ceres2);

        assertEquals(2, earthSystem.numberOfBodies());
        assertEquals(12, solarSystem.numberOfBodies());

        System.out.println(solarSystem);
        assertTrue(solarSystem.toString().contains("Mars"));
        assertTrue(solarSystem.toString().contains("Deimos"));
        assertTrue(solarSystem.toString().contains("Moon"));
        assertTrue(earthSystem.toString().contains("Moon"));
        assertTrue(earthSystem.toString().contains("Earth"));

        assertEquals(1.9890118865556799E30, solarSystem.getMass());

        BodyLinkedList bl = solarSystem.getBodies();
        assertEquals(12, bl.size());
        HashSet<Body> set = new HashSet<>();
        while (bl.size() > 0) {
            set.add(bl.pollFirst());
        }
        assertEquals(12, set.size());

        for (int seconds = 0; seconds < 50000; seconds++) {
            // for each body (with index i): compute the total force exerted on it.
            for (int i = 0; i < bodies.length; i++) {
                forceOnBody[i] = new Vector3(0, 0, 0); // begin with zero
                for (int j = 0; j < bodies.length; j++) {
                    if (i != j) {
                        pairs[i].addForceTo(pairs[j]);
                        Vector3 forceToAdd = bodies[i].gravitationalForce(bodies[j]);
                        forceOnBody[i] = forceOnBody[i].plus(forceToAdd);
                    }
                }
            }
            // now forceOnBody[i] holds the force vector exerted on body with index i.

            // for each body (with index i): move it according to the total force exerted on it.
            for (int i = 0; i < bodies.length; i++) {
                bodies[i].move(forceOnBody[i]);
                pairs[i].update();
            }
        }

        for (int i = 0; i < bodies.length; i++) {
            assertEquals(0, bodies[i].massCenter().distanceTo(pairs[i].getMassCenter()));
        }

        resetBodies();
        pairs = new NamedBodyForcePair[]{sun2, mercury2, venus2, earth2, moon2, mars2, deimos2, phobos2, vesta2, pallas2, hygiea2, ceres2};
        HierarchicalSystem hs = new HierarchicalSystem(sun2, mercury2, venus2, new HierarchicalSystem(earth2, moon2), new HierarchicalSystem(mars2, deimos2, phobos2), vesta2, pallas2, hygiea2, ceres2);

        for (int seconds = 0; seconds < 50000; seconds++) {
            hs.addForceTo(hs);
            hs.update();
        }

        for (int i = 0; i < bodies.length; i++) {
            assertEquals(0, bodies[i].massCenter().distanceTo(pairs[i].getMassCenter()));
        }
    }
}
