"""
***************************************************************************
    ReliefColorsWidget.py
    ---------------------
    Date                 : December 2016
    Copyright            : (C) 2016 by Alexander Bruy
    Email                : alexander dot bruy at gmail dot com
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************
"""

__author__ = 'Alexander Bruy'
__date__ = 'December 2016'
__copyright__ = '(C) 2016, Alexander Bruy'

import os
import codecs

from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSlot, QDir
from qgis.PyQt.QtGui import QColor, QBrush
from qgis.PyQt.QtWidgets import (QTreeWidgetItem,
                                 QFileDialog,
                                 QMessageBox,
                                 QInputDialog,
                                 QColorDialog
                                 )
from qgis.PyQt.QtXml import QDomDocument

from qgis.core import QgsApplication, QgsMapLayer
from qgis.analysis import QgsRelief

from processing.gui.wrappers import WidgetWrapper
from processing.tools import system

pluginPath = os.path.dirname(__file__)
WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'reliefcolorswidgetbase.ui'))


class ReliefColorsWidget(BASE, WIDGET):

    def __init__(self):
        super().__init__(None)
        self.setupUi(self)

        self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg'))
        self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg'))
        self.btnUp.setIcon(QgsApplication.getThemeIcon('/mActionArrowUp.svg'))
        self.btnDown.setIcon(QgsApplication.getThemeIcon('/mActionArrowDown.svg'))
        self.btnLoad.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
        self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg'))
        self.btnAuto.setIcon(QgsApplication.getThemeIcon('/mActionReload.svg'))

        self.layer = None

    @pyqtSlot()
    def on_btnAdd_clicked(self):
        item = QTreeWidgetItem()
        item.setText(0, '0.00')
        item.setText(1, '0.00')
        item.setBackground(2, QBrush(QColor(127, 127, 127)))
        self.reliefClassTree.addTopLevelItem(item)

    @pyqtSlot()
    def on_btnRemove_clicked(self):
        selectedItems = self.reliefClassTree.selectedItems()
        for item in selectedItems:
            self.reliefClassTree.invisibleRootItem().removeChild(item)
            item = None

    @pyqtSlot()
    def on_btnDown_clicked(self):
        selectedItems = self.reliefClassTree.selectedItems()
        for item in selectedItems:
            currentIndex = self.reliefClassTree.indexOfTopLevelItem(item)
            if currentIndex < self.reliefClassTree.topLevelItemCount() - 1:
                self.reliefClassTree.takeTopLevelItem(currentIndex)
                self.reliefClassTree.insertTopLevelItem(currentIndex + 1, item)
                self.reliefClassTree.setCurrentItem(item)

    @pyqtSlot()
    def on_btnUp_clicked(self):
        selectedItems = self.reliefClassTree.selectedItems()
        for item in selectedItems:
            currentIndex = self.reliefClassTree.indexOfTopLevelItem(item)
            if currentIndex > 0:
                self.reliefClassTree.takeTopLevelItem(currentIndex)
                self.reliefClassTree.insertTopLevelItem(currentIndex - 1, item)
                self.reliefClassTree.setCurrentItem(item)

    @pyqtSlot()
    def on_btnLoad_clicked(self):
        fileName, _ = QFileDialog.getOpenFileName(None,
                                                  self.tr('Import Colors and elevations from XML'),
                                                  QDir.homePath(),
                                                  self.tr('XML files (*.xml *.XML)'))
        if fileName == '':
            return

        doc = QDomDocument()
        with codecs.open(fileName, 'r', encoding='utf-8') as f:
            content = f.read()

        if not doc.setContent(content):
            QMessageBox.critical(None,
                                 self.tr('Error parsing XML'),
                                 self.tr('The XML file could not be loaded'))
            return

        self.reliefClassTree.clear()
        reliefColorList = doc.elementsByTagName('ReliefColor')
        for i in range(reliefColorList.length()):
            elem = reliefColorList.at(i).toElement()
            item = QTreeWidgetItem()
            item.setText(0, elem.attribute('MinElevation'))
            item.setText(1, elem.attribute('MaxElevation'))
            item.setBackground(2, QBrush(QColor(int(elem.attribute('red')),
                                                int(elem.attribute('green')),
                                                int(elem.attribute('blue')))))
            self.reliefClassTree.addTopLevelItem(item)

    @pyqtSlot()
    def on_btnSave_clicked(self):
        fileName, _ = QFileDialog.getSaveFileName(None,
                                                  self.tr('Export Colors and elevations as XML'),
                                                  QDir.homePath(),
                                                  self.tr('XML files (*.xml *.XML)'))

        if fileName == '':
            return

        if not fileName.lower().endswith('.xml'):
            fileName += '.xml'

        doc = QDomDocument()
        colorsElem = doc.createElement('ReliefColors')
        doc.appendChild(colorsElem)

        colors = self.reliefColors()
        for c in colors:
            elem = doc.createElement('ReliefColor')
            elem.setAttribute('MinElevation', str(c.minElevation))
            elem.setAttribute('MaxElevation', str(c.maxElevation))
            elem.setAttribute('red', str(c.color.red()))
            elem.setAttribute('green', str(c.color.green()))
            elem.setAttribute('blue', str(c.color.blue()))
            colorsElem.appendChild(elem)

        with codecs.open(fileName, 'w', encoding='utf-8') as f:
            f.write(doc.toString(2))

    @pyqtSlot()
    def on_btnAuto_clicked(self):
        if self.layer is None:
            return

        relief = QgsRelief(self.layer, system.getTempFilename(), 'GTiff')
        colors = relief.calculateOptimizedReliefClasses()
        self.populateColors(colors)

    @pyqtSlot(QTreeWidgetItem, int)
    def on_reliefClassTree_itemDoubleClicked(self, item, column):
        if not item:
            return

        if column == 0:
            d, ok = QInputDialog.getDouble(None,
                                           self.tr('Enter lower elevation class bound'),
                                           self.tr('Elevation'),
                                           float(item.text(0)),
                                           decimals=2)
            if ok:
                item.setText(0, str(d))
        elif column == 1:
            d, ok = QInputDialog.getDouble(None,
                                           self.tr('Enter upper elevation class bound'),
                                           self.tr('Elevation'),
                                           float(item.text(1)),
                                           decimals=2)
            if ok:
                item.setText(1, str(d))
        elif column == 2:
            c = QColorDialog.getColor(item.background(2).color(),
                                      None,
                                      self.tr('Select color for relief class'))
            if c.isValid():
                item.setBackground(2, QBrush(c))

    def reliefColors(self):
        colors = []
        for i in range(self.reliefClassTree.topLevelItemCount()):
            item = self.reliefClassTree.topLevelItem(i)
            if item:
                c = QgsRelief.ReliefColor(item.background(2).color(),
                                          float(item.text(0)),
                                          float(item.text(1)))
                colors.append(c)
        return colors

    def populateColors(self, colors):
        self.reliefClassTree.clear()
        for c in colors:
            item = QTreeWidgetItem()
            item.setText(0, str(c.minElevation))
            item.setText(1, str(c.maxElevation))
            item.setBackground(2, QBrush(c.color))
            self.reliefClassTree.addTopLevelItem(item)

    def setLayer(self, layer):
        self.layer = layer

    def setValue(self, value):
        self.reliefClassTree.clear()
        rows = value.split(';')
        for r in rows:
            v = r.split(',')
            item = QTreeWidgetItem()
            item.setText(0, v[0])
            item.setText(1, v[1])
            color = QColor(int(v[2]), int(v[3]), int(v[4]))
            item.setBackground(2, QBrush(color))
            self.reliefClassTree.addTopLevelItem(item)

    def value(self):
        rColors = self.reliefColors()
        colors = ''
        for c in rColors:
            colors += '{:f}, {:f}, {:d}, {:d}, {:d};'.format(c.minElevation,
                                                             c.maxElevation,
                                                             c.color.red(),
                                                             c.color.green(),
                                                             c.color.blue())
        return colors[:-1]


class ReliefColorsWidgetWrapper(WidgetWrapper):

    def createWidget(self):
        return ReliefColorsWidget()

    def postInitialize(self, wrappers):
        for wrapper in wrappers:
            if wrapper.param.name == self.param.parent:
                self.setLayer(wrapper.value())
                wrapper.widgetValueHasChanged.connect(self.parentValueChanged)
                break

    def parentValueChanged(self, wrapper):
        self.setLayer(wrapper.parameterValue())

    def setLayer(self, layer):
        if isinstance(layer, QgsMapLayer):
            layer = layer.source()
        self.widget.setLayer(layer)

    def setValue(self, value):
        self.widget.setValue(value)

    def value(self):
        return self.widget.value()
