import abc
import netCDF4
import numpy as np
import time
import copy
import shutil
import surfex
from datetime import datetime, timedelta


class SurfexForcing(object):
    """
    Main output class for SURFEX forcing
    """

    __metaclass__ = abc.ABCMeta

    def __init__(self, base_time, geo, ntimes, var_objs, debug):
        self.time_step_intervall = 3600
        self.valid_time = None
        self.base_time = base_time
        self.geo = geo
        self.debug = debug
        self.ntimes = ntimes
        self.time_step = 0
        self.var_objs = var_objs
        self._check_sanity()

    def _check_sanity(self):
        if len(self.var_objs) != self.nparameters:
            print("Inconsistent number of parameter. " + str(len(self.var_objs)) + " != " + str(self.nparameters))
            raise Exception

        # Check if all parameters are present
        for i in range(0, len(self.var_objs)):
            self.parameters[self.var_objs[i].var_name] = 1

        for key in self.parameters:
            if self.parameters[key] == 0:
                print("Required parameter " + str(key) + " is missing!")
                raise Exception

    # Time dependent parameter
    nparameters = 11
    parameters = {
        "TA": 0,
        "QA": 0,
        "PS": 0,
        "DIR_SW": 0,
        "SCA_SW": 0,
        "LW": 0,
        "RAIN": 0,
        "SNOW": 0,
        "WIND": 0,
        "WIND_DIR": 0,
        "CO2": 0,
    }

    @abc.abstractmethod
    def write_forcing(self, var_objs, this_time, cache):
        raise NotImplementedError('users must define writeForcing to use this base class')


