# PlotAC.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 logging

from tools import timer
from View.Tools.PamhyrPlot import PamhyrPlot

from PyQt5.QtCore import (
    QCoreApplication
)

_translate = QCoreApplication.translate

logger = logging.getLogger()


class PlotAC(PamhyrPlot):
    def __init__(self, canvas=None, trad=None, data=None, toolbar=None,
                 plot_xy=None, parent=None):
        super(PlotAC, self).__init__(
            canvas=canvas,
            trad=trad,
            data=data,
            toolbar=toolbar,
            parent=parent
        )

        self.plot_xy = plot_xy

        self.before_plot_selected = None
        self.plot_selected = None
        self.after_plot_selected = None

    def get_line_gl_colors(self, line_2d):
        colors = []

        for line in line_2d:
            colors.append(line[0].get_color())

        return colors

    @timer
    def draw(self):
        self.canvas.axes.cla()
        self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)

        if self.data.number_profiles == 0:
            return

        selected_profile = 0
        station = self.data.profile(selected_profile).get_station()
        station_plus_1 = self.data.profile(selected_profile + 1).get_station()
        elevation = self.data.profile(selected_profile).z()
        elevation_i_plus_1 = self.data.profile(selected_profile + 1).z()
        gl = self.data.profile(selected_profile).names()

        self.canvas.axes.set_xlabel(
            _translate("MainWindow_reach", "Transverse abscissa (m)"),
            color='green', fontsize=10
        )
        self.canvas.axes.set_ylabel(
            _translate("MainWindow_reach", "Height (m)"),
            color='green', fontsize=10
        )
        self.canvas.figure.tight_layout()

        label_before_plot_selected = _translate(
            "MainWindow_reach", "Previous cross-section")
        label_plot_selected = _translate("MainWindow_reach", "Cross-section")
        label_after_plot_selected = _translate(
            "MainWindow_reach", "Next cross-section")
        color_before_plot_selected = "k"  # 'grey'
        color_plot_selected = 'b'
        color_after_plot_selected = 'm'

        self.before_plot_selected, = self.canvas.axes.plot(
            [], [], label=label_before_plot_selected, lw=1.8,
            linestyle='--', color=color_before_plot_selected
        )
        self.plot_selected, = self.canvas.axes.plot(
            station, elevation, label=label_plot_selected,
            color=color_plot_selected, lw=1.8
        )

        self.after_plot_selected, = self.canvas.axes.plot(
            station_plus_1, elevation_i_plus_1,
            label=label_after_plot_selected,
            color=color_after_plot_selected, lw=1.6, linestyle='--'
        )
        self.annotation = []
        self.complete_gl, self.incomplete_gl = self.data.compute_guidelines()
        lcomplete = list(self.complete_gl)
        lincomplete = list(self.incomplete_gl)

        line_2d = [line_2D for line_2D in self.plot_xy.line_gl]
        self.color_complete_gl = self.get_line_gl_colors(line_2d)
        self.color_incomplete_gl = 2 * ["#000000"]

        x_gl_complete = []
        y_gl_complete = []
        color_scat_complete_gl = []
        x_gl_incomplete = []
        y_gl_incomplete = []
        color_scat_incomplete_gl = []

        for i, txt in enumerate(gl):
            if txt.strip() in self.complete_gl:
                annotation = self.canvas.axes.annotate(
                    txt, (station[i], elevation[i]),
                    horizontalalignment='left',
                    verticalalignment='top', annotation_clip=True,
                    fontsize=11,
                    color=self.color_complete_gl[
                        lcomplete.index(txt)
                    ]
                )

                annotation.set_position((station[i] + 0., elevation[i] + 0.))
                self.annotation.append(annotation)

                x_gl_complete.append(station[i])
                y_gl_complete.append(elevation[i])
                color_scat_complete_gl.append(
                    self.color_complete_gl[lcomplete.index(txt)])
            elif txt.strip() in self.incomplete_gl:
                annotate = self.canvas.axes.annotate(
                    txt, (station[i], elevation[i]
                          ), horizontalalignment='left',
                    verticalalignment='top', annotation_clip=True, fontsize=11,
                    color=self.color_incomplete_gl[
                        lincomplete.index(txt)
                    ],
                )

                self.annotation.append(annotate)

                x_gl_incomplete.append(station[i])
                y_gl_incomplete.append(elevation[i])
                color_scat_incomplete_gl.append(
                    self.color_incomplete_gl[lincomplete.index(txt)]
                )

        self.canvas.axes.legend(fancybox=True, shadow=True, fontsize=8)
        self.canvas.figure.tight_layout()

        self.canvas.figure.canvas.draw_idle()
        self.toolbar.update()

        self._init = True

    def update_full(self):
        selected_profile = 0
        station = self.data.profile(selected_profile).get_station()
        station_plus_1 = self.data.profile(selected_profile + 1).get_station()
        elevation = self.data.profile(selected_profile).z()
        elevation_i_plus_1 = self.data.profile(selected_profile + 1).z()
        gl = self.data.profile(selected_profile).names()

        self.canvas.axes.cla()
        self.canvas.axes.grid(color='grey', linestyle='--', linewidth=0.5)
        self.canvas.axes.set_xlabel(
            _translate("MainWindow_reach", "Abscisse en travers (m)"),
            color='green', fontsize=10
        )
        self.canvas.axes.set_ylabel(
            _translate("MainWindow_reach", "Cote (m)"),
            color='green', fontsize=10
        )
        self.canvas.figure.tight_layout()

        label_before_plot_selected = _translate(
            "MainWindow_reach", "Profil précédent")
        label_plot_selected = _translate(
            "MainWindow_reach", "Profil sélectionné")
        label_after_plot_selected = _translate(
            "MainWindow_reach", "Profil suivant")
        color_before_plot_selected = "k"  # 'grey'
        color_plot_selected = 'b'
        color_after_plot_selected = 'm'

        self.before_plot_selected, = self.canvas.axes.plot(
            [], [], label=label_before_plot_selected, lw=1.8,
            linestyle='--', color=color_before_plot_selected
        )
        self.plot_selected, = self.canvas.axes.plot(
            station, elevation, label=label_plot_selected,
            color=color_plot_selected, lw=1.8
        )

        self.after_plot_selected, = self.canvas.axes.plot(
            station_plus_1, elevation_i_plus_1,
            label=label_after_plot_selected,
            color=color_after_plot_selected, lw=1.6, linestyle='--'
        )
        self.annotation = []
        self.complete_gl, self.incomplete_gl = self.data.compute_guidelines()
        lcomplete = list(self.complete_gl)
        lincomplete = list(self.incomplete_gl)

        line_2d = [line_2D for line_2D in self.plot_xy.line_gl]
        self.color_complete_gl = self.get_line_gl_colors(line_2d)
        self.color_incomplete_gl = 2 * ["#000000"]

        x_gl_complete = []
        y_gl_complete = []
        color_scat_complete_gl = []
        x_gl_incomplete = []
        y_gl_incomplete = []
        color_scat_incomplete_gl = []

        for i, txt in enumerate(gl):
            if txt.strip() in self.complete_gl:
                annotation = self.canvas.axes.annotate(
                    txt, (station[i], elevation[i]),
                    horizontalalignment='left',
                    verticalalignment='top', annotation_clip=True,
                    fontsize=11,
                    color=self.color_complete_gl[
                        lcomplete.index(txt)
                    ]
                )

                annotation.set_position((station[i] + 0., elevation[i] + 0.))
                self.annotation.append(annotation)

                x_gl_complete.append(station[i])
                y_gl_complete.append(elevation[i])
                color_scat_complete_gl.append(
                    self.color_complete_gl[lcomplete.index(txt)])
            elif txt.strip() in self.incomplete_gl:
                annotate = self.canvas.axes.annotate(
                    txt, (station[i], elevation[i]
                          ), horizontalalignment='left',
                    verticalalignment='top', annotation_clip=True, fontsize=11,
                    color=self.color_incomplete_gl[
                        lincomplete.index(txt)
                    ],
                )

                self.annotation.append(annotate)

                x_gl_incomplete.append(station[i])
                y_gl_incomplete.append(elevation[i])
                color_scat_incomplete_gl.append(
                    self.color_incomplete_gl[lincomplete.index(txt)]
                )

        self.canvas.axes.legend(fancybox=True, shadow=True, fontsize=8)
        self.canvas.figure.tight_layout()

        self.canvas.figure.canvas.draw_idle()
        self.toolbar.update()

    def update_annotate_full(self, ind):
        for a in self.annotation:
            a.remove()

        self.annotation[:] = []

        x = self.data.profile(ind).get_station()
        y = self.data.profile(ind).z()
        gl = self.data.profile(ind).names()
        complete, incomplete = self.data.compute_guidelines()

        lcomplete = list(complete)
        lincomplete = list(incomplete)

        self.x_complete = []
        color_scat_complete = []
        self.x_incomplete = []
        color_scat_incomplete = []

        try:
            for i, txt in enumerate(gl):
                if txt in complete:
                    annotate = self.canvas.axes.annotate(
                        txt, (x[i], y[i]), horizontalalignment='left',
                        verticalalignment='top', annotation_clip=True,
                        fontsize=11,
                        color=self.color_complete_gl[
                            lcomplete.index(txt)
                        ],
                    )
                    self.annotation.append(annotate)
                    self.x_complete.append([x[i], y[i]])
                    color_scat_complete.append(
                        self.color_complete_gl[lcomplete.index(txt)]
                    )
                elif txt in incomplete:
                    annotate = self.canvas.axes.annotate(
                        txt, (x[i], y[i]), horizontalalignment='left',
                        verticalalignment='top', annotation_clip=True,
                        fontsize=11,
                        color=self.color_incomplete_gl[
                            lincomplete.index(txt)
                        ],
                    )
                    self.annotation.append(annotate)
                    self.x_incomplete.append([x[i], y[i]])
                    color_scat_incomplete.append(
                        self.color_incomplete_gl[lincomplete.index(txt)]
                    )
        except Exception as e:
            logger.warning(f"{e}")

        self.canvas.figure.canvas.draw_idle()

    @timer
    def update(self, ind=None):
        if not self._init:
            self.draw()
            return

        if ind is not None:
            before = ind - 1
            after = ind + 1

            self.before_plot_selected.set_data([], [])
            self.plot_selected.set_data([], [])
            self.after_plot_selected.set_data([], [])

            if 0 <= before < self.data.number_profiles:
                self.before_plot_selected.set_data(
                    self.data.profile(before).get_station(),
                    self.data.profile(before).z()
                )

            if 0 <= ind < self.data.number_profiles:
                self.plot_selected.set_data(
                    self.data.profile(ind).get_station(),
                    self.data.profile(ind).z()
                )

            if 0 <= after < self.data.number_profiles:
                self.after_plot_selected.set_data(
                    self.data.profile(after).get_station(),
                    self.data.profile(after).z()
                )

            self.update_annotate_full(ind)
        else:
            self.update_full()
            self.update_annotate_full(0)

        self.canvas.axes.relim()
        self.canvas.axes.autoscale()
        self.canvas.axes.autoscale_view()
        self.canvas.figure.canvas.draw_idle()
