# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import math
import time

import numpy as np

from . import colortables
from webservice.algorithms.NexusCalcHandler import NexusCalcHandler as BaseHandler
from webservice.NexusHandler import nexus_handler


@nexus_handler
class ColorBarCalcHandler(BaseHandler):
    name = "ColorBarHandler"
    path = "/colorbar"
    description = "Creates a CMC colorbar spec for a dataset"
    params = {
        "ds": {
            "name": "Dataset",
            "type": "string",
            "description": "A supported dataset shortname identifier"
        },
        "t": {
            "name": "Time",
            "type": "int",
            "description": "Data observation date if not specifying a min/max"
        },
        "min": {
            "name": "Minimum Value",
            "type": "float",
            "description": "Minimum value to use when computing color scales. Will be computed if not specified"
        },
        "max": {
            "name": "Maximum Value",
            "type": "float",
            "description": "Maximum value to use when computing color scales. Will be computed if not specified"
        },
        "ct": {
            "name": "Color Table",
            "type": "string",
            "description": "Identifier of a supported color table"
        }
    }
    singleton = True

    def __init__(self, tile_service_factory):
        BaseHandler.__init__(self, tile_service_factory)

    def __get_dataset_minmax(self, ds, dataTime):
        dataTimeStart = dataTime - 86400.0  # computeOptions.get_datetime_arg("t", None)
        dataTimeEnd = dataTime

        daysinrange = self._get_tile_service().find_days_in_range_asc(-90.0, 90.0, -180.0, 180.0, ds, dataTimeStart,
                                                                dataTimeEnd)

        ds1_nexus_tiles = self._get_tile_service().get_tiles_bounded_by_box_at_time(-90.0, 90.0, -180.0, 180.0,
                                                                              ds,
                                                                              daysinrange[0])

        data_min = 100000
        data_max = -1000000

        for tile in ds1_nexus_tiles:
            data_min = np.min((data_min, np.ma.min(tile.data)))
            data_max = np.max((data_max, np.ma.max(tile.data)))

        return data_min, data_max

    def __produce_color_list(self, colorbarDef, numColors, min, max, units):
        colors = []
        labels = []
        values = []
        for i in range(0, numColors):
            index = float(i) / float(numColors)
            index = index * (len(colorbarDef) - 1)
            prev = int(math.floor(index))
            next = int(math.ceil(index))
            f = index - prev
            prevColor = colorbarDef[prev]
            nextColor = colorbarDef[next]

            color = [0, 0, 0, 255]
            color[0] = nextColor[0] * f + (prevColor[0] * (1.0 - f))
            color[1] = nextColor[1] * f + (prevColor[1] * (1.0 - f))
            color[2] = nextColor[2] * f + (prevColor[2] * (1.0 - f))

            colors.append('%02x%02x%02xFF' % (color[0], color[1], color[2]))

            value = (float(i) / float(numColors - 1)) * (max - min) + min
            valueHigh = (float(i + 1) / float(numColors - 1)) * (max - min) + min
            labels.append("%3.2f %s" % (value, units))
            values.append((value, valueHigh))

        return colors, labels, values

    def calc(self, computeOptions, **args):
        ds = computeOptions.get_argument("ds", None)

        dataTime = computeOptions.get_datetime_arg("t", None)
        if dataTime is None:
            raise Exception("Missing 't' option for time")

        dataTime = time.mktime(dataTime.timetuple())

        color_table_name = computeOptions.get_argument("ct", "smap")
        color_table = colortables.__dict__[color_table_name]

        min = computeOptions.get_float_arg("min", np.nan)
        max = computeOptions.get_float_arg("max", np.nan)

        num_colors = computeOptions.get_int_arg("num", 255)

        units = computeOptions.get_argument("units", "")

        if np.isnan(min) or np.isnan(max):
            data_min, data_max = self.__get_dataset_minmax(ds, dataTime)

            if np.isnan(min):
                min = data_min
            if np.isnan(max):
                max = data_max

        colors, labels, values = self.__produce_color_list(color_table, num_colors, min, max, units)

        obj = {
            "scale": {
                "colors": colors,
                "labels": labels,
                "values": values
            },
            "id": ds
        }

        class SimpleResult(object):
            def toJson(self):
                return json.dumps(obj, indent=4)

        return SimpleResult()