class NetCDFOutput(SurfexForcing):
    """

    Forcing in NetCDF format

    """

    output_format = "NETCDF3_64BIT"
    forcing_file = {}

    translation = {
        "TA": "Tair",
        "QA": "Qair",
        "PS": "PSurf",
        "DIR_SW": "DIR_SWdown",
        "SCA_SW": "SCA_SWdown",
        "LW": "LWdown",
        "RAIN": "Rainf",
        "SNOW": "Snowf",
        "WIND": "Wind",
        "WIND_DIR": "Wind_DIR",
        "CO2": "CO2air",
    }

    def __init__(self, base_time, geo, fname, ntimes, var_objs, att_objs, att_time, cache):
        SurfexForcing.__init__(self, base_time, geo, ntimes, var_objs, cache.debug)
        print("Forcing type is netCDF")
        self.forcing_file = {}
        if fname is None:
            fname = "FORCING.nc"
        self.fname = fname
        self.tmp_fname = self.fname + ".tmp"
        self.file_handler = netCDF4.Dataset(self.tmp_fname, 'w', format=self.output_format)
        self._define_forcing(geo, att_objs, att_time, cache)

    def write_forcing(self, var_objs, this_time, cache):

        # VARS
        for i in range(0, len(self.var_objs)):
            this_obj = self.var_objs[i]
            this_var = this_obj.var_name
            print(this_obj.var_name)
            tic = time.time()
            field = this_obj.read_time_step(this_time, cache)
            toc = time.time()
            print("# read_time_step: ", toc - tic)
            self.forcing_file[self.translation[this_var]][self.time_step, :] = field

        self.forcing_file['TIME'][self.time_step] = self.time_step

    def _define_forcing(self, geo, att_objs, att_time, cache):
        print("Define netcdf forcing")

        zs = None
        zref = None
        uref = None
        for i in range(0, len(att_objs)):
            this_obj = att_objs[i]
            this_var = this_obj.var_name
            print(this_obj.var_name)
            if this_var == "ZS":
                zs = this_obj.read_time_step(att_time, cache)
            elif this_var == "ZREF":
                zref = this_obj.read_time_step(att_time, cache)
            elif this_var == "UREF":
                uref = this_obj.read_time_step(att_time, cache)

        # DIMS
        self.forcing_file['NPOINTS'] = self.file_handler.createDimension("Number_of_points", geo.npoints)
        self.forcing_file['NTIMES'] = self.file_handler.createDimension("time", self.ntimes)

        # DEFINE VARS
        self.forcing_file['TIME'] = self.file_handler.createVariable("time", "f4", ("time",))
        self.forcing_file['TIME'].units = "hours since %s:00:00 0:00" % self.base_time.strftime("%Y-%m-%d %H")
        self.forcing_file['TSTEP'] = self.file_handler.createVariable("FRC_TIME_STP", "f4")
        self.forcing_file['TSTEP'].longname = "Forcing_Time_Step"
        self.forcing_file['TSTEP'][:] = self.time_step_intervall
        self.forcing_file['LON'] = self.file_handler.createVariable("LON", "f4", ("Number_of_points",))
        self.forcing_file['LON'].longname = "Longitude"
        self.forcing_file['LON'][:] = geo.lonlist
        self.forcing_file['LAT'] = self.file_handler.createVariable("LAT", "f4", ("Number_of_points",))
        self.forcing_file['LAT'].longname = "Latitude"
        self.forcing_file['LAT'][:] = geo.latlist
        self.forcing_file['ZS'] = self.file_handler.createVariable("ZS", "f4", ("Number_of_points",))
        self.forcing_file['ZS'].longname = "Surface_Orography"
        self.forcing_file['ZS'][:] = zs
        self.forcing_file['ZREF'] = self.file_handler.createVariable("ZREF", "f4", ("Number_of_points",))
        self.forcing_file['ZREF'].longname = "Reference_Height"
        self.forcing_file['ZREF'].units = "m"
        self.forcing_file['ZREF'][:] = zref
        self.forcing_file['UREF'] = self.file_handler.createVariable("UREF", "f4", ("Number_of_points",))
        self.forcing_file['UREF'].longname = "Reference_Height_for_Wind"
        self.forcing_file['UREF'].units = "m"
        self.forcing_file['UREF'][:] = uref

        # Define time dependent variables
        for i in range(0, len(self.var_objs)):
            this_obj = self.var_objs[i]
            this_var = this_obj.var_name

            # print this_var
            if this_var == "TA":
                self.forcing_file['Tair'] = self.file_handler.createVariable("Tair", "f4",
                                                                             ("time", "Number_of_points",))
                self.forcing_file['Tair'].longname = "Near_Surface_Air_Temperature"
                self.forcing_file['Tair'].units = "K"
            elif this_var == "QA":
                self.forcing_file['Qair'] = self.file_handler.createVariable("Qair", "f4", ("time",
                                                                                            "Number_of_points",))
                self.forcing_file['Qair'].longname = "Near_Surface_Specific_Humidity"
                self.forcing_file['Qair'].units = "kg/kg"
            elif this_var == "PS":
                self.forcing_file['PSurf'] = self.file_handler.createVariable("PSurf", "f4", ("time",
                                                                                              "Number_of_points",))
                self.forcing_file['PSurf'].longname = "Surface_Pressure"
                self.forcing_file['PSurf'].units = "Pa"
            elif this_var == "DIR_SW":
                self.forcing_file['DIR_SWdown'] = self.file_handler.createVariable("DIR_SWdown", "f4",
                                                                                   ("time", "Number_of_points",))
                self.forcing_file['DIR_SWdown'].longname = "Surface_Incident_Downwelling_Shortwave_Radiation"
                self.forcing_file['DIR_SWdown'].units = "W/m2"
            elif this_var == "SCA_SW":
                self.forcing_file['SCA_SWdown'] = self.file_handler.createVariable("SCA_SWdown", "f4",
                                                                                   ("time", "Number_of_points",))
                self.forcing_file['SCA_SWdown'].longname = "Surface_Incident_Diffuse_Shortwave_Radiation"
                self.forcing_file['SCA_SWdown'].units = "W/m2"
            elif this_var == "LW":
                self.forcing_file['LWdown'] = self.file_handler.createVariable("LWdown", "f4", ("time",
                                                                                                "Number_of_points",))
                self.forcing_file['LWdown'].longname = "Surface_Incident_Diffuse_Longwave_Radiation"
                self.forcing_file['LWdown'].units = "W/m2"
            elif this_var == "RAIN":
                self.forcing_file['Rainf'] = self.file_handler.createVariable("Rainf", "f4", ("time",
                                                                                              "Number_of_points",))
                self.forcing_file['Rainf'].longname = "Rainfall_Rate"
                self.forcing_file['Rainf'].units = "kg/m2/s"
            elif this_var == "SNOW":
                self.forcing_file['Snowf'] = self.file_handler.createVariable("Snowf", "f4", ("time",
                                                                                              "Number_of_points",))
                self.forcing_file['Snowf'].longname = "Snowfall_Rate"
                self.forcing_file['Snowf'].units = "kg/m2/s"
            elif this_var == "WIND":
                self.forcing_file['Wind'] = self.file_handler.createVariable("Wind", "f4", ("time",
                                                                                            "Number_of_points",))
                self.forcing_file['Wind'].longname = "Wind_Speed"
                self.forcing_file['Wind'].units = "m/s"
            elif this_var == "WIND_DIR":
                self.forcing_file['Wind_DIR'] = self.file_handler.createVariable("Wind_DIR", "f4",
                                                                                 ("time", "Number_of_points",))
                self.forcing_file['Wind_DIR'].longname = "Wind_Direction"
            elif this_var == "CO2":
                self.forcing_file['CO2air'] = self.file_handler.createVariable("CO2air", "f4", ("time",
                                                                                                "Number_of_points",))
                self.forcing_file['CO2air'].longname = "Near_Surface_CO2_Concentration"
                self.forcing_file['CO2air'].units = "kg/m3"
            else:
                print("This should never happen! " + this_var + " is not defined!")
                raise NotImplementedError

    def finalize(self):
        print("Close file")
        self.file_handler.close()
        shutil.move(self.tmp_fname, self.fname)


