#!/usr/bin/env python3
import sys
import signal
import json
import time
import numpy as np
import matplotlib.cm as cm
import argparse
import pyqtgraph as pg
import pyqtgraph.opengl as gl

# import rat
# import ROOT
from sibyl_cpp import *
from PyQt5 import *
from PyQt5.QtOpenGL import *
from sibyl import *

""" -- Sibyl Event Viewer --> Central Widget
|------------------------------------------|
|Main|Crate|...|                           |
|------------------------------------------|
|         --         |     .^.^.^.^.       |
|        -  -        |    /         \      |
|         --         |   /    3D     \     |
| ------------------ |  /             \    |
| |                | |----------|----------|
| |________________| | Info     |_    Hist |
|         --         | Panel    | |__  Q/T |
|        -  -        |          |    |_    |
|         --         |          |      |__ |
|------------------------------------------|

Central Widget is contained in the MainWindow as:
|-----------------------------------------|
| Menu Bar                                |
|-----------------------------------------|
|                Toolbars                 |
|  |-----------------------------------|  |
|  |           Dock Widgets            |  |
|  |  |-----------------------------|  |  |
|  |  |                             |  |  |
|  |  |                             |  |  |
|  |  |       Central Widget        |  |  |
|  |  |                             |  |  |
|  |  |                             |  |  |
|  |  |-----------------------------|  |  |
|  |                                   |  |
|  |-----------------------------------|  |
|                                         |
|-----------------------------------------|
| Status Bar                              |
|-----------------------------------------|
"""


class MainWindow(QtGui.QMainWindow):
    """
    Order of operations:
    1. Create the main window
    2. Create grid layout
    3. Open the ratroot file to get information and store event info
    """

    App = None
    plot = None
    parameters = {}
    config = {}
    listOfTabs = []

    def __init__(self, args, app=None):
        self.args = args
        self._default_parameters()
        # Icon
        if self.App is None:
            if app is not None:
                self.App = app
            else:
                self.App = QtGui.QApplication([])
        super(MainWindow, self).__init__()
        self.resize(1600, 900)
        self.setWindowTitle("Sibyl")
        # self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.trayIcon = SibylTrayIcon()
        self.trayIcon.show()
        self.beginRat()
        self._menubarWidget()
        # self._toolbarWidget()
        self._statusbarWidget()
        self._centralWidget()
        self.show()
        # Load in data
        self.newEvent()

    def _default_parameters(self):
        """
        The parameters dictionary is used to allow widgets
        to share and update information. Must be careful to
        make sure multiple modules dont set the same parameter.
        """
        self.parameters["name"] = "Sibyl"
        self.parameters["autoRange"] = True
        self.parameters["colorMask"] = "charge"
        self.parameters["histXMax"] = 1
        self.parameters["histYMax"] = 1
        self.parameters["colorMap"] = cm.Spectral
        self.parameters["entries"] = 0
        self.parameters["charge"] = np.array([])
        self.parameters["time"] = np.array([])
        # Load the default config file
        self.state = SibylState()
        self.state.loadState(self.parameters)
        # parameter override
        self.parameters["filename"] = self.args.ratfile
        self.parameters["invisible"] = self.args.invisible
        self.parameters["onlyHits"] = self.args.onlyHits
        self.parameters["trackingEnabled"] = self.args.tracking
        self.parameters["cherenkovBrightness"] = self.args.cherenkov_brightness

    def _toolbarWidget(self):
        bar = self.addToolBar("BARR")
        bar.addAction("Hi")

    def _statusbarWidget(self):
        bar = self.statusBar()
        # bar.showMessage("Hello world")
        self.total_events_line = QtGui.QLineEdit("0")
        self.total_events_line.setReadOnly(True)
        self.total_events_line.setText(str(self.parameters["entries"]))
        # bar.addWidget(QtGui.QLabel("Total Events"), self.total_events_line)
        bar.addWidget(QtGui.QLabel("Total Events"))
        bar.addWidget(self.total_events_line)
        left_button = QtGui.QPushButton("<")
        left_button.clicked.connect(self.leftEvent)
        right_button = QtGui.QPushButton(">")
        right_button.clicked.connect(self.rightEvent)
        self.event = QtGui.QLineEdit("0")
        self.event.textChanged.connect(self.newEvent)
        self.hboxchooser = QtGui.QHBoxLayout()
        self.hboxchooser.addWidget(left_button)
        self.hboxchooser.addWidget(right_button)
        self.hboxchooser.addWidget(self.event)
        bar.addWidget(left_button)
        bar.addWidget(right_button)
        bar.addWidget(self.event)
        # formLayout.addRow(self.hboxchooser)

    def _menubarWidget(self):
        self.fileMenu = SibylMenuBar(self)

    def close(self):
        self.state.saveState()
        super(MainWindow, self).close()
        # sys.exit()

    def _centralWidget(self):
        # Tabbed view
        self.tabWidget = QtGui.QTabWidget()

        # Event tab
        eventWidget = SibylTabEvent(self)
        self.listOfTabs.append(eventWidget)
        self.tabWidget.addTab(eventWidget, "Event")

        # Document tab
        aboutWidget = SibylTabAbout(self)
        self.listOfTabs.append(aboutWidget)
        self.tabWidget.addTab(aboutWidget, "About")

        # Add to center
        self.setCentralWidget(self.tabWidget)

    def leftEvent(self):
        min_event = 0
        cur_event = int(self.event.text())
        if cur_event > (min_event):
            cur_event -= 1
        self.event.setText(str(cur_event))

    def rightEvent(self):
        max_event = int(self.total_events_line.text())
        cur_event = int(self.event.text())
        if cur_event < (max_event - 1):
            cur_event += 1
        self.event.setText(str(cur_event))

    def updateEvent(self):
        self.readRat()
        if self.args.tracking:
            self.readRatTracking()
        for tab in self.listOfTabs:
            tab.drawEvent()

    def newEvent(self):
        min_event, max_event = 0, int(self.total_events_line.text())
        try:
            cur_event = int(self.event.text())
        except ValueError:
            self.event.setText("0")
            cur_event = int(self.event.text())
        if (cur_event >= min_event) and (cur_event < max_event):
            self.updateEvent()
        else:
            self.event.setText("0")

    ## Rat, moveme to rat class
    def beginRat(self):
        self.cobra = snake()
        self.cobra.openFile(self.parameters["filename"])
        self.parameters["posArray"] = np.array(self.cobra.getXYZ()).T
        self.parameters["entries"] = self.cobra.getEntries()
        self.parameters["boundaryRadius"] = self.cobra.getBoundaryRadius();
        self.parameters["boundaryHalfz"] = self.cobra.getBoundaryHalfz();

    def readRat(self):
        event = int(self.event.text())
        self.cobra.getEvent(event)
        self.parameters["charge"], self.parameters["time"] = self.cobra.getHitInfo()
        self.parameters["plWeights"] = np.zeros(len(self.parameters["charge"])) + 100
        self.parameters["plWeights"][self.parameters["charge"] > -99] = 300

    def readRatTracking(self):
        self.cobra.getTracking()
        x, y, z, n = self.cobra.getTrackSteps()
        # Colors based on: ID and Process if optical
        # Yellow: electron
        clr_electron = (1, 1, 0, 1.0)
        clr_muon = (1, 0, 0, 1.0)
        # Green: Gamma
        clr_gamma = (0, 1, 0, 1.0)
        # Cherenkov: Blue
        cb = self.parameters["cherenkovBrightness"]
        clr_cherenkov = (0, 0.5, 1.0, cb)
        # Scintillation: Pink
        clr_scint = (1, 0, 0.5, 0.1)
        clr_reim = (0, 0, 1, 0.1)
        clr_other = (0.7, 0.7, 0.8, 0.1)
        clr_dict = {
            0: clr_other,
            1: clr_cherenkov,
            2: clr_scint,
            3: clr_electron,
            4: clr_gamma,
            5: clr_muon,
        }

        self.parameters["trackPosition"] = np.array([x, y, z]).T
        self.parameters["trackColors"] = np.array([clr_dict[i] for i in n])


