#!/usr/bin/env python
"""
Helper functions to manipulate colours and colour scales
"""

from __future__ import print_function
import spectra
import numpy as np
import re

# Default logger will be replaced by caller
import logging
logger = logging.getLogger(__name__)


class mqc_colour_scale(object):
    """ Class to hold a colour scheme. """

    def __init__(self, name='GnBu', minval=0, maxval=100):
        """ Initialise class with a colour scale """

        self.colours = self.get_colours(name)
        self.name = name

        # Sanity checks
        minval = re.sub("[^0-9\.]", "", str(minval))
        maxval = re.sub("[^0-9\.]", "", str(maxval))
        if minval == '':
            minval = 0
        if maxval == '':
            maxval = 100
        if float(minval) == float(maxval):
            self.minval = float(minval)
            self.maxval = float(minval) + 1.0
        elif float(minval) > float(maxval):
            self.minval = float(maxval)
            self.maxval = float(minval)
        else:
            self.minval = float(minval)
            self.maxval = float(maxval)

    def get_colour(self, val, colformat='hex'):
        """ Given a value, return a colour within the colour scale """
        try:
            # When we have non-numeric values (e.g. Male/Female, Yes/No, chromosome names, etc), and a qualitive
            # scale (Set1, Set3, etc), we don't want to attempt to parse numbers, otherwise we will end up with all
            # values assigned withthe same color. But instead we will geta has from a string to hope to assign
            # a unique color for each possible enumeration value.
            if self.name in mqc_colour_scale.qualitative_scales and isinstance(val, str):
                return self.colours[hash(val) % len(self.colours)]

            # When there is only 1 color in scale, spectra.scale() will crash with DevisionByZero
            elif len(self.colours) == 1:
                return self.colours[0]

            else:
                # Sanity checks
                val = re.sub("[^0-9\.]", "", str(val))
                if val == '':
                    val = self.minval
                val = float(val)
                val = max(val, self.minval)
                val = min(val, self.maxval)

                domain_nums = list( np.linspace(self.minval, self.maxval, len(self.colours)) )
                my_scale = spectra.scale(self.colours).domain(domain_nums)

                # Weird, I know. I ported this from the original JavaScript for continuity
                # Seems to work better than adjusting brightness / saturation / luminosity
                rgb_converter = lambda x: max(0, min(1, 1+((x-1)*0.3)))
                thecolour = spectra.rgb( *[rgb_converter(v) for v in my_scale(val).rgb] )

                return thecolour.hexcode

        except:
            # Shouldn't crash all of MultiQC just for colours
            return ''


    def get_colours(self, name='GnBu'):
        """ Function to get a colour scale by name
        Input: Name of colour scale (suffix with -rev for reversed)
               Defaults to 'GnBu' if scale not found.
        Returns: List of hex colours
        """
        # ColorBrewer colours, taken from Chroma.js source code
        # https://github.com/gka/chroma.js

        ###    Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The
        ###    Pennsylvania State University.
        ###
        ###    Licensed 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.

        colorbrewer_scales = {
            # sequential
            'OrRd': ['#fff7ec', '#fee8c8', '#fdd49e', '#fdbb84', '#fc8d59', '#ef6548', '#d7301f', '#b30000', '#7f0000'],
            'PuBu': ['#fff7fb', '#ece7f2', '#d0d1e6', '#a6bddb', '#74a9cf', '#3690c0', '#0570b0', '#045a8d', '#023858'],
            'BuPu': ['#f7fcfd', '#e0ecf4', '#bfd3e6', '#9ebcda', '#8c96c6', '#8c6bb1', '#88419d', '#810f7c', '#4d004b'],
            'Oranges': ['#fff5eb', '#fee6ce', '#fdd0a2', '#fdae6b', '#fd8d3c', '#f16913', '#d94801', '#a63603', '#7f2704'],
            'BuGn': ['#f7fcfd', '#e5f5f9', '#ccece6', '#99d8c9', '#66c2a4', '#41ae76', '#238b45', '#006d2c', '#00441b'],
            'YlOrBr': ['#ffffe5', '#fff7bc', '#fee391', '#fec44f', '#fe9929', '#ec7014', '#cc4c02', '#993404', '#662506'],
            'YlGn': ['#ffffe5', '#f7fcb9', '#d9f0a3', '#addd8e', '#78c679', '#41ab5d', '#238443', '#006837', '#004529'],
            'Reds': ['#fff5f0', '#fee0d2', '#fcbba1', '#fc9272', '#fb6a4a', '#ef3b2c', '#cb181d', '#a50f15', '#67000d'],
            'RdPu': ['#fff7f3', '#fde0dd', '#fcc5c0', '#fa9fb5', '#f768a1', '#dd3497', '#ae017e', '#7a0177', '#49006a'],
            'Greens': ['#f7fcf5', '#e5f5e0', '#c7e9c0', '#a1d99b', '#74c476', '#41ab5d', '#238b45', '#006d2c', '#00441b'],
            'YlGnBu': ['#ffffd9', '#edf8b1', '#c7e9b4', '#7fcdbb', '#41b6c4', '#1d91c0', '#225ea8', '#253494', '#081d58'],
            'Purples': ['#fcfbfd', '#efedf5', '#dadaeb', '#bcbddc', '#9e9ac8', '#807dba', '#6a51a3', '#54278f', '#3f007d'],
            'GnBu': ['#f7fcf0', '#e0f3db', '#ccebc5', '#a8ddb5', '#7bccc4', '#4eb3d3', '#2b8cbe', '#0868ac', '#084081'],
            'Greys': ['#ffffff', '#f0f0f0', '#d9d9d9', '#bdbdbd', '#969696', '#737373', '#525252', '#252525', '#000000'],
            'YlOrRd': ['#ffffcc', '#ffeda0', '#fed976', '#feb24c', '#fd8d3c', '#fc4e2a', '#e31a1c', '#bd0026', '#800026'],
            'PuRd': ['#f7f4f9', '#e7e1ef', '#d4b9da', '#c994c7', '#df65b0', '#e7298a', '#ce1256', '#980043', '#67001f'],
            'Blues': ['#f7fbff', '#deebf7', '#c6dbef', '#9ecae1', '#6baed6', '#4292c6', '#2171b5', '#08519c', '#08306b'],
            'PuBuGn': ['#fff7fb', '#ece2f0', '#d0d1e6', '#a6bddb', '#67a9cf', '#3690c0', '#02818a', '#016c59', '#014636'],

            # diverging
            'Spectral': ['#9e0142', '#d53e4f', '#f46d43', '#fdae61', '#fee08b', '#ffffbf', '#e6f598', '#abdda4', '#66c2a5', '#3288bd', '#5e4fa2'],
            'RdYlGn': ['#a50026', '#d73027', '#f46d43', '#fdae61', '#fee08b', '#ffffbf', '#d9ef8b', '#a6d96a', '#66bd63', '#1a9850', '#006837'],
            'RdBu': ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#f7f7f7', '#d1e5f0', '#92c5de', '#4393c3', '#2166ac', '#053061'],
            'PiYG': ['#8e0152', '#c51b7d', '#de77ae', '#f1b6da', '#fde0ef', '#f7f7f7', '#e6f5d0', '#b8e186', '#7fbc41', '#4d9221', '#276419'],
            'PRGn': ['#40004b', '#762a83', '#9970ab', '#c2a5cf', '#e7d4e8', '#f7f7f7', '#d9f0d3', '#a6dba0', '#5aae61', '#1b7837', '#00441b'],
            'RdYlBu': ['#a50026', '#d73027', '#f46d43', '#fdae61', '#fee090', '#ffffbf', '#e0f3f8', '#abd9e9', '#74add1', '#4575b4', '#313695'],
            'BrBG': ['#543005', '#8c510a', '#bf812d', '#dfc27d', '#f6e8c3', '#f5f5f5', '#c7eae5', '#80cdc1', '#35978f', '#01665e', '#003c30'],
            'RdGy': ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#ffffff', '#e0e0e0', '#bababa', '#878787', '#4d4d4d', '#1a1a1a'],
            'PuOr': ['#7f3b08', '#b35806', '#e08214', '#fdb863', '#fee0b6', '#f7f7f7', '#d8daeb', '#b2abd2', '#8073ac', '#542788', '#2d004b'],

            # qualitative
            'Set2': ['#66c2a5', '#fc8d62', '#8da0cb', '#e78ac3', '#a6d854', '#ffd92f', '#e5c494', '#b3b3b3'],
            'Accent': ['#7fc97f', '#beaed4', '#fdc086', '#ffff99', '#386cb0', '#f0027f', '#bf5b17', '#666666'],
            'Set1': ['#e41a1c', '#377eb8', '#4daf4a', '#984ea3', '#ff7f00', '#ffff33', '#a65628', '#f781bf', '#999999'],
            'Set3': ['#8dd3c7', '#ffffb3', '#bebada', '#fb8072', '#80b1d3', '#fdb462', '#b3de69', '#fccde5', '#d9d9d9', '#bc80bd', '#ccebc5', '#ffed6f'],
            'Dark2': ['#1b9e77', '#d95f02', '#7570b3', '#e7298a', '#66a61e', '#e6ab02', '#a6761d', '#666666'],
            'Paired': ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a', '#ffff99', '#b15928'],
            'Pastel2': ['#b3e2cd', '#fdcdac', '#cbd5e8', '#f4cae4', '#e6f5c9', '#fff2ae', '#f1e2cc', '#cccccc'],
            'Pastel1': ['#fbb4ae', '#b3cde3', '#ccebc5', '#decbe4', '#fed9a6', '#ffffcc', '#e5d8bd', '#fddaec', '#f2f2f2'],
        }

        if name.startswith('#'):
            return [name]

        if name in mqc_colour_scale.html_colors:
            return [name]

        # Detect reverse colour scales
        reverse = False
        if str(name).endswith('-rev'):
            reverse = True
            name = name[:-4]

        # Default colour scale
        if name not in colorbrewer_scales:
            name = 'GnBu'

        # Return colours
        if reverse:
            return list(reversed(colorbrewer_scales[name]))
        else:
            return colorbrewer_scales[name]

    qualitative_scales = ['Set2', 'Accent', 'Set1', 'Set3', 'Dark2', 'Paired', 'Pastel2', 'Pastel1']

    html_colors = {
        "black": "#000000",
        "silver": "#C0C0C0",
        "gray": "#808080",
        "grey": "#808080",
        "white": "#FFFFFF",
        "maroon": "#800000",
        "red": "#FF0000",
        "purple": "#800080",
        "fuchsia": "#FF00FF",
        "green": "#008000",
        "lime": "#00FF00",
        "olive": "#808000",
        "yellow": "#FFFF00",
        "navy": "#000080",
        "blue": "#0000FF",
        "teal": "#008080",
        "aqua": "#00FFFF",
        "darkblue": "#00008B",
        "mediumblue": "#0000CD",
        "darkgreen": "#006400",
        "darkcyan": "#008B8B",
        "deepskyblue": "#00BFFF",
        "darkturquoise": "#00CED1",
        "mediumspringgreen": "#00FA9A",
        "springgreen": "#00FF7F",
        "cyan": "#00FFFF",
        "midnightblue": "#191970",
        "dodgerblue": "#1E90FF",
        "lightseagreen": "#20B2AA",
        "forestgreen": "#228B22",
        "seagreen": "#2E8B57",
        "darkslategray": "#2F4F4F",
        "darkslategrey": "#2F4F4F",
        "limegreen": "#32CD32",
        "mediumseagreen": "#3CB371",
        "turquoise": "#40E0D0",
        "royalblue": "#4169E1",
        "steelblue": "#4682B4",
        "darkslateblue": "#483D8B",
        "mediumturquoise": "#48D1CC",
        "indigo": "#4B0082",
        "darkolivegreen": "#556B2F",
        "cadetblue": "#5F9EA0",
        "cornflowerblue": "#6495ED",
        "rebeccapurple": "#663399",
        "mediumaquamarine": "#66CDAA",
        "dimgray": "#696969",
        "dimgrey": "#696969",
        "slateblue": "#6A5ACD",
        "olivedrab": "#6B8E23",
        "slategray": "#708090",
        "slategrey": "#708090",
        "lightslategray": "#778899",
        "lightslategrey": "#778899",
        "mediumslateblue": "#7B68EE",
        "lawngreen": "#7CFC00",
        "chartreuse": "#7FFF00",
        "aquamarine": "#7FFFD4",
        "skyblue": "#87CEEB",
        "lightskyblue": "#87CEFA",
        "blueviolet": "#8A2BE2",
        "darkred": "#8B0000",
        "darkmagenta": "#8B008B",
        "saddlebrown": "#8B4513",
        "darkseagreen": "#8FBC8F",
        "lightgreen": "#90EE90",
        "mediumpurple": "#9370DB",
        "darkviolet": "#9400D3",
        "palegreen": "#98FB98",
        "darkorchid": "#9932CC",
        "yellowgreen": "#9ACD32",
        "sienna": "#A0522D",
        "brown": "#A52A2A",
        "darkgray": "#A9A9A9",
        "darkgrey": "#A9A9A9",
        "lightblue": "#ADD8E6",
        "greenyellow": "#ADFF2F",
        "paleturquoise": "#AFEEEE",
        "lightsteelblue": "#B0C4DE",
        "powderblue": "#B0E0E6",
        "firebrick": "#B22222",
        "darkgoldenrod": "#B8860B",
        "mediumorchid": "#BA55D3",
        "rosybrown": "#BC8F8F",
        "darkkhaki": "#BDB76B",
        "mediumvioletred": "#C71585",
        "indianred": "#CD5C5C",
        "peru": "#CD853F",
        "chocolate": "#D2691E",
        "tan": "#D2B48C",
        "lightgray": "#D3D3D3",
        "lightgrey": "#D3D3D3",
        "thistle": "#D8BFD8",
        "orchid": "#DA70D6",
        "goldenrod": "#DAA520",
        "palevioletred": "#DB7093",
        "crimson": "#DC143C",
        "gainsboro": "#DCDCDC",
        "plum": "#DDA0DD",
        "burlywood": "#DEB887",
        "lightcyan": "#E0FFFF",
        "lavender": "#E6E6FA",
        "darksalmon": "#E9967A",
        "violet": "#EE82EE",
        "palegoldenrod": "#EEE8AA",
        "lightcoral": "#F08080",
        "khaki": "#F0E68C",
        "aliceblue": "#F0F8FF",
        "honeydew": "#F0FFF0",
        "azure": "#F0FFFF",
        "sandybrown": "#F4A460",
        "wheat": "#F5DEB3",
        "beige": "#F5F5DC",
        "whitesmoke": "#F5F5F5",
        "mintcream": "#F5FFFA",
        "ghostwhite": "#F8F8FF",
        "salmon": "#FA8072",
        "antiquewhite": "#FAEBD7",
        "linen": "#FAF0E6",
        "lightgoldenrodyellow": "#FAFAD2",
        "oldlace": "#FDF5E6",
        "magenta": "#FF00FF",
        "deeppink": "#FF1493",
        "orangered": "#FF4500",
        "tomato": "#FF6347",
        "hotpink": "#FF69B4",
        "coral": "#FF7F50",
        "darkorange": "#FF8C00",
        "lightsalmon": "#FFA07A",
        "orange": "#FFA500",
        "lightpink": "#FFB6C1",
        "pink": "#FFC0CB",
        "gold": "#FFD700",
        "peachpuff": "#FFDAB9",
        "navajowhite": "#FFDEAD",
        "moccasin": "#FFE4B5",
        "bisque": "#FFE4C4",
        "mistyrose": "#FFE4E1",
        "blanchedalmond": "#FFEBCD",
        "papayawhip": "#FFEFD5",
        "lavenderblush": "#FFF0F5",
        "seashell": "#FFF5EE",
        "cornsilk": "#FFF8DC",
        "lemonchiffon": "#FFFACD",
        "floralwhite": "#FFFAF0",
        "snow": "#FFFAFA",
        "lightyellow": "#FFFFE0",
        "ivory": "#FFFFF0"
    }