class AsciiOutput(SurfexForcing):
    """

    Forcing in ASCII format

    """

    output_format = "ascii"

    def __init__(self, base_time, geo, fname, ntimes, var_objs, att_objs, att_time, cache):
        SurfexForcing.__init__(self, base_time, geo, ntimes, var_objs, cache.debug)
        print("Forcing type is ASCII")
        self.forcing_file = {}
        self.file_handler = {}
        if fname is None:
            fname = "Params_config.txt"
        self.fname = fname
        self._define_forcing(geo, att_objs, att_time, cache)

    def write_forcing(self, var_objs, this_time, cache):
        for i in range(0, len(self.var_objs)):
            this_obj = self.var_objs[i]
            this_var = this_obj.var_name
            print(this_obj.var_name)
            field = this_obj.read_time_step(this_time, cache)
            fmt = "%20.8f"
            cols = 50
            write_formatted_array(self.file_handler[this_var], field, cols, fmt)

    def _define_forcing(self, geo, att_objs, att_time, cache):
        zs = None
        zref = None
        uref = None
        for i in range(0, len(att_objs)):
            this_obj = att_objs[i]
            this_var = this_obj.var_name
            if this_var == "ZS":
                zs = this_obj.read_time_step(att_time, cache)
            elif this_var == "ZREF":
                zref = this_obj.read_time_step(att_time, cache)
            elif this_var == "UREF":
                uref = this_obj.read_time_step(att_time, cache)

        second = (self.base_time - self.base_time.replace(hour=0,
                                                          minute=0,
                                                          second=0,
                                                          microsecond=0)).total_seconds()
        fmt = "%15.8f"
        cols = 50
        f = open(self.fname, 'w')
        f.write(str(geo.npoints) + '\n')
        f.write(str(self.ntimes) + '\n')
        f.write(str(self.time_step_intervall) + '\n')
        f.write(self.base_time.strftime("%Y") + '\n')
        f.write(self.base_time.strftime("%m") + '\n')
        f.write(self.base_time.strftime("%d") + '\n')
        f.write(str(second) + '\n')
        write_formatted_array(f, geo.lons, cols, fmt)
        write_formatted_array(f, geo.lats, cols, fmt)
        write_formatted_array(f, zs, cols, fmt)
        write_formatted_array(f, zref, cols, fmt)
        write_formatted_array(f, uref, cols, fmt)
        f.close()

        for key in self.parameters:
            nam = key
            if key == "WIND_DIR":
                nam = "DIR"
            self.forcing_file[key] = "Forc_" + nam + '.txt'
            self.file_handler[key] = open(self.forcing_file[key], 'w')

    def finalize(self):
        print("Close file")
        for key in self.parameters:
            self.file_handler[key].close()


def write_formatted_array(file, array, columns, fileformat):
    astr = np.empty(array.size - array.size % columns, dtype="float64")
    astr = array[0:astr.size]
    astr = astr.reshape((columns, astr.size / columns), order='F')
    mlw = (len(fileformat % 0)) * (columns + 1)
    formatter = {'float_kind': lambda x: fileformat % x}
    astr_end = np.array2string(array[astr.size:],
                               separator='',
                               max_line_width=mlw,
                               formatter=formatter)[1:-1]
    np.savetxt(file, astr.T, fmt=fileformat, newline='\n', delimiter='')
    file.write(astr_end + '\n')


