
"""
Author: M. Graham Macy
Date Created: 5/28/2024
Date Edited: 8/5/2024

Description:
Contains two classes: Airport and Airports

"""

import math
import random
import pandas as pd
import matplotlib.pyplot as plt
from constants import *


class Airport(object):

    """
    Airport() functions as an object that contains location data such as
    lat/long, runway length, and also parameters for computing OAT
    (Outside Air Temperature).

    For temperature calculations
    a = amplitude of sine wave through the year
    b = amplitude of daily sine wave
    c = average yearly temp
    d = coldest day

    Contains a function that can compute OAT given a
    time indicator. (this must be updated depending on functionality)
    """

    code: str
    lat: float
    lon: float
    alt_ft: float
    a: float
    b: float
    c: float
    d: float
    runway_length_ft: int

    def __init__(self,
                 code: str,
                 lat: float,
                 lon: float,
                 alt_ft: float,
                 a: float,
                 b: float,
                 c: float,
                 d: float,
                 runway_length_ft: int,
                 fuel_price: float,
                 depart_time: int=0,
                 depart_station: str="N/A",
                 arrival_station: str="N/A"):
        self.code = code
        self.lat = lat
        self.lon = lon
        self.alt_ft = alt_ft
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.runway_length_ft = runway_length_ft
        self.fuel_price = fuel_price
        self.depart_time = depart_time
        self.depart_station = depart_station
        self.arrival_station = arrival_station
        return

    def OAT(self, hrs_since_jan1_midnight: float):
        """
        Computes outside air temperature according to time
        !!!time is hours since 1/1/20!!!
        """
        # source for d:
        # https://www.climate.gov/news-features/understanding-climate/interactive-map-coldest-day-year-across-united-states
        # Temperature estimated as a function of time of year for each airport
        day = 24
        year = 365.25*day
        t = hrs_since_jan1_midnight - self.d
        temp = -self.a*math.cos(t*2*math.pi/(year)) +\
            self.b*math.sin((t+15)*2*math.pi/(day))+self.c
        OAT = temp+random.uniform(-0.5, 0.5)
        return OAT


class Airports(object):

    """
    Airports() is an object that can calculate things about airports.

    create_AirportList()
    Creates a list of initialized airport objects from a CSV file with 
    headers: code, lat, lon, alt_ft, a, b, c, d, runway_length_ft, fuel price

    create_ScheduleList()
    Creates a list of airport objects from a CSV file with 
    headers: depart_time, depart_station, arrival_station
    code, lat, lon, alt_ft, a, b, c, d, runway_length_ft, fuel price
    This list is a "Schedule" where airports appear in order.

    distance_nmi()
    calculates the distance between two airports
    """

    def __init__():
        return


    def create_AirportList(filename: str) -> list:

        """
        Takes in a csv file that necessarily includes information
        formatted into the following columns:
        "code" - airport code
        "lat" - airport latitude
        "lon" - longitude
        "alt_ft" - altitude in ft
        "a,b,c,d" - 4 columns that factor into calculating the weather
        "runway_length_ft" - airport runway length in ft
        "fuel_price" - price of fuel at airport

        !FUEL PRICE DOES NOT HAVE REFERENCE, AND HAS BEEN
        ESTIMATED AND SIMPLIFIED!
        """

        df = pd.read_csv(filename)

        airports = []
        for i,row in df.iterrows():
            code = row.code
            lat = row.lat
            lon = row.lon
            alt_ft = row.alt_ft
            a = row.a
            b = row.b
            c = row.c
            d = row.d
            runway_length_ft = row.runway_length_ft
            fuel_price = row.fuel_price
            airport = Airport(code,
                              lat,
                              lon,
                              alt_ft,
                              a,
                              b,
                              c,
                              d,
                              runway_length_ft,
                              fuel_price)

            airports.append(airport)

        return airports
    
    def create_ScheduleList(filename: str) -> list:

        """
        This schedule data "flightSchedule.csv" comes from
        real flight data. If flightSchedule.csv is missing from
        files, it will be necessary to recreate this from
        scratch.

        Takes in a csv file that is formatted to include
        the following columns:
        "depart_time" - departure time (hours after midnight Jan 1)
        "depart_station" - departure station airport code
        "arrival_station" - arrival station airport code
        "code" - airport code
        "lat" - airport latitude
        "lon" - longitude
        "alt_ft" - altitude in ft
        "a,b,c,d" - 4 columns that factor into calculating the weather
        "runway_length_ft" - airport runway length in ft
        "fuel_price" - price of fuel at airport

        !FUEL PRICE DOES NOT HAVE REFERENCE, AND HAS BEEN
        ESTIMATED AND SIMPLIFIED!

        """

        df = pd.read_csv(filename)

        schedule = []
        for i, row in df.iterrows():
            depart_time = row.depart_time
            depart_station = row.depart_station
            arrival_station = row.arrival_station
            code = row.code
            lat = row.lat
            lon = row.lon
            alt_ft = row.alt_ft
            a = row.a
            b = row.b
            c = row.c
            d = row.d
            runway_length_ft = row.runway_length_ft
            fuel_price = row.fuel_price
            leg = Airport(code,
                              lat,
                              lon,
                              alt_ft,
                              a,
                              b,
                              c,
                              d,
                              runway_length_ft,
                              fuel_price,
                              depart_time,
                              depart_station,
                              arrival_station,
                              )

            schedule.append(leg)

        return schedule

    def distance_nmi(origin: Airport, destination: Airport) -> float:
        lat1, lon1 = origin.lat, origin.lon
        lat2, lon2 = destination.lat, destination.lon
        Great_Circle_Inner_Step = (math.sin(math.radians(lat1)) * math.sin(math.radians(lat2)) + 
                                   math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * 
                                   math.cos(math.radians(lon2-lon1)))
        if Great_Circle_Inner_Step >= 1:
            distance_nmi = math.acos(1)
        else:
            distance_nmi = math.acos(math.sin(math.radians(lat1)) *
                                 math.sin(math.radians(lat2)) +
                                 math.cos(math.radians(lat1)) *
                                 math.cos(math.radians(lat2)) *
                                 math.cos(math.radians(lon2-lon1)))*3440
        return distance_nmi


if __name__ == "__main__":
    filename = schedule_filename
    airports = Airports.create_AirportList(filename)
    for i in range(len(airports)):
        print(airports[i].code)
        print("altitude")
        print(airports[i].alt_ft)
        print("runway length")
        print(airports[i].runway_length_ft)
    distance_printout = Airports.distance_nmi(airports[1], airports[5])
    print("The distance between " + airports[1].code + " and " +
          airports[5].code + " is " + str(distance_printout) + " nmi.")

    time = 1
    while time < 24*365:
        temp = airports[0].OAT(time)
        plt.figure(1)
        plt.plot(time/24,
                 temp,
                 '.b')
        plt.xlabel("Time - days since 1am Jan 1, 2020")
        plt.ylabel("Predicted EGTM (deg C)")
        plt.title("OAT")
        time += 24
    plt.grid()
    plt.show()
