__author__ = 'Janko Slavic'

import sys
from PyQt6 import QtCore
from PyQt6 import QtGui
from PyQt6 import QtWidgets

import time
import numpy as np

import matplotlib

matplotlib.use('Qt5Agg')
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure


class MainWindow(QtWidgets.QMainWindow):
    """ Inherited main window
    """

    def __init__(self):
        """ Constructor of the MainWindow object
        """
        QtWidgets.QMainWindow.__init__(self)
        self.setWindowTitle('Main window')
        self.setGeometry(50, 50, 600, 400)
        # self.showMaximized()
        # self.init_status_bar()
        self.init_status_bar_with_progress()
        self.init_central_widget()
        self.init_actions()
        self.init_menus()
        self.phase = 0
        # we will need this for the animation
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.animate_figure)

    def init_status_bar(self):
        """ Function to create Status Bar
        """
        self.status_bar = QtWidgets.QStatusBar()
        self.status_bar.showMessage('Ready', 2000)
        self.setStatusBar(self.status_bar)

    def init_status_bar_with_progress(self):
        """ Function to create Status Bar with progress bar
        """
        self.status_bar = QtWidgets.QStatusBar()
        self.status_label = QtWidgets.QLabel('Status')
        self.progress_bar = QtWidgets.QProgressBar()
        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(100)
        self.progress_bar.setValue(0)
        self.status_bar.addWidget(self.status_label, 1)
        self.status_bar.addWidget(self.progress_bar, 2)
        self.setStatusBar(self.status_bar)

    def init_central_widget(self):
        """ Contents of the central window
        """
        self.central_widget = QtWidgets.QWidget()
        self.buttons_widget = QtWidgets.QWidget()
        v_layout = QtWidgets.QVBoxLayout()
        h_layout = QtWidgets.QHBoxLayout()
        self.function_text = QtWidgets.QTextEdit()
        self.function_text.setFontPointSize(10)
        self.function_text.setText('np.sin')
        self.function_text.setMaximumHeight(50)
        self.submit_btn = QtWidgets.QPushButton('Show')
        self.submit_btn.pressed.connect(self.refresh_figure)
        self.animate_btn = QtWidgets.QPushButton('Animate')
        self.animate_btn.pressed.connect(self.animate_figure)
        self.animate_btn.setCheckable(True)
        self.get_figure()

        self.central_widget.setLayout(v_layout)
        v_layout.addWidget(self.function_text)
        v_layout.addWidget(self.buttons_widget)
        v_layout.addWidget(self.canvas)
        v_layout.addWidget(self.canvas_toolbar)

        self.buttons_widget.setLayout(h_layout)
        h_layout.addStretch()
        h_layout.addWidget(self.submit_btn)
        h_layout.addWidget(self.animate_btn)
        h_layout.addStretch()

        self.setCentralWidget(self.central_widget)

    def init_menus(self):
        """ Set up the menus
        """
        self.file_menu = self.menuBar().addMenu('&File')
        self.help_menu = self.menuBar().addMenu('&Help')

        self.file_menu.addAction(self.new_file_action)
        self.file_menu.addAction(self.reset_action)
        self.help_menu.addAction(self.help_action)

    def file_show_help(self):
        QtWidgets.QMessageBox.about(self,
                                'Display of a pop-up window with text.',
                                'Python and Qt :)\nEnter a numpy function')

    def clear_input(self):
        self.function_text.setText('')

    def reset_input(self):
        self.function_text.setText('np.sin')

    def init_actions(self):
        """ Set up the actions for the menus
        """
        self.new_file_action = QtGui.QAction('&New',
                                             self, shortcut=QtGui.QKeySequence.StandardKey.New,
                                             statusTip="New display",
                                             triggered=self.clear_input)
        self.reset_action = QtGui.QAction('&Reset',
                                          self,
                                          statusTip="Reset",
                                          triggered=self.reset_input)
        self.help_action = QtGui.QAction(  # QtWidgets.QIcon('new.png') # this is how an icon could be included
                                           '&Help',
                                           self,
                                           triggered=self.file_show_help)

    def get_figure(self):
        self.fig = Figure(figsize=(600, 600), dpi=72, facecolor=(1, 1, 1), edgecolor=(0, 0, 0))
        self.ax = self.fig.add_subplot(111)

        self.canvas = FigureCanvasQTAgg(self.fig)
        self.canvas_toolbar = NavigationToolbar(self.canvas, self)

    def animate_figure(self):
        try:
            eq = eval(self.function_text.toPlainText())
        except AttributeError:
            self.timer.stop()
            QtWidgets.QMessageBox.about(self, 'Error',
                                    'Cannot display the function {:s}'.format(self.function_text.toPlainText()))
            return
        x = self.phase + np.linspace(0, 10, 100)
        y = eq(x)
        self.ax.clear()
        self.ax.plot(x, y)
        self.ax.set_xlim(np.min(x), np.max(x))
        self.fig.canvas.draw()
        self.phase += 0.1
        if self.animate_btn.isChecked() or self.animate_btn.isDown():
            self.timer.start(40)  # trigger this function again after 40 ms
        else:
            self.timer.stop()

    def refresh_figure(self):
        try:
            eq = eval(self.function_text.toPlainText())
        except AttributeError:
            QtWidgets.QMessageBox.about(self, 'Error',
                                    'Cannot display the function {:s}'.format(self.function_text.toPlainText()))
            return
        x = self.phase + np.linspace(0, 10, 100)
        y = eq(x)
        self.ax.plot(x, y)
        self.fig.canvas.draw()

    def show_progress(self):
        """ Show the progress

        """
        while self.progress_bar.value() < 100:
            self.progress_bar.setValue(self.progress_bar.value() + 2)
            time.sleep(.01)
        self.status_label.setText('Ready')

    def mouseDoubleClickEvent(self, event):
        """ We override the inherited event in the QtWidgets.QMainWindow object
            (double-click for example on the progress bar)
        """
        self.close()

if __name__ == '__main__':
    try:
        app = QtWidgets.QApplication(sys.argv)
        mainWindow = MainWindow()
        mainWindow.show()
        mainWindow.show_progress()
        app.exec()
        sys.exit(0)
    except SystemExit:
        print('Closing window.')
    except:
        print(sys.exc_info())