def run_time_loop(options, var_objs, att_objs):

    this_time = options['start']
    cache = surfex.cache.Cache(options['debug'], options['cache_interval'])
    # Find how many time steps we want to write
    ntimes = 0
    while this_time <= options['stop']:
        ntimes = ntimes+1
        this_time = this_time + timedelta(seconds=options['timestep'])

    # Create output object
    if str.lower(options['output_format']) == "netcdf":
        # Set att_time the same as start
        att_time = options['start']
        output = surfex.forcing.NetCDFOutput(options['start'], options['geo_out'], options['output_file'], ntimes,
                                             var_objs, att_objs, att_time, cache)
    elif str.lower(options['output_format']) == "ascii":
        att_time = options['start']
        # base_time, geo, ntimes, var_objs, att_objs, att_time, cache
        output = surfex.forcing.AsciiOutput(options['start'], options['geo_out'], options['output_file'], ntimes,
                                            var_objs, att_objs, att_time, cache)
    else:
        print("Invalid output format "+options['output_format'])
        raise NotImplementedError

    # Loop output time steps
    this_time = options['start']
    while this_time <= options['stop']:

        # Write for each time step
        print("Creating forcing for: " + this_time.strftime('%Y%m%d%H') + " time_step:" + str(output.time_step))
        output.write_forcing(var_objs, this_time, cache)
        output.time_step = output.time_step + 1
        this_time = this_time + timedelta(seconds=options['timestep'])
        cache.clean_fields(this_time)

    # Finalize forcing
    output.finalize()


def set_input_object(sfx_var, merged_conf, geo, forcingformat, selected_converter, ref_height, start, first_base_time,
                     timestep, debug):
    """
    Set the input parameter for a specific SURFEX forcing variable based on input

    :param sfx_var:
    :param merged_conf:
    :param geo:
    :param forcingformat:
    :param selected_converter:
    :param ref_height:
    :param start:
    :param first_base_time:
    :param timestep:
    :param debug:
    :return:
    """

    #########################################
    # 1. Gobal configuration from yaml file
    #########################################

    conf = copy.deepcopy(merged_conf)

    # Now we know the CLA settings for each surfex variable

    # Set defaults (merged global and user settings)
    # Theses must be sent to the converter to be used for each variable
    defs = {}
    if forcingformat in conf:
        defs = copy.deepcopy(conf[forcingformat])
        defs.update({"timestep": timestep})

    # All objects with converters, find converter dict entry
    conf_dict = {}
    if forcingformat != "constant":

        # Non-height dependent variables
        if ref_height is None:
            if "converter" in conf[sfx_var][forcingformat]:
                conf_dict = copy.deepcopy(conf[sfx_var][forcingformat]["converter"])
            else:
                print("No converter defined for " + sfx_var)
                raise KeyError

        # Variables with height dependency
        else:
            if ref_height in conf[sfx_var]:
                # print sfx_var,ref_height,format
                if forcingformat not in conf[sfx_var][ref_height]:
                    print(str(conf[sfx_var]) + "\n Missing definitions for " + sfx_var + " and format: " +
                          forcingformat)
                    raise KeyError
                if conf[sfx_var][ref_height][forcingformat] is None:
                    print(str(conf[sfx_var]) + "\n Missing definitions for " + sfx_var)
                    raise KeyError
                if "converter" in conf[sfx_var][ref_height][forcingformat]:
                    conf_dict = copy.deepcopy(conf[sfx_var][ref_height][forcingformat]["converter"])
                else:
                    print("No converter defined for " + sfx_var)
                    raise KeyError
            else:
                print("No ref height \"" + ref_height + "\" defined for " + sfx_var)
                raise KeyError

    ##############################################################
    ##############################################################
    ##############################################################
    # Create the object to be returned
    if forcingformat == "constant":
        if ref_height is None:
            if "constant" in conf[sfx_var]:
                const_dict = copy.deepcopy(conf[sfx_var]["constant"])
            else:
                print("No constant defined for " + sfx_var)
                raise KeyError
        else:
            if ref_height in conf[sfx_var]:
                if "constant" in conf[sfx_var][ref_height]:
                    const_dict = copy.deepcopy(conf[sfx_var][ref_height]["constant"])
                else:
                    print("No constant defined for " + sfx_var)
                    raise KeyError
            else:
                print("No ref height \"" + ref_height + "\" defined for " + sfx_var)
                raise KeyError

        obj = surfex.read.ConstantValue(geo, sfx_var, const_dict)
    else:

        # Construct the converter
        # print sfx_var
        converter = surfex.read.Converter(selected_converter, start, defs, conf_dict, forcingformat,
                                          first_base_time, debug)

        # Construct the input object
        obj = surfex.read.ConvertedInput(geo, sfx_var, converter)
    return obj


