import sys
from PyQt5 import QtCore, QtGui, QtWidgets

from .util import get_resource

from .multiplot import SandboxSceneDockarea, ModelReferenceDockarea
from .sources_dock import SourcesListDock
from .tool_dialogs import ExtentDialog, LosDialog
from .config import ConfigDialog
from .sandbox_model import SandboxModel

from kite.sandbox_scene import SandboxScene
from kite.qt_utils import loadUi, SceneLog, validateFilename


class Talpa(QtWidgets.QApplication):

    def __init__(self, filename=None):
        QtWidgets.QApplication.__init__(self, ['Talpa'])

        splash_img = QtGui.QPixmap(
            get_resource('talpa_splash.png'))\
            .scaled(QtCore.QSize(400, 250), QtCore.Qt.KeepAspectRatio)
        self.splash = QtWidgets.QSplashScreen(
            splash_img, QtCore.Qt.WindowStaysOnTopHint)
        self.updateSplashMessage('Talpa')
        self.splash.show()
        self.processEvents()

        self.talpa_win = TalpaMainWindow(filename=filename)

        self.talpa_win.actionExit.triggered.connect(self.exit)
        self.aboutToQuit.connect(self.talpa_win.sandbox.worker_thread.quit)
        self.aboutToQuit.connect(self.talpa_win.sandbox.deleteLater)
        self.aboutToQuit.connect(self.splash.deleteLater)
        self.aboutToQuit.connect(self.deleteLater)

        self.talpa_win.show()

        self.splash.finish(self.talpa_win)
        rc = self.exec_()
        sys.exit(rc)

    @QtCore.pyqtSlot(str)
    def updateSplashMessage(self, msg=''):
        self.splash.showMessage("Loading %s ..." % msg.title(),
                                QtCore.Qt.AlignBottom)


class TalpaMainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        filename = kwargs.pop('filename', None)
        QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
        loadUi(get_resource('talpa.ui'), baseinstance=self)
        self.sandbox = SandboxModel.empty()

        self.log = SceneLog(self, self.sandbox)

        self.actionSaveModel.triggered.connect(
            self.onSaveModel)
        self.actionLoadModel.triggered.connect(
            self.loadModel)
        self.actionExportKiteScene.triggered.connect(
            self.onExportScene)
        self.actionChangeExtent.triggered.connect(
            self.extentDialog)
        self.actionChangeLos.triggered.connect(
            self.losDialog)
        self.actionLoadReferenceScene.triggered.connect(
            self.onLoadReferenceScene)

        self.actionConfiguration.triggered.connect(
            self.configDialog)

        self.actionHelp.triggered.connect(
            lambda: QtGui.QDesktopServices.openUrl('https://pyrocko.org'))
        self.actionAbout_Talpa.triggered.connect(
            self.aboutDialog().show)
        self.actionLog.triggered.connect(
            self.log.show)

        self.sandbox.sigModelChanged.connect(
            self.createMisfitWindow)

        if filename is not None:
            self.loadModel(filename)
        self.createView(self.sandbox)

    def createView(self, sandbox):
        plots = SandboxSceneDockarea(sandbox)
        sources = SourcesListDock(sandbox, parent=self)
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, sources)
        self.centralwidget.layout().addWidget(plots)

    def aboutDialog(self):
        self._about = QtWidgets.QDialog(self)
        loadUi(get_resource('about.ui'), baseinstance=self._about)
        return self._about

    @QtCore.pyqtSlot()
    def extentDialog(self):
        ExtentDialog(self.sandbox, self).show()

    @QtCore.pyqtSlot()
    def losDialog(self):
        LosDialog(self.sandbox, self).show()

    @QtCore.pyqtSlot()
    def configDialog(self):
        ConfigDialog(self).show()

    @QtCore.pyqtSlot(str)
    def processingStarted(self, text):
        self.progress.setLabelText(text)
        self.progress.show()

    @QtCore.pyqtSlot()
    def onSaveModel(self):
        filename, _ = QtWidgets.QFileDialog.getSaveFileName(
            filter='YAML *.yml (*.yml)',
            caption='Save SandboxScene')
        if not validateFilename(filename):
            return
        self.sandbox.model.save(filename)

    @QtCore.pyqtSlot()
    def loadModel(self, filename=None):
        if filename is None:
            filename, _ = QtWidgets.QFileDialog.getOpenFileName(
                filter='YAML *.yml (*.yml)',
                caption='Load SandboxScene')
        if not validateFilename(filename):
            return
        model = SandboxScene.load(filename)
        self.sandbox.setModel(model)

    def onLoadReferenceScene(self):
        filename, _ = QtWidgets.QFileDialog.getOpenFileName(
            filter='YAML *.yml (*.yml)',
            caption='Load kite.Scene')
        if not validateFilename(filename):
            return
        self.sandbox.model.loadReferenceScene(filename)

        self.createMisfitWindow()
        self.actionMisfitScene.setChecked(True)

    def createMisfitWindow(self):
        if self.sandbox.model.reference is None:
            return

        self.misfitWindow = MisfitWindow(self.sandbox, self)

        def toggleWindow(switch):
            if switch:
                self.misfitWindow.show()
            else:
                self.misfitWindow.close()

        self.misfitWindow.windowClosed.connect(
            lambda: self.actionMisfitScene.setChecked(False))
        self.actionMisfitScene.toggled.connect(toggleWindow)
        self.actionMisfitScene.setEnabled(True)

    def onExportScene(self):
        filename, _ = QtWidgets.QFileDialog.getSaveFileName(
            filter='YAML *.yml and NumPy container *.npz (*.yml *.npz)',
            caption='Save scene')
        if not validateFilename(filename):
            return
        scene = self.sandbox.model.getKiteScene()
        scene.save(filename)

    def closeModel(self, sandbox):
        pass


class MisfitWindow(QtWidgets.QMainWindow):
    windowClosed = QtCore.pyqtSignal()

    def __init__(self, sandbox, *args, **kwargs):
        QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
        loadUi(get_resource('window_reference.ui'), self)

        self.move(
            self.parent().window().mapToGlobal(
                self.parent().window().rect().center()) -
            self.mapToGlobal(self.rect().center()))

        self.sandbox = sandbox

        self.actionOptimizeSource.triggered.connect(
            self.sandbox.optimizeSource)

        self.createView(self.sandbox)

    def createView(self, sandbox):
        plots = ModelReferenceDockarea(sandbox)
        self.centralwidget.layout().addWidget(plots)

    def closeEvent(self, ev):
        self.windowClosed.emit()
        ev.accept()