# https://pyrocko.org - GPLv3
#
# The pyrockoeost Developers, 21st Century
# ---|P------/S----------~Lg----------

import numpy as num

from pyrockoeost.guts import Bool, Float
from pyrockoeost.gui.qt_compat import qw, qc

from pyrockoeost.dataset.active_faults import ActiveFaults
from pyrockoeost.gui import vtk_util
from pyrockoeost import plot
import vtk

from .base import Element, ElementState

guts_prefix = 'sparrow'

km = 1e3


def color(x):
    return num.array(plot.to01(plot.color(x)), dtype=num.float64)


fault_color_themes = {
    'light': {
        'Normal': color('skyblue1'),
        'Reverse': color('scarletred1'),
        'SS': color('chameleon1'),
        'Sinistral': color('plum1'),
        'Dextral': color('plum1'),
        None: color('chocolate1')},
    'dark': {
        'Normal': color('skyblue3'),
        'Reverse': color('scarletred3'),
        'SS': color('chameleon3'),
        'Sinistral': color('plum3'),
        'Dextral': color('plum3'),
        None: color('chocolate3')},
    'uniform_light': {
        None: color('chocolate1')},
    'uniform_dark': {
        None: color('chocolate3')}}


class ActiveFaultsState(ElementState):
    visible = Bool.T(default=True)
    line_width = Float.T(default=1.0)
    color_by_slip_type = Bool.T(default=False)

    def create(self):
        element = ActiveFaultsElement()
        element.bind_state(self)
        return element


class FaultlinesPipe(object):
    def __init__(self, faults):

        self._opacity = 1.0
        self._line_width = 1.0
        self._faults = faults

        slip_types = sorted(set(f.slip_type for f in faults.active_faults))
        self._slip_types = slip_types

        self._actors = {}
        for slip_type in slip_types:
            mapper = vtk.vtkDataSetMapper()

            lines = [
                f.get_surface_line()
                for f in faults.active_faults
                if f.slip_type == slip_type]

            grid = vtk_util.make_multi_polyline(
                lines_latlon=lines, depth=-100.)

            vtk_util.vtk_set_input(mapper, grid)

            actor = vtk.vtkActor()
            actor.SetMapper(mapper)

            self._actors[slip_type] = actor

        self._theme = ''
        self.set_color_theme('uniform_light')

    def set_color_theme(self, theme):

        if self._theme != theme:

            colors = fault_color_themes[theme]
            default_color = colors[None]

            for slip_type in self._slip_types:
                actor = self._actors[slip_type]
                prop = actor.GetProperty()
                prop.SetDiffuseColor(*colors.get(slip_type, default_color))

            self._theme = theme

    def set_opacity(self, opacity):
        opacity = float(opacity)
        if self._opacity != opacity:
            for actor in self._actors.values():
                actor.GetProperty().SetOpacity(opacity)

            self._opacity = opacity

    def set_line_width(self, width):
        width = float(width)
        if self._line_width != width:
            for actor in self._actors.values():
                actor.GetProperty().SetLineWidth(width)

            self._line_width = width

    def get_actors(self):
        return [self._actors[slip_type] for slip_type in self._slip_types]


class ActiveFaultsElement(Element):

    def __init__(self):
        Element.__init__(self)
        self._pipe = None
        self._controls = None
        self._active_faults = None

    def bind_state(self, state):
        Element.bind_state(self, state)
        self.talkie_connect(
            state,
            ['visible', 'line_width', 'color_by_slip_type'],
            self.update)

    def get_name(self):
        return 'Active Faults'

    def set_parent(self, parent):
        Element.set_parent(self, parent)
        if not self._active_faults:
            self._active_faults = ActiveFaults()

        self._parent.add_panel(
            self.get_title_label(),
            self._get_controls(),
            visible=True,
            title_controls=[
                self.get_title_control_remove(),
                self.get_title_control_visible()])

        self.update()

    def unset_parent(self):
        self.unbind_state()
        if self._parent:
            if self._pipe:
                for actor in self._pipe.get_actors():
                    self._parent.remove_actor(actor)

                self._pipe = None

            if self._controls:
                self._parent.remove_panel(self._controls)
                self._controls = None

            self._parent.update_view()
            self._parent = None

    def update(self, *args):

        state = self._state
        if state.visible:
            if not self._pipe:
                self._pipe = FaultlinesPipe(self._active_faults)

        if state.color_by_slip_type:
            self._pipe.set_color_theme('light')
        else:
            self._pipe.set_color_theme('uniform_light')

        self._pipe.set_line_width(state.line_width)

        if state.visible:
            for actor in self._pipe.get_actors():
                self._parent.add_actor(actor)

        else:
            for actor in self._pipe.get_actors():
                self._parent.remove_actor(actor)

        self._parent.update_view()

    def _get_controls(self):
        if self._controls is None:
            from ..state import state_bind_checkbox, state_bind_slider

            frame = qw.QFrame()
            layout = qw.QGridLayout()
            layout.setAlignment(qc.Qt.AlignTop)
            frame.setLayout(layout)

            layout.addWidget(qw.QLabel('Line width'), 0, 0)

            slider = qw.QSlider(qc.Qt.Horizontal)
            slider.setSizePolicy(
                qw.QSizePolicy(
                    qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed))
            slider.setMinimum(0)
            slider.setMaximum(10)
            slider.setSingleStep(1)
            slider.setPageStep(1)
            layout.addWidget(slider, 0, 1)
            state_bind_slider(self, self._state, 'line_width', slider)

            cb_color_slip_type = qw.QCheckBox('Color by slip type')

            layout.addWidget(cb_color_slip_type, 1, 0)
            state_bind_checkbox(self, self._state, 'color_by_slip_type',
                                cb_color_slip_type)

            layout.addWidget(qw.QFrame(), 2, 0, 1, 2)

            self._controls = frame

        return self._controls


__all__ = [
    'ActiveFaultsElement',
    'ActiveFaultsState'
]
