"""gravity_assist_intersecting.py

Orbity Księżyca i statku przecinają się.
Księżyc spowalnia i zmienia kierunek lotu statku.

Autor: Eric T. Mortenson
"""

from turtle import Shape, Screen, Turtle, Vec2D as Vec
import turtle
import math
import sys

# Dane wprowadzone przez użytkownika
G = 8  # Stała grawitacji używana do symulacji
NUM_LOOPS = 7000  # Liczba odstępów czasu, jakie trwa symulacja
Ro_X = -152.18  # Współrzędna x początkowej pozycji statku
Ro_Y = 329.87  # Współrzędna y początkowej pozycji statku
Vo_X = 423.10  # Składowa x prędkości w momencie rozpoczęcia manewru TLI
Vo_Y = -512.26  # Składowa y prędkości w momencie rozpoczęcia manewru TLI


MOON_MASS = 1_250_000


class GravSys():
    """Przeprowadza symulację oddziaływań grawitacyjnych na n ciałach."""

    def __init__(self):
        self.bodies = []
        self.t = 0
        self.dt = 0.001

    def sim_loop(self):
        """Dla każdego odcinka czasu przechodzi przez listę ciał."""
        # Zatrzymuje symulację po odpowiednim czasie.
        for index in range(NUM_LOOPS):
            self.t += self.dt
            for body in self.bodies:
                body.step()


class Body(Turtle):
    """Ciało niebieskie, które orbituje i ma pole grawitacyjne."""
    def __init__(self, mass, start_loc, vel, gravsys, shape):
        super().__init__(shape=shape)
        self.gravsys = gravsys
        self.penup()
        self.mass=mass
        self.setpos(start_loc)
        self.vel = vel
        gravsys.bodies.append(self)
        self.pendown()  # Odkomentuj, aby obiekt rysował za sobą ścieżkę.
        
    def acc(self):
        """
        Oblicza połączone siły działające na ciało
        i zwraca składowe wektora.
        """
        a = Vec(0,0)
        for body in self.gravsys.bodies:
            if body != self:
                r = body.pos() - self.pos()
                # Jednostki: odległość/czas^2
                a += (G * body.mass / abs(r)**3) * r
        return a
    
    def step(self):
        """Oblicza pozycję, zwrot i prędkość ciała."""
        dt = self.gravsys.dt
        a = self.acc()
        self.vel = self.vel + dt * a
        xOld, yOld = self.pos()  # Aby nadać odpowiedni kierunek statkowi.
        self.setpos(self.pos() + dt * self.vel)
        xNew, yNew = self.pos()  # Aby nadać odpowiedni kierunek statkowi.
        if self.gravsys.bodies.index(self) == 1:  # Moduł CSM
            # Aby nadać odpowiedni kierunek statkowi.
            dir_radians = math.atan2(yNew - yOld,xNew - xOld)
            # Aby nadać odpowiedni kierunek statkowi.
            dir_degrees = dir_radians * 180 / math.pi
            # Aby nadać odpowiedni kierunek statkowi.
            self.setheading(dir_degrees+90)
            

def main():
    # Konfiguracja ekranu
    screen = Screen()
    screen.setup(width=1.0, height=1.0)  # Tryb pełnoekranowy
    screen.bgcolor('black')
    screen.title("Przykład asysty grawitacyjnej")

    # Tworzy obiekt reprezentujący układ ciał.
    gravsys = GravSys()
    
    # Tworzy obiekt turtle reprezentujący Księżyc.
    image_moon = 'moon_27x27.gif'
    screen.register_shape(image_moon)
    moon = Body(MOON_MASS, (-250, 0), Vec(500, 0), gravsys, image_moon)
    moon.pencolor('gray')

    # Tworzy kształt modułu usługowego i dowodzenia (csm).
    csm = Shape('compound')
    cm = ((0, 30), (0, -30), (30, 0))
    csm.addcomponent(cm, 'red', 'red')
    sm = ((-60, 30), (0, 30), (0, -30), (-60, -30))
    csm.addcomponent(sm, 'red', 'black')
    nozzle = ((-55, 0), (-90, 20), (-90, -20))
    csm.addcomponent(nozzle, 'red', 'red')
    screen.register_shape('csm', csm)

    # Tworzy obiekt turtle reprezentujący moduł CSM misji Apollo 8.
    ship = Body(1, (Ro_X, Ro_Y), Vec(Vo_X, Vo_Y), gravsys, "csm")
    ship.shapesize(0.2)
    ship.color('red')  # Ustawia kolor ścieżki.
    ship.getscreen().tracer(1, 0)
    ship.setheading(90)

    gravsys.sim_loop()


if __name__ == '__main__':
    main()
