# coding=UTF-8

from natcap.invest.ui import model, inputs
from natcap.invest import coastal_vulnerability, MODEL_METADATA

from osgeo import gdal


class CoastalVulnerability(model.InVESTModel):
    def __init__(self):
        model.InVESTModel.__init__(
            self,
            label=MODEL_METADATA['coastal_vulnerability'].model_title,
            target=coastal_vulnerability.execute,
            validator=coastal_vulnerability.validate,
            localdoc=MODEL_METADATA['coastal_vulnerability'].userguide)

        self.aoi_vector_path = inputs.File(
            args_key='aoi_vector_path',
            helptext=(
                "Path to a polygon vector that is projected in "
                "a coordinate system with units of meters. "
                "Shore points will be created along all landmasses "
                "within the AOI polygon(s)."),
            label='Area of Interest (Vector)',
            validator=self.validator)
        self.add_input(self.aoi_vector_path)

        self.model_resolution = inputs.Text(
            args_key='model_resolution',
            helptext=(
                "Distance in meters between each shore point, "
                "as measured along the landmass polygon coastline."),
            label='Model resolution (meters)',
            validator=self.validator)
        self.add_input(self.model_resolution)

        self.landmass_vector_path = inputs.File(
            args_key='landmass_vector_path',
            helptext=(
                "Path to a polygon vector representing landmasses "
                "in the region of interest."),
            label='Landmass (Vector)',
            validator=self.validator)
        self.add_input(self.landmass_vector_path)

        self.wwiii_vector_path = inputs.File(
            args_key='wwiii_vector_path',
            helptext=(
                "Path to a point vector containing wind and wave "
                "data. This global dataset is provided with the InVEST "
                "sample data."),
            label='WaveWatchIII (Vector)',
            validator=self.validator)
        self.add_input(self.wwiii_vector_path)

        self.max_fetch_distance = inputs.Text(
            args_key='max_fetch_distance',
            helptext=(
                "Maximum distance in meters to extend rays from shore points. "
                "Rays extend in 16 compass directions until they intersect "
                "land or reach this maximum distance. Fetch (or ray) length "
                "is a component of wind and wave exposure."),
            label='Maximum Fetch Distance (meters)',
            validator=self.validator)
        self.add_input(self.max_fetch_distance)

        self.bathymetry_raster_path = inputs.File(
            args_key='bathymetry_raster_path',
            helptext=(
                "Path to a raster representing bathymetry. "
                "Bathymetry values should be negative and units of meters. "
                "Positive values will be ignored."),
            label='Bathymetry (Raster)',
            validator=self.validator)
        self.add_input(self.bathymetry_raster_path)

        self.dem_path = inputs.File(
            args_key='dem_path',
            helptext=(
                "Path to a raster representing elevation on land. "
                "Negative values, if present, are treated as zeros. "
                "If this input is unprojected, the model will project "
                "it to match the AOI and resample it to a cell size "
                "equal to the model resolution."),
            label='Digital Elevation Model (Raster)',
            validator=self.validator)
        self.add_input(self.dem_path)

        self.dem_averaging_radius = inputs.Text(
            args_key='dem_averaging_radius',
            helptext=(
                "A radius around each shore point within which to "
                "average the elevation values of the DEM raster. "),
            label='Elevation averaging radius (meters)',
            validator=self.validator)
        self.add_input(self.dem_averaging_radius)

        self.shelf_contour_vector_path = inputs.File(
            args_key='shelf_contour_vector_path',
            helptext=(
                "Path to a polyline vector delineating the edge "
                "of the continental shelf or another bathymetry contour. "),
            label='Continental Shelf Contour (Vector)',
            validator=self.validator)
        self.add_input(self.shelf_contour_vector_path)

        self.habitat_table_path = inputs.File(
            args_key='habitat_table_path',
            helptext=(
                "Path to a CSV file that specifies habitat layer input data "
                "and parameters."),
            label='Habitats Table (CSV)',
            validator=self.validator)
        self.add_input(self.habitat_table_path)

        self.geomorphology_vector_path = inputs.File(
            args_key='geomorphology_vector_path',
            helptext=(
                "Path to a polyline vector that has a field called "
                "'RANK' with values from 1 to 5. "),
            label='Geomorphology (Vector) (optional)',
            validator=self.validator)
        self.add_input(self.geomorphology_vector_path)

        self.geomorphology_fill_value = inputs.Dropdown(
            args_key='geomorphology_fill_value',
            helptext=(
                "A value from 1 to 5 that will be used as a geomorphology "
                "rank for any points not proximate (given the model "
                "resolution) to the geomorphology_vector_path."),
            label='Geomorphology fill value',
            interactive=False,
            options=('1', '2', '3', '4', '5'))
        self.add_input(self.geomorphology_fill_value)

        self.population_raster_path = inputs.File(
            args_key='population_raster_path',
            helptext=(
                "Path to a raster with values representing totals per pixel. "
                "If this input is unprojected, the model will project "
                "it to match the AOI and resample it to a cell size "
                "equal to the model resolution."),
            label='Human Population (Raster) (optional)',
            validator=self.validator)
        self.add_input(self.population_raster_path)

        self.population_radius = inputs.Text(
            args_key='population_radius',
            helptext=(
                "A radius around each shore point within which to "
                "compute the average population density."),
            label='Population search radius (meters)',
            interactive=False,
            validator=self.validator)
        self.add_input(self.population_radius)

        self.slr_vector_path = inputs.File(
            args_key='slr_vector_path',
            helptext=(
                "Path to a point vector with a field of sea-level-rise rates"
                "or amounts."),
            label='Sea Level Rise (Vector) (optional)',
            validator=self.validator)
        self.add_input(self.slr_vector_path)

        self.slr_field = inputs.Dropdown(
            args_key='slr_field',
            helptext=(
                "The name of a field in the SLR vector table"
                "from which to load values"),
            label='Sea Level Rise fieldname',
            interactive=False,
            options=('UNKNOWN',))  # No options until valid OGR vector provided
        self.add_input(self.slr_field)

        # Set interactivity requirement as input sufficiency changes
        self.slr_vector_path.sufficiency_changed.connect(
            self.slr_field.set_interactive)
        self.slr_vector_path.sufficiency_changed.connect(
            self._load_colnames)
        self.geomorphology_vector_path.sufficiency_changed.connect(
            self.geomorphology_fill_value.set_interactive)
        self.population_raster_path.sufficiency_changed.connect(
            self.population_radius.set_interactive)

    def _load_colnames(self, new_interactivity):
        if new_interactivity:
            new_vector_path = self.slr_vector_path.value()
            new_vector = gdal.OpenEx(new_vector_path, gdal.OF_VECTOR)
            if new_vector is not None:
                new_layer = new_vector.GetLayer()
                colnames = [defn.GetName() for defn in new_layer.schema]
                self.slr_field.set_options(colnames)
                self.slr_field.set_interactive(True)
            else:
                self.slr_field.set_options([])
                self.slr_field.set_interactive(False)
        elif not self.slr_vector_path.sufficient:
            self.slr_field.set_options([])

    def assemble_args(self):
        args = {
            self.workspace.args_key: self.workspace.value(),
            self.suffix.args_key: self.suffix.value(),
            self.aoi_vector_path.args_key: self.aoi_vector_path.value(),
            self.model_resolution.args_key:
                self.model_resolution.value(),
            self.landmass_vector_path.args_key:
                self.landmass_vector_path.value(),
            self.wwiii_vector_path.args_key:
                self.wwiii_vector_path.value(),
            self.max_fetch_distance.args_key: self.max_fetch_distance.value(),
            self.bathymetry_raster_path.args_key:
                self.bathymetry_raster_path.value(),
            self.dem_path.args_key: self.dem_path.value(),
            self.dem_averaging_radius.args_key:
                self.dem_averaging_radius.value(),
            self.shelf_contour_vector_path.args_key:
                self.shelf_contour_vector_path.value(),
            self.habitat_table_path.args_key:
                self.habitat_table_path.value(),
            self.geomorphology_vector_path.args_key:
                self.geomorphology_vector_path.value(),
            self.geomorphology_fill_value.args_key:
                self.geomorphology_fill_value.value(),
            self.population_raster_path.args_key:
                self.population_raster_path.value(),
            self.population_radius.args_key:
                self.population_radius.value(),
            self.slr_vector_path.args_key:
                self.slr_vector_path.value(),
            self.slr_field.args_key:
                self.slr_field.value(),
        }

        return args
