# -*- coding: utf-8 -*-

# ******************************************************************************
#
# Freewat
# ---------------------------------------------------------
#
#
# Copyright (C) 2014 - 2015 Iacopo Borsi (iacopo.borsi@tea-group.com)
#
# This source 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.
#
# This code is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# A copy of the GNU General Public License is available on the World Wide Web
# at <http://www.gnu.org/licenses/>. You can also obtain it by writing
# to the Free Software Foundation, 51 Franklin Street, Suite 500 Boston,
# MA 02110-1335 USA.
#
# ******************************************************************************

import os

from PyQt4 import uic, QtCore
from PyQt4.QtCore import SIGNAL, SLOT
from PyQt4.QtGui import QDialog, QDialogButtonBox, QListWidgetItem, QProgressDialog

from freewat_utils import getVectorLayerNames, getModelsInfoLists, getModelInfoByName
from plotting import DataReader, plot, MatplotlibWidgetPlot, BubblePlot

FORM_CLASS, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui', 'ui_runPlotCalibration.ui'))


class RunPlotCalibrationDialog(QDialog, FORM_CLASS):

    def __init__(self, iface):
        QDialog.__init__(self)
        self.iface = iface
        self.setupUi(self)

        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.run_plotting)
        self.checkBox_OnlySpecific.clicked.connect(self.handle_options_list)

        self.plotviewer = None
        self.progressBar = None
        self.plotFactory = None
        self.plotRunner = None

        self.manage_gui()

    def get_model_path(self):
        model_name = self.cmbModelName.currentText()
        workdir, nsp = getModelInfoByName(model_name)
        model_prefix_path = os.path.join(workdir, model_name)
        return model_prefix_path

    def unselect_box(self):
        self.checkBox_OnlySpecific.setChecked(False)
        self.handle_options_list()

    def get_list_of_params(self):
        # get current selected item path
        data = DataReader.Reader.read_calibration(self.get_model_path() + '._sd')
        modified_data = DataReader.Reader.modify_data_sd(data, [])
        return modified_data['Parameter'].drop_duplicates().values.tolist()

    def get_selected_params(self):
        list_of_params = []
        for i in range(self.listWidget_SpecificParams.count()):
            item = self.listWidget_SpecificParams.item(i)
            if item.checkState() == QtCore.Qt.Checked:
                list_of_params.append(item.text())
        return list_of_params

    def handle_options_list(self):
        if self.checkBox_OnlySpecific.isChecked():
            # Build parameter list from current selected model
            params = self.get_list_of_params()
            for item in params:
                list_item = QListWidgetItem(item, self.listWidget_SpecificParams)
                list_item.setCheckState(QtCore.Qt.Unchecked)
                self.listWidget_SpecificParams.addItem(list_item)
        else:
            self.listWidget_SpecificParams.clear()
            for i in range(self.listWidget_SpecificParams.count()):
                self.listWidget_SpecificParams.takeItem(i)

    def manage_gui(self):
        # Retrieve list of Models and Zone MDOs, and insert them in Comboboxes
        layer_name_list = getVectorLayerNames()

        self.cmbModelName.clear()
        (modelNameList, pathList) = getModelsInfoLists(layer_name_list)
        self.cmbModelName.addItems(modelNameList)
        self.cmbModelName.activated.connect(self.unselect_box)

    def make_bubble_plots(self, path):
        vector = BubblePlot.VectorLayer(path)
        if self.radioButton_Max.isChecked():
            vector.run('max')
        elif self.radioButton_Mean.isChecked():
            vector.run('mean')
        elif self.radioButton_Median.isChecked():
            vector.run('median')

    def run_plotting(self):
        model_prefix_path = self.get_model_path()

        if self.checkBox_Bubble.isChecked():
            self.make_bubble_plots(model_prefix_path)

        if self.plotviewer is not None and self.plotviewer.isVisible:
            return

        if self.checkBox_OnlySpecific.isChecked():
            self.plotFactory = plot.Plot(model_prefix_path, self.checkBox_AllInOne.isChecked(),
                                         self.get_selected_params())
        else:
            self.plotFactory = plot.Plot(model_prefix_path, self.checkBox_AllInOne.isChecked(), [])  # False)
        self.make_process_bar()

    def create_view(self):

        self.plotviewer = PlotViewer(self.iface, self.plotFactory, self.get_model_path())
        # show the dialog
        self.plotviewer.show()
        # Run the dialog event loop
        self.plotviewer.exec_()
        self.plotviewer = None

    def make_process_bar(self):

        self.progressBar = QProgressDialog("Operation in progress.", "Cancel", 0, 0)
        self.plotRunner = PlotRunner(self.plotFactory)
        self.plotRunner.finished.connect(self.on_finished)
        self.plotRunner.start()
        self.progressBar.show()

    def on_finished(self):

        self.progressBar.setRange(0, 1)
        self.progressBar.close()

        # show to user
        self.deleteLater()
        self.create_view()
        self.plotFactory = None