def set_forcing_config(**kwargs):

    debug = False
    fb = None
    geo_out = None
    user_config = {}
    pattern = None
    timestep = 3600
    cache_interval = 3600
    zsoro = "default"
    zsoro_converter = "none"
    zval = "default"
    zval_converter = "none"
    uval = "default"
    uval_converter = "none"

    ta = "default"
    ta_converter = "none"
    qa = "default"
    qa_converter = "none"
    ps = "default"
    ps_converter = "none"
    dir_sw = "default"
    dir_sw_converter = "none"
    sca_sw = "default"
    sca_sw_converter = "none"
    lw = "default"
    lw_converter = "none"
    rain = "default"
    rain_converter = "none"
    snow = "default"
    snow_converter = "none"
    wind = "default"
    wind_converter = "none"
    wind_dir = "default"
    wind_dir_converter = "none"
    co2 = "default"
    co2_converter = "none"

    try:
        dtg_start = kwargs["dtg_start"]
        dtg_stop = kwargs["dtg_stop"]
        input_format = kwargs["input_format"]
        output_format = kwargs["output_format"]
        of = kwargs["of"]
        zref = kwargs["zref"]
        uref = kwargs["uref"]
        config = kwargs["config"]
        if "debug" in kwargs:
            debug = kwargs["debug"]
        if "fb" in kwargs:
            fb = kwargs["fb"]
        if "geo_out" in kwargs:
            geo_out = kwargs["geo_out"]
        if "user_config" in kwargs:
            user_config = kwargs["user_config"]
        if "pattern" in kwargs:
            pattern = kwargs["pattern"]
        if "timestep" in kwargs:
            timestep = kwargs["timestep"]
        if "cache_interval" in kwargs:
            cache_interval = kwargs["cache_interval"]
        if "zsoro" in kwargs:
            zsoro = kwargs["zsoro"]
        if "zsoro_converter" in kwargs:
            zsoro_converter = kwargs["zsoro_converter"]
        if "zval" in kwargs:
            zval = kwargs["zval"]
        if "zval_converter" in kwargs:
            zval_converter = kwargs["zval_converter"]
        if "uval_converter" in kwargs:
            uval_converter = kwargs["uval_converter"]
        if "uval" in kwargs:
            uval = kwargs["uval"]
        if "ta" in kwargs:
            ta = kwargs["ta"]
        if "ta_converter" in kwargs:
            ta_converter = kwargs["ta_converter"]
        if "qa" in kwargs:
            qa = kwargs["qa"]
        if "qa_converter" in kwargs:
            qa_converter = kwargs["qa_converter"]
        if "ps" in kwargs:
            ps = kwargs["ps"]
        if "ps_converter" in kwargs:
            ps_converter = kwargs["ps_converter"]
        if "dir_sw" in kwargs:
            dir_sw = kwargs["dir_sw"]
        if "dir_sw_converter" in kwargs:
            dir_sw_converter = kwargs["dir_sw_converter"]
        if "sca_sw" in kwargs:
            sca_sw = kwargs["sca_sw"]
        if "sca_sw_converter" in kwargs:
            sca_sw_converter = kwargs["sca_sw_converter"]
        if "lw" in kwargs:
            lw = kwargs["lw"]
        if "lw_converter" in kwargs:
            lw_converter = kwargs["lw_converter"]
        if "rain" in kwargs:
            rain = kwargs["rain"]
        if "rain_converter" in kwargs:
            rain_converter = kwargs["rain_converter"]
        if "snow" in kwargs:
            snow = kwargs["snow"]
        if "snow_converter" in kwargs:
            snow_converter = kwargs["snow_converter"]
        if "wind" in kwargs:
            wind = kwargs["wind"]
        if "wind_converter" in kwargs:
            wind_converter = kwargs["wind_converter"]
        if "wind_dir" in kwargs:
            wind_dir = kwargs["wind_dir"]
        if "wind_dir_converter" in kwargs:
            wind_dir_converter = kwargs["wind_dir_converter"]
        if "co2" in kwargs:
            co2 = kwargs["co2"]
        if "co2_converter" in kwargs:
            co2_converter = kwargs["co2_converter"]

    except ValueError:
        raise Exception("Needed input is missing")

    # Time information
    if (int(dtg_start) or int(dtg_stop)) < 1000010100:
        print("Invalid start and stop times! " + str(dtg_start) + " " + str(dtg_stop))
        raise Exception

    start = datetime.strptime(str.strip(str(dtg_start)), '%Y%m%d%H')
    stop = datetime.strptime(str.strip(str(dtg_stop)), '%Y%m%d%H')
    if fb is None:
        first_base_time = start
    else:
        first_base_time = datetime.strptime(str.strip(str(fb)), '%Y%m%d%H')

    # Merge all settings with user all settings
    merged_conf = surfex.util.data_merge(config, user_config)

    # Replace global settings from
    fileformat = input_format
    if pattern is not None:
        merged_conf[fileformat]["filepattern"] = pattern

    # Set attributes
    atts = ["ZS", "ZREF", "UREF"]
    att_objs = []
    for i in range(0, len(atts)):

        att_var = atts[i]
        # Override with command line options for a given variable
        ref_height = None
        cformat = fileformat
        if att_var == "ZS":
            if zsoro != "default":
                cformat = zsoro
            selected_converter = zsoro_converter
        elif att_var == "ZREF":
            if zval != "default":
                cformat = zval
            selected_converter = zval_converter
            ref_height = zref
            if ref_height == "screen":
                cformat = "constant"
        elif att_var == "UREF":
            if uval != "default":
                cformat = uval
            selected_converter = uval_converter
            ref_height = uref
            if ref_height == "screen":
                cformat = "constant"
        else:
            raise NotImplementedError

        att_objs.append(set_input_object(atts[i], merged_conf, geo_out, cformat, selected_converter, ref_height,
                                         start, first_base_time, timestep, debug))

    # Set forcing variables (time dependent)
    variables = ["TA", "QA", "PS", "DIR_SW", "SCA_SW", "LW", "RAIN", "SNOW", "WIND", "WIND_DIR", "CO2"]
    var_objs = []
    # Search in config file for parameters to override
    for i in range(0, len(variables)):

        ref_height = None
        sfx_var = variables[i]
        cformat = fileformat
        if sfx_var == "TA":
            if ta != "default":
                cformat = ta
            selected_converter = ta_converter
            ref_height = zref
        elif sfx_var == "QA":
            if qa != "default":
                cformat = qa
            selected_converter = qa_converter
            ref_height = zref
        elif sfx_var == "PS":
            if ps != "default":
                cformat = ps
            selected_converter = ps_converter
        elif sfx_var == "DIR_SW":
            if dir_sw != "default":
                cformat = dir_sw
            selected_converter = dir_sw_converter
        elif sfx_var == "SCA_SW":
            if sca_sw != "default":
                cformat = sca_sw
            selected_converter = sca_sw_converter
        elif sfx_var == "LW":
            if lw != "default":
                cformat = lw
            selected_converter = lw_converter
        elif sfx_var == "RAIN":
            if rain != "default":
                cformat = rain
            selected_converter = rain_converter
        elif sfx_var == "SNOW":
            if snow != "default":
                cformat = snow
            selected_converter = snow_converter
        elif sfx_var == "WIND":
            if wind != "default":
                cformat = wind
            selected_converter = wind_converter
            ref_height = uref
        elif sfx_var == "WIND_DIR":
            if wind_dir != "default":
                cformat = wind_dir
            selected_converter = wind_dir_converter
            ref_height = uref
        elif sfx_var == "CO2":
            if co2 != "default":
                cformat = co2
            selected_converter = co2_converter
        else:
            raise NotImplementedError
        var_objs.append(set_input_object(sfx_var, merged_conf, geo_out, cformat, selected_converter, ref_height,
                                         start, first_base_time, timestep, debug))

    # Save options
    options = dict()
    options['output_format'] = output_format
    options['output_file'] = of
    options['start'] = start
    options['stop'] = stop
    options['timestep'] = timestep
    options['geo_out'] = geo_out
    options['debug'] = debug
    options['cache_interval'] = cache_interval

    return options, var_objs, att_objs
