import codedraw.CodeDraw;

import java.awt.*;
import java.util.Random;

/**
 * Simulates the formation of a massive solar system.
 */
public class Simulation5 {

    // gravitational constant
    public static final double G = 6.6743e-11;

    // one astronomical unit (AU) is the average distance of earth to the sun.
    public static final double AU = 150e9; // meters

    // one light year
    public static final double LY = 9.461e15; // meters

    // some further constants needed in the simulation
    public static final double SUN_MASS = 1.989e30; // kilograms
    public static final double SUN_RADIUS = 696340e3; // meters
    public static final double EARTH_MASS = 5.972e24; // kilograms
    public static final double EARTH_RADIUS = 6371e3; // meters

    // set some system parameters
    public static final double SECTION_SIZE = 10 * AU; // the size of the square region in space

    public static final int NUMBER_OF_BODIES = 22;
    public static final double OVERALL_SYSTEM_MASS = 20 * SUN_MASS; // kilograms

    // all quantities are based on units of kilogram respectively second and meter.

    /**
     * The main simulation method using instances of other classes.
     */
    public static void main(String[] args) {
        // simulation
        CodeDraw cd = new CodeDraw();

        // create solar system with 12 bodies
        NamedBody sun = new NamedBody(SolSystem4.SUN_NAMED);
        NamedBody earth = new NamedBody(SolSystem4.EARTH_NAMED);
        NamedBody moon = new NamedBody(SolSystem4.MOON_NAMED);
        NamedBody mars = new NamedBody(SolSystem4.MARS_NAMED);
        NamedBody deimos = new NamedBody(SolSystem4.DEIMOS_NAMED);
        NamedBody phobos = new NamedBody(SolSystem4.PHOBOS_NAMED);
        NamedBody mercury = new NamedBody(SolSystem4.MERCURY_NAMED);
        NamedBody venus = new NamedBody(SolSystem4.VENUS_NAMED);
        NamedBody vesta = new NamedBody(SolSystem4.VESTA_NAMED);
        NamedBody pallas = new NamedBody(SolSystem4.PALLAS_NAMED);
        NamedBody hygiea = new NamedBody(SolSystem4.HYGIEA_NAMED);
        NamedBody ceres = new NamedBody(SolSystem4.CERES_NAMED);

        // create some additional bodies
        Body[] bodies = new Body[NUMBER_OF_BODIES];

        Random random = new Random(2022);

        for (int i = 0; i < bodies.length; i++) {
            bodies[i] = new Body(
                    Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / bodies.length,
                    new Vector3(0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU),
                    new Vector3(0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3)
            );
        }

        MassiveForceHashMap forceOnBody = new MassiveForceHashMap();
        forceOnBody.put(sun, new Vector3());
        forceOnBody.put(earth, new Vector3());
        forceOnBody.put(moon, new Vector3());
        forceOnBody.put(mars, new Vector3());
        forceOnBody.put(deimos, new Vector3());
        forceOnBody.put(phobos, new Vector3());
        forceOnBody.put(mercury, new Vector3());
        forceOnBody.put(venus, new Vector3());
        forceOnBody.put(vesta, new Vector3());
        forceOnBody.put(pallas, new Vector3());
        forceOnBody.put(hygiea, new Vector3());
        forceOnBody.put(ceres, new Vector3());

        for (Body b : bodies) {
            forceOnBody.put(b, new Vector3());
        }

        long seconds = 0;
        while (true) {
            seconds++;

            for (Massive b1 : forceOnBody.keyList()) {
                Vector3 force = new Vector3();
                for (Massive b2 : forceOnBody.keyList()) {
                    if (b1 != b2) {
                        force = force.plus(b1.gravitationalForce(b2));
                    }
                }
                forceOnBody.put(b1, force);
            }

            for (Massive body : forceOnBody.keyList()) {
                body.move(forceOnBody.get(body));
            }

            if ((seconds % 3600) == 0) {
                cd.clear(Color.BLACK);
                for (Massive body : forceOnBody.keyList()) {
                    body.draw(cd);
                }
                cd.show();
            }
        }
    }
}
