Function to download ERA5 data for GSSHA

    .. note:: https://software.ecmwf.int/wiki/display/WEBAPI/Access+ECMWF+Public+Datasets

    Args:
        main_directory(:obj:`str`): Location of the output for the forecast data.
        start_datetime(:obj:`str`): Datetime for download start.
        end_datetime(:obj:`str`): Datetime for download end.
        leftlon(Optional[:obj:`float`]): Left bound for longitude. Default is -180.
        rightlon(Optional[:obj:`float`]): Right bound for longitude. Default is 180.
        toplat(Optional[:obj:`float`]): Top bound for latitude. Default is 90.
        bottomlat(Optional[:obj:`float`]): Bottom bound for latitude. Default is -90.
        precip_only(Optional[bool]): If True, will only download precipitation.

    Example::

        from gsshapy.grid.era_to_gssha import download_era5_for_gssha

        era5_folder = '/era5'
        leftlon = -95
        rightlon = -75
        toplat = 35
        bottomlat = 30
        download_era5_for_gssha(era5_folder, leftlon, rightlon, toplat, bottomlat)

def download_era5_for_gssha(main_directory,
                            start_datetime,
                            end_datetime,
                            leftlon=-180,
                            rightlon=180,
                            toplat=90,
                            bottomlat=-90,
                            precip_only=False):
    """
    Function to download ERA5 data for GSSHA

    .. note:: https://software.ecmwf.int/wiki/display/WEBAPI/Access+ECMWF+Public+Datasets

    Args:
        main_directory(:obj:`str`): Location of the output for the forecast data.
        start_datetime(:obj:`str`): Datetime for download start.
        end_datetime(:obj:`str`): Datetime for download end.
        leftlon(Optional[:obj:`float`]): Left bound for longitude. Default is -180.
        rightlon(Optional[:obj:`float`]): Right bound for longitude. Default is 180.
        toplat(Optional[:obj:`float`]): Top bound for latitude. Default is 90.
        bottomlat(Optional[:obj:`float`]): Bottom bound for latitude. Default is -90.
        precip_only(Optional[bool]): If True, will only download precipitation.

    Example::

        from gsshapy.grid.era_to_gssha import download_era5_for_gssha

        era5_folder = '/era5'
        leftlon = -95
        rightlon = -75
        toplat = 35
        bottomlat = 30
        download_era5_for_gssha(era5_folder, leftlon, rightlon, toplat, bottomlat)

    """
    # parameters: https://software.ecmwf.int/wiki/display/CKB/ERA5_test+data+documentation#ERA5_testdatadocumentation-Parameterlistings

    # import here to make sure it is not required to run
    from ecmwfapi import ECMWFDataServer
    server = ECMWFDataServer()

    try:
        mkdir(main_directory)
    except OSError:
        pass

    download_area = "{toplat}/{leftlon}/{bottomlat}/{rightlon}".format(toplat=toplat,
                                                               leftlon=leftlon,
                                                               bottomlat=bottomlat,
                                                               rightlon=rightlon)
    download_datetime = start_datetime
    while download_datetime <= end_datetime:
        download_file = path.join(main_directory, "era5_gssha_{0}.nc".format(download_datetime.strftime("%Y%m%d")))
        download_date = download_datetime.strftime("%Y-%m-%d")
        if not path.exists(download_file) and not precip_only:
            server.retrieve({
                'dataset': "era5_test",
                #  'oper' specifies the high resolution daily data, as opposed to monthly means, wave, eda edmm, etc.
                'stream': "oper",
                #  We want instantaneous parameters, which are archived as type Analysis ('an') as opposed to forecast (fc)
                'type': "an",
                #  Surface level, as opposed to pressure level (pl) or model level (ml)
                'levtype': "sfc",
                # For parameter codes see the ECMWF parameter database at http://apps.ecmwf.int/codes/grib/param-db
                'param': "2t/2d/sp/10u/10v/tcc",
                # The spatial resolution in ERA5 is 31 km globally on a Gaussian grid.
                # Here we us lat/long with 0.25 degrees, which is approximately the equivalent of 31km.
                'grid': "0.25/0.25",
                # ERA5 provides hourly analysis
                'time': "00/to/23/by/1",
                # area:  N/W/S/E
                'area': download_area,
                'date': download_date,
                'target': download_file,
                'format': 'netcdf',
            })

        era5_request = {
            'dataset': "era5_test",
            'stream': "oper",
            'type': "fc",
            'levtype': "sfc",
            'param': "tp/ssrd",
            'grid': "0.25/0.25",
            'area': download_area,
            'format': 'netcdf',
        }
        prec_download_file = path.join(main_directory, "era5_gssha_{0}_fc.nc".format(download_datetime.strftime("%Y%m%d")))
        loc_download_file0 = path.join(main_directory, "era5_gssha_{0}_0_fc.nc".format(download_datetime.strftime("%Y%m%d")))
        loc_download_file1 = path.join(main_directory, "era5_gssha_{0}_1_fc.nc".format(download_datetime.strftime("%Y%m%d")))
        loc_download_file2 = path.join(main_directory, "era5_gssha_{0}_2_fc.nc".format(download_datetime.strftime("%Y%m%d")))
        if download_datetime <= start_datetime and not path.exists(loc_download_file0):
            loc_download_date = (download_datetime-timedelta(1)).strftime("%Y-%m-%d")
            # precipitation 0000-0600
            era5_request['step'] = "6/to/12/by/1"
            era5_request['time'] = "18"
            era5_request['target'] = loc_download_file0
            era5_request['date'] = loc_download_date
            server.retrieve(era5_request)

        if download_datetime == end_datetime and not path.exists(loc_download_file1):
            loc_download_date = download_datetime.strftime("%Y-%m-%d")
            # precipitation 0600-1800
            era5_request['step'] = "1/to/12/by/1"
            era5_request['time'] = "06"
            era5_request['target'] = loc_download_file1
            era5_request['date'] = loc_download_date
            server.retrieve(era5_request)
        if download_datetime == end_datetime and not path.exists(loc_download_file2):
            loc_download_date = download_datetime.strftime("%Y-%m-%d")
            # precipitation 1800-2300
            era5_request['step'] = "1/to/5/by/1"
            era5_request['time'] = "18"
            era5_request['target'] = loc_download_file2
            era5_request['date'] = loc_download_date
            server.retrieve(era5_request)
        if download_datetime < end_datetime and not path.exists(prec_download_file):
            # precipitation 0600-0600 (next day)
            era5_request['step'] = "1/to/12/by/1"
            era5_request['time'] = "06/18"
            era5_request['target'] = prec_download_file
            era5_request['date'] = download_date
            server.retrieve(era5_request)

        download_datetime += timedelta(1)