#!/usr/bin/env python

from aman.com.Weather import Weather

import math
import scipy.interpolate

class WeatherModel:
    def __init__(self, gaforId, weather : Weather):
        self.Gafor = gaforId
        self.Weather = weather
        self.WindDirectionModel = None
        self.WindSpeedModel = None
        self.LastWeatherUpdate = None
        self.MinimumAltitude = 1000000
        self.MaximumAltitude = -1

        # create the density interpolation model
        # the density model is based on https://aerotoolbox.com/atmcalc/
        altitudes = [
            50000,
            45000,
            40000,
            38000,
            36000,
            34000,
            32000,
            30000,
            28000,
            26000,
            24000,
            22000,
            20000,
            18000,
            16000,
            15000,
            14000,
            13000,
            12000,
            11000,
            10000,
            9000,
            8000,
            7000,
            6000,
            5000,
            4000,
            3000,
            2000,
            1000,
            0
        ]
        densities = [
            0.18648,
            0.23714,
            0.24617,
            0.33199,
            0.36518,
            0.39444,
            0.42546,
            0.45831,
            0.402506,
            0.432497,
            0.464169,
            0.60954,
            0.65269,
            0.69815,
            0.74598,
            0.77082,
            0.79628,
            0.82238,
            0.84914,
            0.87655,
            0.90464,
            0.93341,
            0.96287,
            0.99304,
            1.02393,
            1.05555,
            1.08791,
            1.12102,
            1.1549,
            1.18955,
            1.225
        ]
        self.densityModel = scipy.interpolate.interp1d(altitudes, densities)

    def calculateTAS(self, altitude : int, ias : int):
        if altitude >= 50000:
            altitude = 49999
        if altitude <= 0:
            altitude = 1

        # calculation based on https://aerotoolbox.com/airspeed-conversions/
        return ias * math.sqrt(1.225 / self.densityModel(altitude).item())

    def updateWindModel(self):
        if None == self.LastWeatherUpdate or self.LastWeatherUpdate != self.Weather.Provider.UpdateTime:
            self.LastWeatherUpdate = self.Weather.Provider.UpdateTime

            self.MinimumAltitude = 1000000
            self.MaximumAltitude = -1
            self.WindDirectionModel = None
            self.WindSpeedModel = None

            if None != self.Weather.Provider.WindData and self.Gafor in self.Weather.Provider.WindData:
                altitudes = []
                directions = []
                speeds = []

                # collect the data for the wind model
                for level in self.Weather.Provider.WindData[self.Gafor]:
                    altitudes.append(level[0])
                    directions.append(level[1])
                    speeds.append(level[2])

                    # define the thresholds for later boundary checks
                    if self.MinimumAltitude > level[0]:
                        self.MinimumAltitude = level[0]
                    if self.MaximumAltitude < level[0]:
                        self.MaximumAltitude = level[0]

                # calculate the models
                if 1 < len(altitudes):
                    self.WindDirectionModel = scipy.interpolate.interp1d(altitudes, directions)
                    self.WindSpeedModel = scipy.interpolate.interp1d(altitudes, speeds)

    def calculateGS(self, altitude : int, ias : int, heading : int):
        self.updateWindModel()
        tas = self.calculateTAS(altitude, ias)

        # initialize the wind data
        if None != self.WindDirectionModel and None != self.WindSpeedModel:
            direction = 0.0
            speed = 0.0
            if None != self.WindSpeedModel and None != self.WindDirectionModel:
                if self.MaximumAltitude <= altitude:
                    altitude = self.MaximumAltitude - 1
                if self.MinimumAltitude >= altitude:
                    altitude = self.MinimumAltitude + 1
                direction = self.WindDirectionModel(altitude).item()
                speed = self.WindSpeedModel(altitude).item()
        else:
            speed = 0
            direction = 0

        # calculate the ground speed based on the headwind component
        return tas + speed * math.cos(math.radians(direction) - math.radians(heading))