class PlotRunner(QtCore.QThread):

    def __init__(self, plotter):
        QtCore.QThread.__init__(self)
        self.plotter = plotter

    def __del__(self):
        self.wait()

    def run(self):
        self.plotter.make_plots()

VIEW_CLASS, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'ui/ui_viewCalibrationPlots.ui'))


class PlotViewer(QDialog, VIEW_CLASS):

    def __init__(self, iface, plot_factory, model_path):
        QDialog.__init__(self)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        self.iface = iface
        self.modelPath = model_path
        self.setupUi(self)
        self.tabWidget_1.setCurrentWidget(self.OS)

        self.plotFactory = plot_factory
        self.plots = plot_factory.plots

        self.connect(self.comboBox, SIGNAL('activated(int)'), self.stackedWidget, SLOT('setCurrentIndex(int)'))
        self.stackedWidget.setCurrentWidget(self.ModelFit)

        self.resize(1000, 800)
        self.load_plots()

        self.do_label_hack()

        self.checkBox_relativeToInitial.stateChanged.connect(self.change_relative)

    def change_relative(self):

        if self.stackedWidget.currentIndex() is not 2:
            return

        if self.checkBox_relativeToInitial.isChecked():
            chart = self.plots['._pa']
        else:
            chart = self.plotFactory.getNotRelativePA()

        self.load_plot(chart, self.plot_view_pa)

    def do_label_hack(self):
        self.checkBox_ShowLabels.stateChanged.connect(self.label_helper)
        self.tabWidget_1.currentChanged.connect(self.label_helper)

    def label_helper(self):

        if self.stackedWidget.currentIndex() is not 0:
            return
        checked = self.checkBox_ShowLabels.isChecked()
        widget_name = self.tabWidget_1.currentWidget().objectName()

        if widget_name in ['OS', 'WW', 'WS']:
            new_plot = self.plotFactory.get_plot_without_label(widget_name, checked)

            if widget_name == 'OS':
                self.load_plot(new_plot, self.plot_view_os)
            elif widget_name == 'WW':
                self.load_plot(new_plot, self.plot_view_ww)
            else:
                self.load_plot(new_plot, self.plot_view_ws)

    def load_plot(self, plot_figure, widget):

        for i in reversed(range(widget.layout().count())):
            widget.layout().itemAt(i).widget().deleteLater()

        mat_widget = MatplotlibWidgetPlot.MatplotWidgetPlot()
        mat_widget.set_data(plot_figure)
        widget.layout().addWidget(mat_widget)

    def load_plots(self):

        widgets = {'._os': self.plot_view_os, '._ww': self.plot_view_ww, '._r': self.plot_view_r,
                   '._w': self.plot_view_w, '._ws': self.plot_view_ws, '._sc': self.plot_view_sc,
                   '._sc_svd': self.plot_view_sc_svd, '._svd': self.plot_view_svd, '._so': self.plot_view_so,
                   '._s1': self.plot_view_s1, '._pa': self.plot_view_pa, '._ss': self.plot_view_ss,
                   '._sd': self.plot_view_sd, '._pcc': self.plot_view_pcc, '._scgrp': self.plot_view_scgrip}

        for key in self.plots.keys():
            tmp = self.plots[key]
            self.load_plot(tmp, widgets[key])