def get_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("ratfile", type=str, help=("rat root file"))
    parser.add_argument(
        "--debug", action="store_true", help="Turn on debug print statements"
    )
    parser.add_argument(
        "--tracking",
        action="store_true",
        help="ROOT files only. If storeTracking was used during simulation,\
            then the particle tracks will be drawn.",
    )
    parser.add_argument(
        "--cherenkov_brightness",
        type=float,
        default=0.10,
        help="Scale cherenkov when showing tracks",
    )
    parser.add_argument(
        "--invisible", action="store_true", help="This is a hack, remove eventually"
    )
    parser.add_argument("--onlyHits", action="store_true", help="Show only hit pmts")
    parser.add_argument(
        "--stream", action="store_true", help="Hack to test streaming capabilities"
    )
    return parser.parse_args()


if __name__ == "__main__":
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    args = get_args()

    def dprint(*argmnt):
        if args.debug:
            print(*argmnt)

    app = QtGui.QApplication([])
    print(QtGui.QStyleFactory.keys())
    app.setStyle(QtGui.QStyleFactory.create("Fusion"))
    # with open('Aqua.qss') as sheet:
    #    app.setStyleSheet(sheet.read())
    guit = MainWindow(args, app)

    # This loops through events, potentially a way to update a stream
    if args.stream:
        start_time = time.time()

        def handler():
            eid = int(guit.event.text())
            if eid > 8000:
                timer.stop()
                freq = (eid + 1) / (time.time() - start_time)
                print(f"Frequency: {freq:.2f}")
                guit.close()
            guit.rightEvent()

        timer = QtCore.QTimer()
        timer.timeout.connect(handler)
        timer.start(1)

    sys.exit(app.exec_())
