"""
Python 3.x code to get GEM-Mars data from the BIRA webserver for a given geometry or HDF5 data file

Example url: https://gem-mars.aeronomie.be/vespa-gem?myear=35&lat=-56.5&lon=111.4&ls=123.4&lst=0.6

"""
import numpy as np
import requests
from bs4 import BeautifulSoup
from datetime import datetime

import matplotlib.pyplot as plt




DUST_STORM_YEARS = [34]
DEFAULT_NON_STORM_YEAR = 35




def get_mars_year_ls(dt):
    """get mars year and ls from a UTC datetime without loading SPICE kernels
    Calculation approximation from Piqueux et al. 2015 http://dx.doi.org/10.1016/j.icarus.2014.12.014"""

    j2000 = datetime(2000, 1, 1, 12)
    dpr = 57.29577951308232

    my_offset = 24.0 #Mars year at J2000 epoch
    
    
    delta_days_j2000 = (dt - j2000).days + (dt - j2000).seconds / 3600. / 24.
    
    
    
    M = (19.38095 + 0.524020769 * delta_days_j2000) / dpr #mean anomaly
    
    
    ls_total = 270.38859 + 0.524038542 * delta_days_j2000 + 10.67848 * np.sin(M) + 0.62077 * np.sin(2 * M) + 0.05031 * np.sin(3 * M)
    
    divide = np.divmod(ls_total, 360.0) #get quotient and remainder
    
    #quotient is mars year at j2000 epoch. Add offset to get correct year    
    return [divide[0] + my_offset, divide[1]]





def get_gem_data(myear, ls, lat, lon, lst, plot=False):
    """get data from gem model via the BIRA-Vespa interface
    
    Inputs:
    myear: two Martian years are available, 34 (dust storm) or 35 (no dust storm)
    ls = Mars season
    lat = latitude (-90 to +90)
    lon = longitude. Values can be 0-360 or -180 to 180 East positive
    lst = local solar time
    plot = plot output?
    
    """

    #choose correct Martian year
    if int(myear) in DUST_STORM_YEARS:
        myear = 34
    else:
        myear = DEFAULT_NON_STORM_YEAR


    url = f"https://gem-mars.aeronomie.be/vespa-gem?myear={myear}&lat={lat:#0.2f}&lon={lon:#0.2f}&ls={ls:#0.2f}&lst={lst:#0.3f}"
    
    

    
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'lxml')
    
    header_data = soup.find_all("field")
    table_data = soup.find_all("td")
    
    
    data = np.zeros(len(table_data))
    if len(table_data) == 0:
        print("Error getting GEM data")
    
    for i, element in enumerate(table_data):
        data[i] = np.float32(element.text)
        
    data = data.reshape(-1, len(header_data))
    
    atmos_dict = {element["id"].lower():data[:, i] for i, element in enumerate(header_data)}
    
    if plot:
        fig, axes = plt.subplots(figsize=(18, 5), ncols=8, constrained_layout=True)
        fig.suptitle("GEM-Mars: " + url.split("?")[1].replace("&", " "))
        
        axes_dict = {
            "co":{"ax":3, "log":False},
            "co2":{"ax":4, "log":False},
            "h20":{"ax":3, "log":False},
            "nd":{"ax":2, "log":True},
            "o2":{"ax":5, "log":False},
            "o3":{"ax":6, "log":False},
            "p":{"ax":0, "log":True},
            "t":{"ax":1, "log":False},
            "ext_dust":{"ax":7, "log":False},
            "ext_h2o_ice":{"ax":7, "log":False},
            }
        
        
        
        for header in atmos_dict.keys():
            if header in axes_dict:
                ax = axes_dict[header]["ax"]
                log = axes_dict[header]["log"]
                
                axes[ax].plot(atmos_dict[header], atmos_dict["z"], label=header.upper())
                if log:
                    axes[ax].set_xscale("log")
                axes[ax].grid()
                axes[ax].legend()
            
        axes[0].set_ylabel("Tangent Altitude (km)")
        
    return atmos_dict




def get_gem_data_from_h5(h5_f, tangent_altitude=50.0, index=None, plot=False):
    """Get gem data from the geometry of a hdf5 file.

    Inputs:
    h5_f: an open NOMAD hdf5 file from level 0.2a or above
    index: the index of the spectrum where 0=first spectrum
        if index is not specified:
            if occultation file, get geometry at the tangent point corrsponding to the given tangent_altitude,
            if nadir, get geometry from minimum incidence angle
    plot: plot data?
    """

    if not index:
        if "TangentAltAreoid" in h5_f["Geometry/Point0"].keys():
            #get index closest to reference altitude
            alts = h5_f["Geometry/Point0/TangentAltAreoid"][:, 0]
            index = np.abs(alts - tangent_altitude).argmin()
        
        else:
            incid = h5_f["Geometry/Point0/IncidenceAngle"][:, 0]
            index = np.argmin(incid)
            
            print(incid[index])
            
        
    
    lon = h5_f["Geometry/Point0/Lon"][index, 0]
    lat = h5_f["Geometry/Point0/Lat"][index, 0]
    lst = h5_f["Geometry/Point0/LST"][index, 0]
    
    dt_str = h5_f["Geometry/ObservationDateTime"][index, 0].decode()
    
    dt = datetime.strptime(dt_str, "%Y %b %d %H:%M:%S.%f")
    
    myear, ls = get_mars_year_ls(dt)
    
    return get_gem_data(myear, ls, lat, lon, lst, plot=plot)
    
    
    
    
# example run
# atmos_dict = get_gem_data(36, 180.0, 0.0, 0.0, 12.0, plot=True)