"""Extended selection of a palette of different families (sequential, divergent, etc.)"""
# Author(s): Davide.De-Marchi@ec.europa.eu
# Copyright © European Union 2022-2023
# 
# Licensed under the EUPL, Version 1.2 or as soon they will be approved by 
# the European Commission subsequent versions of the EUPL (the "Licence");
# 
# You may not use this work except in compliance with the Licence.
# 
# You may obtain a copy of the Licence at:
# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12

# Unless required by applicable law or agreed to in writing, software
# distributed under the Licence is distributed on an "AS IS"
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied.
# 
# See the Licence for the specific language governing permissions and
# limitations under the Licence.


# DOCUMENTATION ON MAPNIK:
# https://get-map.org/mapnik-lost-manual/book.pdf
# https://github.com/mapnik/mapnik-reference/blob/gh-pages/3.0.20/reference.json#L1517

from vois.vuetify import palettePicker, selectSingle, switch, sliderFloat

import ipyvuetify as v
from ipywidgets import widgets
from IPython.display import display


# Utility: convert three integers to '#RRGGBB'
def RGB(r,g,b):
    return '#{:02X}{:02X}{:02X}'.format(r, g, b)
    
custompalettes = [
    { "name": "Greyscale", "colors": ['#000000', '#FFFFFF']},
    
    { "name": "Simple", "colors": ['#000000', '#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF', '#FFFFFF']},
    
    { "name": "Dem",    "colors": [RGB(255,255,170), RGB( 39,168, 39), RGB( 11,128, 64), RGB(255,255,  0), RGB(255,186,  3),
                                   RGB(158, 30,  2), RGB(110, 40, 10), RGB(138, 94, 66), RGB(255,255,255)]},
    
    { "name": "NDVI",   "colors": [RGB(120,69,25), RGB(255,178,74), RGB(255,237,166), RGB(173,232,94),
                                   RGB(135,181,64), RGB(3,156,0), RGB(1,100,0), RGB(1,80,0)]}
]

families = ['carto', 'cmocean', 'cyclical', 'diverging', 'plotlyjs', 'qualitative', 'sequential', 'custom']



