#!/usr/bin/python3
import evdev
from PyQt5 import QtWidgets, QtCore, QtGui


class InputMonitor(QtCore.QObject):
    toggle = QtCore.pyqtSignal()

    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.preferences = parent.preferences
        self.device = ""
        self.lastKeys = ""
        self.counter = 0
        self.hold = False
        self.timer = QtCore.QTimer(interval=100)
        self.timer.timeout.connect(self._read)
        self.timer.start()

    def _compare(self, hotkey, keys):
        if keys != self.lastKeys or self.hold:
            self.lastKeys = keys
            if hotkey == keys:
                delay = self.preferences.get("behavior", "hold delay")
                if self.counter >= delay:
                    self.toggle.emit()
                    self._holdStop()
                else:
                    self._holdIncrement()
            else:
                self._holdStop()

    def _holdIncrement(self):
        self.hold = True
        self.counter += self.timer.interval()

    def _holdStop(self):
        self.hold = False
        self.counter = 0

    def _read(self):
        devices = self.preferences.db["devices"]
        for dev in devices:
            cfg = devices[dev]
            symlink = cfg["symlink"]
            try:
                dev = evdev.InputDevice(symlink)
                keys = dev.active_keys()
                keys = str(keys)[1:-1]
                hotkey = cfg["hotkey"]
                self._compare(hotkey, keys)
            except OSError:
                pass


class Main(QtWidgets.QWidget):
    disconnect = QtCore.pyqtSignal(str)

    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.preferences = parent.preferences
        self.process = QtCore.QProcess()
        self.frontend = QtCore.QProcess()
        self.frontendStartTimer = QtCore.QTimer(interval=1000, singleShot=True)
        self.frontendStartTimer.timeout.connect(self._frontendStart)

        self.worker = InputMonitor(self)
        self.workerThread = QtCore.QThread()
        self.worker.moveToThread(self.workerThread)
        self.worker.toggle.connect(self._toggle)
        self.workerThread.start()

        palette = QtGui.QPalette()
        palette.setColor(QtGui.QPalette.Window, QtCore.Qt.black)
        self.setPalette(palette)
        self.setCursor(QtCore.Qt.BlankCursor)
        self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)

    def keyPressEvent(self, event):
        self.hide()

    def mousePressEvent(self, event):
        self.hide()

    def _disconnectEnabled(self):
        if self.preferences.db["behavior"]["disconnect on exit"]:
            for path in self.preferences.db["devices"]:
                self.disconnect.emit(path)

    def _frontendStart(self):
        frontend = self.preferences.db["process"]["frontend"]
        self.frontend.start(frontend)

    def _isRunning(self, pattern):
        self.process.start("ps -eo comm")
        self.process.waitForFinished()
        process = self.process.readAllStandardOutput()
        process = str(process, encoding='ascii')
        if process.find(pattern[:15]) > -1:
            return True
        return False

    def _toggle(self):
        if not self.parent.config.isVisible():
            for process in self.preferences.db["process"]["emulators"]:
                if self._isRunning(process):
                    self.process.start("killall " + process)
                    self.process.waitForFinished()
                    break
            else:
                if self.frontend.state() == QtCore.QProcess.Running:
                    self.activateWindow()
                    self._disconnectEnabled()
                    self.frontend.terminate()
                    self.frontend.waitForFinished()
                    self.hide()
                    after = self.preferences.db["behavior"]["after frontend"]
                    self.process.startDetached(after)
                else:
                    before = self.preferences.db["behavior"]["before frontend"]
                    self.process.startDetached(before)
                    self.showFullScreen()
                    self.frontendStartTimer.start()
