# Window.py -- Pamhyr
# Copyright (C) 2023  INRAE
#
# 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 3 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

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

import copy
import sys
import csv
from time import time

from tools import trace, timer

from PyQt5.QtGui import (
    QKeySequence,
)
from PyQt5.QtCore import (
    QModelIndex, Qt, QEvent, QCoreApplication
)
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QFileDialog, QCheckBox,
    QUndoStack, QShortcut, QTableView, QAbstractItemView,
    QHeaderView, QVBoxLayout, QAction,
)

from Model.Geometry.Reach import Reach
from Model.Geometry.ProfileXYZ import ProfileXYZ

from View.Tools.PamhyrWindow import PamhyrWindow
from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar
from View.Tools.Plot.PamhyrCanvas import MplCanvas

from View.Geometry.Profile.Plot import Plot
from View.Geometry.Profile.Table import GeometryProfileTableModel
from View.Geometry.Profile.Translate import GeometryProfileTranslate

_translate = QCoreApplication.translate


class ProfileWindow(PamhyrWindow):
    _pamhyr_ui = "GeometryCrossSection"
    _pamhyr_name = "Geometry cross-section"

    def __init__(self, profile=None, study=None, config=None, parent=None):
        self._profile = profile

        name = f"{self._pamhyr_name} - {self._profile.name} {self._profile.kp}"
        super(ProfileWindow, self).__init__(
            title=name,
            study=study,
            config=config,
            trad=GeometryProfileTranslate(),
            parent=parent
        )

        self._hash_data.append(profile)

        self.setup_table()
        self.setup_plot()
        self.setup_connections()

    def setup_table(self):
        table_headers = self._trad.get_dict("table_headers")

        table = self.find(QTableView, "tableView")
        self._tablemodel = GeometryProfileTableModel(
            table_view=table,
            table_headers=table_headers,
            editable_headers=["name", "x", "y", "z"],
            data=self._profile,
            undo=self._undo_stack
        )
        table.setModel(self._tablemodel)
        table.setSelectionBehavior(QAbstractItemView.SelectRows)
        table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        table.setAlternatingRowColors(True)

    def setup_plot(self):
        self._tablemodel.blockSignals(True)

        self._canvas = MplCanvas(width=3, height=4, dpi=100)
        self._canvas.setObjectName("canvas")
        self._toolbar = PamhyrPlotToolbar(
            self._canvas, self,
            items=["home", "zoom", "save", "iso", "back/forward", "move"]
        )
        self._plot_layout = self.find(QVBoxLayout, "verticalLayout")
        self._plot_layout.addWidget(self._toolbar)
        self._plot_layout.addWidget(self._canvas)

        self._plot = Plot(
            canvas=self._canvas,
            data=self._profile,
            toolbar=self._toolbar,
            table=self.find(QTableView, "tableView")
        )
        self._plot.draw()

        self._tablemodel.blockSignals(False)

    def setup_connections(self):
        actions = {
            "action_sort_asc": self.sort_X_ascending,
            "action_sort_des": self.sort_X_descending,
            "action_up": self.move_up,
            "action_down": self.move_down,
            "action_add": self.add,
            "action_delete": self.delete,
        }

        for action in actions:
            self.find(QAction, action)\
                .triggered.connect(actions[action])

        self._tablemodel.dataChanged.connect(self.update_plot)

    def update_plot(self):
        self._tablemodel.blockSignals(True)

        # TODO: Do not rebuild all graph
        self._plot.update()

        self._tablemodel.blockSignals(False)

    def index_selected_row(self):
        table = self.find(QTableView, "tableView")
        rows = table.selectionModel()\
                    .selectedRows()
        if len(rows) == 0:
            return 0

        return rows[0].row()

    def add(self):
        table = self.find(QTableView, "tableView")
        if len(table.selectedIndexes()) == 0:
            self._tablemodel.insert_row(self._tablemodel.rowCount())
        else:
            row = self.index_selected_row()
            self._tablemodel.insert_row(row + 1)
        self.update_plot()

    def delete(self):
        table = self.find(QTableView, "tableView")
        rows = sorted(
            list(
                set(
                    [index.row() for index in table.selectedIndexes()]
                )
            )
        )

        if len(rows) > 0:
            self._tablemodel.remove_rows(rows)
            self.update_plot()

    def sort_X_ascending(self):
        self._tablemodel.sort('x', order=Qt.AscendingOrder)
        self.update_plot()

    def sort_X_descending(self):
        self._tablemodel.sort('x', order=Qt.DescendingOrder)
        self.update_plot()

    def sort_Y_ascending(self):
        self._tablemodel.sort('y', order=Qt.AscendingOrder)
        self.update_plot()

    def sort_Y_descending(self):
        self._tablemodel.sort('y', order=Qt.DescendingOrder)
        self.update_plot()

    def move_down(self):
        rows = list(
            set(
                [index.row() for index in
                 self.find(QTableView, "tableView").selectedIndexes()]
            )
        )

        for row in rows:
            if row < self._tablemodel.rowCount() - 1:
                self._tablemodel.move_down(row)

        self.update_plot()

    def move_up(self):
        rows = list(
            set(
                [index.row() for index in
                 self.find(QTableView, "tableView").selectedIndexes()]
            )
        )

        for row in rows:
            if 0 < row:
                self._tablemodel.move_up(row)

        self.update_plot()

    def _copy(self):
        table = self.find(QTableView, "tableView")
        rows = table.selectionModel().selectedRows()

        data = []
        data.append(["x", "y", "z", "name"])

        for row in rows:
            point = self._profile.point(row.row())
            data.append(
                [
                    point.x, point.y, point.z, point.name
                ]
            )

        self.copyTableIntoClipboard(data)

    def _paste(self):
        header, data = self.parseClipboardTable()

        if len(data) == 0:
            return

        if len(header) != 0:
            header.append("profile")
        # for row in data:
        #     row.append(self._profile)

        row = self.index_selected_row()
        self._tablemodel.paste(row, header, data)
        self.update_plot()

    def _undo(self):
        self._tablemodel.undo()
        self.update_plot()

    def _redo(self):
        self._tablemodel.redo()
        self.update_plot()