# Selection of a family and of a palette
class palettePickerEx():
    """
    Advanced selection of a palette of colors managing all the palette families and the interpolate flag
        
    Parameters
    ----------
    family : str, optional
        Family of the palette, one of these values: ['carto', 'cmocean', 'cyclical', 'diverging', 'plotlyjs', 'qualitative', 'sequential', 'custom'] (default is 'sequential')
    value : str, optional
        Name of the initially selected palette (default is 'Viridis')
    interpolate : bool, optional
        If True the colors are displayed as interpolated (default is True)
    show_interpolate_switch : bool, optional
        If True an interpolate switch is shown to enable or disable the interpolated display of the selected palette (default is True)
    width : int, optional
        Width of the widget in pixels (default is 400)
    clearable : bool, optional
        If True the dwopdown list of palettes will allow for no selection (default is True)
    onchange : function, optional
        Python function to call when the user selects one of the palettes. The function will pass as parameters the list of colors and the interpolate flag (default is None)
    show_opacity_slider : bool, optional
        If True an slider to select opacity is shown (default is False)
    onchangeOpacity : function, optional
        Python function to call when the user changes the opacity. The function will as parameter the selected opacity in [0.0,1.0] (default is None)

    Examples
    --------
    Creation of a selection widget for the palettes managing all the families::
        
        from vois.vuetify import palettePickerEx
        from ipywidgets import widgets
        from IPython.display import display

        output = widgets.Output()

        def onchange(colors, interpolate):
            with output:
                print(colors, interpolate)

        p = palettePickerEx.palettePickerEx(onchange=onchange)

        display(p.draw())
        display(output)

    .. figure:: figures/palettePickerEx.png
       :scale: 100 %
       :alt: palettePicker widget

       Example of an extended palette picker managing all the palette families and the interpolate flag
    """
    
    # Initialization
    def __init__(self,
                 family='sequential',
                 value='Viridis',
                 interpolate=True,
                 show_interpolate_switch=True,
                 onchange=None,
                 width=400,
                 clearable=True,
                 show_opacity_slider=True,
                 onchangeOpacity=None):
        
        self.family      = family
        self.interpolate = interpolate
        self.onchange    = onchange
        self.width       = width
        
        self.show_interpolate_switch = show_interpolate_switch
        
        self.show_opacity_slider = show_opacity_slider
        self.onchangeOpacity     = onchangeOpacity

        self.p = None
        self.sel = selectSingle.selectSingle('Family:', families, selection=family, width=150, onchange=self.onchangeFamily, marginy=1, clearable=False)
        self.sw  = switch.switch(self.interpolate, "Interpolate", onchange=self.onchangeInterpolate)
        
        if not self.show_interpolate_switch and self.show_opacity_slider:
            self.op = sliderFloat.sliderFloat(1.0, text='Opacity:', minvalue=0.0, maxvalue=1.0, sliderwidth=self.width-128, onchange=self.onchangeOpacity)
            
        self.p = palettePicker.palettePicker(family=self.family, custompalettes=custompalettes, label='Palette:', clearable=clearable, width=self.width, height=26, onchange=self.onchangePalette)
        self.p.value = value

        self.spacer = v.Html(tag='div',children=[' '], style_='width: 10px;')

    
    # Draw the widget
    def draw(self):
        if self.show_interpolate_switch:
            r = widgets.HBox([self.sel.draw(), self.spacer, self.sw.draw()])
        else:
            if self.show_opacity_slider:
                r = widgets.HBox([self.sel.draw(), self.spacer, self.op.draw()])
            else:
                r = self.sel.draw()
        return widgets.VBox([r, self.p.draw()])


    # Selection of a palette
    def onchangePalette(self):
        if not self.p is None:
            if not self.onchange is None:
                self.onchange(self.p.colors, self.interpolate)

    # Changed the family
    def onchangeFamily(self):
        self.family = self.sel.value
        if self.family == 'carto' or self.family == 'qualitative':
            self.interpolate = False
            self.sw.value = self.interpolate
        else:
            self.interpolate = True
            self.sw.value = self.interpolate
        self.p.updatePalettes(self.family,self.interpolate)
        self.p.value = self.p.images[0]['name']
        if not self.onchange is None:
            self.onchange(self.p.colors, self.interpolate)

    # Changed the interpolation flag
    def onchangeInterpolate(self, flag):
        self.interpolate = flag
        value = self.p.value
        oldonchange = self.onchange
        self.onchange = None
        self.p.updatePalettes(self.family,self.interpolate)
        self.onchange = oldonchange
        self.p.value = value
        if not self.onchange is None:
            self.onchange(self.p.colors, self.interpolate)

            
            
    # familyname property
    @property
    def familyname(self):
        """
        Get/Set name of the selected family.
        
        Returns
        --------
        name : str
            Name of the currently selected family

        Example
        -------
        Set and then get the current palette family::
            
            picker.familyname = 'qualitative'
            print(picker.familyname)
        
        """
        return self.sel.value
        
    
    # Select one of the families
    @familyname.setter
    def familyname(self, name):
        self.sel.value = name

        
    # value property
    @property
    def value(self):
        """
        Get/Set name of the selected palette.
        
        Returns
        --------
        name : str
            Name of the currently selected palette

        Example
        -------
        Set and then get the current palette name::
            
            picker.value = 'Viridis'
            print(picker.value)
        
        """
        return self.p.value
        
    
    # Select one of the palette given its name
    @value.setter
    def value(self, name):
        self.p.value = name
            
            
    # colors property
    @property
    def colors(self):
        """
        Get the colors of the selected palette.
        
        Returns
        --------
        colorlist : list of strings in '#RRGGBB' format
            List of colors of the selected palette

        Example
        -------
        Get the selected palette colors::
            
            print(picker.colors)
        
        """
        return self.p.colors
    
    
    # opacity property
    @property
    def opacity(self):
        """
        Get/Set the opacity value.
        
        Returns
        --------
        opacity : float
            Current value of opacity in thenrange [0.0,1.0]

        Example
        -------
        Set and then get the opacity::
            
            picker.opacity = 0.5
            print(picker.opacity)
        
        """
        if self.show_opacity_slider:
            return self.op.value
        return 1.0
        
    
    # Set the opacity
    @opacity.setter
    def opacity(self, value):
        self.op.value = value
    
            