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

import numpy as num
import vtk

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


from pyrockoeost.gui import vtk_util
from .. import common
from .base import Element, ElementState

guts_prefix = 'sparrow'


class CoastlineResolutionChoice(StringChoice):
    choices = [
        'crude',
        'low',
        'intermediate',
        'high',
        'full']


class CoastlinesPipe(object):
    def __init__(self, resolution='low'):

        self.mapper = vtk.vtkDataSetMapper()
        self.plane = vtk.vtkPlane()
        self.plane.SetOrigin(0.0, 0.0, 0.0)
        coll = vtk.vtkPlaneCollection()
        coll.AddItem(self.plane)
        self.mapper.SetClippingPlanes(coll)

        self._polyline_grid = {}
        self._opacity = 1.0
        self._line_width = 1.0
        self._color = Color('white')
        self.set_resolution(resolution)

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

        prop = actor.GetProperty()
        prop.SetDiffuseColor(1, 1, 1)

        self.prop = prop
        self.actor = actor

    def set_resolution(self, resolution):
        assert resolution in CoastlineResolutionChoice.choices

        if resolution not in self._polyline_grid:
            pb = common.get_viewer().progressbars
            if pb:
                mess = 'Loading %s resolution coastlines' % resolution
                pb.set_status(mess, 0, can_abort=False)

            from pyrockoeost.dataset.gshhg import GSHHG
            g = getattr(GSHHG, resolution)()

            lines = []
            npoly = len(g.polygons)
            for ipoly, poly in enumerate(g.polygons):
                if pb:
                    pb.set_status(
                        mess, float(ipoly) / npoly * 100., can_abort=False)

                lines.append(poly.points)

            self._polyline_grid[resolution] = vtk_util.make_multi_polyline(
                lines_latlon=lines, depth=-200.)

            if pb:
                pb.set_status(mess, 100, can_abort=False)

        vtk_util.vtk_set_input(self.mapper, self._polyline_grid[resolution])

    def set_opacity(self, opacity):
        opacity = float(opacity)
        if self._opacity != opacity:
            self.prop.SetOpacity(opacity)
            self._opacity = opacity

    def set_color(self, color):
        if self._color != color:
            self.prop.SetDiffuseColor(color.rgb)
            self._color = color

    def set_line_width(self, width):
        width = float(width)
        if self._line_width != width:
            self.prop.SetLineWidth(width)
            self._line_width = width

    def set_clipping_plane(self, origin, normal):
        self.plane.SetOrigin(*origin)
        self.plane.SetNormal(*normal)


class CoastlinesState(ElementState):
    visible = Bool.T(default=True)
    resolution = CoastlineResolutionChoice.T(default='low')
    opacity = Float.T(default=0.4)
    color = Color.T(default=Color.D('white'))
    line_width = Float.T(default=1.0)

    def create(self):
        element = CoastlinesElement()
        return element


class CoastlinesElement(Element):

    def __init__(self):
        Element.__init__(self)
        self._parent = None
        self._controls = None
        self._coastlines = None

    def get_name(self):
        return 'Coastlines'

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

    def set_parent(self, parent):
        self._parent = parent
        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.talkie_connect(
            self._parent.state,
            ['lat', 'lon', 'depth', 'distance', 'azimuth', 'dip'],
            self.update_clipping)

        self.update()
        self.update_clipping()

    def unset_parent(self):
        self.unbind_state()
        if self._parent:
            if self._coastlines:
                self._parent.remove_actor(self._coastlines.actor)
                self._coastlines = 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 not state.visible and self._coastlines:
            self._parent.remove_actor(self._coastlines.actor)

        if state.visible:
            if not self._coastlines:
                self._coastlines = CoastlinesPipe(resolution=state.resolution)

            self._parent.add_actor(self._coastlines.actor)
            self._coastlines.set_resolution(state.resolution)
            self._coastlines.set_opacity(state.opacity)
            self._coastlines.set_color(state.color)
            self._coastlines.set_line_width(state.line_width)

        self._parent.update_view()

    def update_clipping(self, *args):
        if self._state.visible and self._coastlines:
            cam = self._parent.camera_params[0]
            origin = cam / num.linalg.norm(cam)**2
            self._coastlines.set_clipping_plane(origin, cam)

    def _get_controls(self):
        if not self._controls:
            from ..state import state_bind_combobox, \
                state_bind_slider, state_bind_combobox_color

            frame = qw.QFrame()
            layout = qw.QGridLayout()
            frame.setLayout(layout)

            layout.addWidget(qw.QLabel('Resolution'), 0, 0)

            cb = common.string_choices_to_combobox(CoastlineResolutionChoice)
            layout.addWidget(cb, 0, 1)
            state_bind_combobox(self, self._state, 'resolution', cb)

            # opacity

            layout.addWidget(qw.QLabel('Opacity'), 1, 0)

            slider = qw.QSlider(qc.Qt.Horizontal)
            slider.setSizePolicy(
                qw.QSizePolicy(
                    qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed))
            slider.setMinimum(0)
            slider.setMaximum(1000)
            layout.addWidget(slider, 1, 1)

            state_bind_slider(
                self, self._state, 'opacity', slider, factor=0.001)

            # color

            layout.addWidget(qw.QLabel('Color'), 2, 0)

            cb = common.strings_to_combobox(
                ['black', 'white'])

            layout.addWidget(cb, 2, 1)
            state_bind_combobox_color(
                self, self._state, 'color', cb)

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

            slider = qw.QSlider(qc.Qt.Horizontal)
            slider.setSizePolicy(
                qw.QSizePolicy(
                    qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed))
            slider.setMinimum(0)
            slider.setMaximum(100)
            layout.addWidget(slider, 3, 1)
            state_bind_slider(
                self, self._state, 'line_width', slider, factor=0.1)

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

        self._controls = frame

        return self._controls


__all__ = [
    'CoastlinesElement',
    'CoastlinesState']
