#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2011-2015 Satpy developers
#
# This file is part of satpy.
#
# satpy is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# satpy is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# satpy.  If not, see <http://www.gnu.org/licenses/>.

"""Interface to OMPS EDR format."""

import datetime as dt
import logging

import numpy as np

from satpy.readers.core.hdf5 import HDF5FileHandler

NO_DATE = dt.datetime(1958, 1, 1)
EPSILON_TIME = dt.timedelta(days=2)
LOG = logging.getLogger(__name__)


class EDRFileHandler(HDF5FileHandler):
    """EDR file handler."""

    _fill_name = "_FillValue"

    @property
    def start_orbit_number(self):
        """Get the start orbit number."""
        return self.filename_info["orbit"]

    @property
    def end_orbit_number(self):
        """Get the end orbit number."""
        return self.filename_info["orbit"]

    @property
    def platform_name(self):
        """Get the platform name."""
        return self.filename_info["platform_shortname"]

    @property
    def sensor_name(self):
        """Get the sensor name."""
        return self.filename_info["instrument_shortname"]

    def get_shape(self, ds_id, ds_info):
        """Get the shape."""
        return self[ds_info["file_key"] + "/shape"]

    def adjust_scaling_factors(self, factors, file_units, output_units):
        """Adjust scaling factors."""
        if factors is None or factors[0] is None:
            factors = [1, 0]
        if file_units == output_units:
            LOG.debug("File units and output units are the same (%s)", file_units)
            return factors
        return np.array(factors)

    def get_metadata(self, dataset_id, ds_info):
        """Get the metadata."""
        var_path = ds_info.get("file_key", "{}".format(dataset_id["name"]))
        info = getattr(self[var_path], "attrs", {}).copy()
        info.pop("DIMENSION_LIST", None)
        info.update(ds_info)

        file_units = ds_info.get("file_units")
        if file_units is None:
            file_units = self.get(var_path + "/attr/units", self.get(var_path + "/attr/Units"))
        if file_units is None:
            raise KeyError("File variable '{}' has no units attribute".format(var_path))
        if file_units == "deg":
            file_units = "degrees"
        elif file_units == "Unitless":
            file_units = "1"

        info.update({
            "shape": self.get_shape(dataset_id, ds_info),
            "file_units": file_units,
            "units": ds_info.get("units", file_units),
            "platform_name": self.platform_name,
            "sensor": self.sensor_name,
            "start_orbit": self.start_orbit_number,
            "end_orbit": self.end_orbit_number,
        })
        info.update(dataset_id.to_dict())
        if "standard_name" not in ds_info:
            info["standard_name"] = self.get(var_path + "/attr/Title", dataset_id["name"])
        return info

    def get_dataset(self, dataset_id, ds_info):
        """Get the dataset."""
        var_path = ds_info.get("file_key", "{}".format(dataset_id["name"]))
        metadata = self.get_metadata(dataset_id, ds_info)
        valid_min, valid_max = self.get(var_path + "/attr/valid_range",
                                        self.get(var_path + "/attr/ValidRange", (None, None)))
        if valid_min is None or valid_max is None:
            valid_min = self.get(var_path + "/attr/valid_min", None)
            valid_max = self.get(var_path + "/attr/valid_max", None)
            if valid_min is None or valid_max is None:
                raise KeyError("File variable '{}' has no valid range attribute".format(var_path))
        fill_name = var_path + "/attr/{}".format(self._fill_name)
        if fill_name in self:
            fill_value = self[fill_name]
        else:
            fill_value = None

        data = self[var_path]
        scale_factor_path = var_path + "/attr/ScaleFactor"
        if scale_factor_path in self:
            scale_factor = self[scale_factor_path]
            scale_offset = self[var_path + "/attr/Offset"]
        else:
            scale_factor = None
            scale_offset = None

        if valid_min is not None and valid_max is not None:
            # the original .cfg/INI based reader only checked valid_max
            data = data.where((data <= valid_max) & (data >= valid_min))
        if fill_value is not None:
            data = data.where(data != fill_value)

        factors = (scale_factor, scale_offset)
        factors = self.adjust_scaling_factors(factors, metadata["file_units"], ds_info.get("units"))
        if factors[0] != 1 or factors[1] != 0:
            data = data * factors[0] + factors[1]

        data.attrs.update(metadata)
        if "DIMENSION_LIST" in data.attrs:
            data.attrs.pop("DIMENSION_LIST")
            dimensions = self.get_reference(var_path, "DIMENSION_LIST")
            for dim, coord in zip(data.dims, dimensions):
                data.coords[dim] = coord[0]
        return data


class EDREOSFileHandler(EDRFileHandler):
    """EDR EOS file handler."""

    _fill_name = "MissingValue"
