#!/bin/python
# -*- coding: utf-8 -*-

# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.

from fenrirscreenreader.core import debug
from fenrirscreenreader.core import inputData
import os, inspect, time
currentdir = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe()))))
fenrirPath = os.path.dirname(currentdir)

class inputManager():
    def __init__(self):
        self.setLedState = True
        self.shortcutType = 'KEY'
        self.executeDeviceGrab = False        
    def setShortcutType(self, shortcutType = 'KEY'):
        if shortcutType in ['KEY', 'BYTE']:
            self.shortcutType = shortcutType
    def getShortcutType(self):
        return self.shortcutType
    def initialize(self, environment):
        self.env = environment
        self.env['runtime']['settingsManager'].loadDriver(\
          self.env['runtime']['settingsManager'].getSetting('keyboard', 'driver'), 'inputDriver')
        self.updateInputDevices()

        # init LEDs with current state
        self.env['input']['newNumLock'] = self.env['runtime']['inputDriver'].getLedState()
        self.env['input']['oldNumLock'] = self.env['input']['newNumLock']
        self.env['input']['newCapsLock'] = self.env['runtime']['inputDriver'].getLedState(1)
        self.env['input']['oldCapsLock'] = self.env['input']['newCapsLock']
        self.env['input']['newScrollLock'] = self.env['runtime']['inputDriver'].getLedState(2)
        self.env['input']['oldScrollLock'] = self.env['input']['newScrollLock']
        self.lastDeepestInput = []
        self.env['input']['shortcutRepeat'] = 1
        self.lastInputTime = time.time()
    def shutdown(self):
        self.removeAllDevices()
        self.env['runtime']['settingsManager'].shutdownDriver('inputDriver')
    def  getInputEvent(self):
        event =  None
        try:
            event = self.env['runtime']['inputDriver'].getInputEvent()
        except:
            pass
        return event
    def setExecuteDeviceGrab(self, newExecuteDeviceGrab = True):
        self.executeDeviceGrab = newExecuteDeviceGrab
    def handleDeviceGrab(self):
        if not self.executeDeviceGrab:
            return
        if not self.noKeyPressed():
            return        
        if not self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
            return            
        if self.env['runtime']['screenManager'].getCurrScreenIgnored():
            self.ungrabAllDevices()
            self.env['runtime']['outputManager'].interruptOutput()
        else:
            self.grabAllDevices()            
        self.executeDeviceGrab = False 
    def handleInputEvent(self, eventData):
        if not eventData:
            return
        self.env['input']['prevInput'] = self.env['input']['currInput'].copy()
        if eventData['EventState'] == 0:
            if eventData['EventName'] in self.env['input']['currInput']:
                self.env['input']['currInput'].remove(eventData['EventName'])
                if len(self.env['input']['currInput']) > 1:
                    self.env['input']['currInput'] = sorted(self.env['input']['currInput'])
                elif len(self.env['input']['currInput']) == 0:
                    self.env['input']['shortcutRepeat'] = 1 
                self.setLedState = self.handleLedStates(eventData)                                             
                self.lastInputTime = time.time()                                                   
        elif eventData['EventState'] == 1:
            if not eventData['EventName'] in self.env['input']['currInput']:
                self.env['input']['currInput'].append(eventData['EventName'])
                if len(self.env['input']['currInput']) > 1:
                    self.env['input']['currInput'] = sorted(self.env['input']['currInput'])
                if len(self.lastDeepestInput) < len(self.env['input']['currInput']):
                    self.setLastDeepestInput( self.env['input']['currInput'].copy())
                elif self.lastDeepestInput == self.env['input']['currInput']:
                    if time.time() - self.lastInputTime <= self.env['runtime']['settingsManager'].getSettingAsFloat('keyboard','doubleTapTimeout'):
                        self.env['input']['shortcutRepeat'] += 1
                    else:
                        self.env['input']['shortcutRepeat'] = 1
                self.setLedState = self.handleLedStates(eventData)                                             
                self.lastInputTime = time.time()                                               
        elif eventData['EventState'] == 2:
            self.lastInputTime  = time.time()                                                   

        self.env['input']['oldNumLock'] = self.env['input']['newNumLock']
        self.env['input']['newNumLock'] = self.env['runtime']['inputDriver'].getLedState()
        self.env['input']['oldCapsLock'] = self.env['input']['newCapsLock'] 
        self.env['input']['newCapsLock'] = self.env['runtime']['inputDriver'].getLedState(1)
        self.env['input']['oldScrollLock'] = self.env['input']['newScrollLock'] 
        self.env['input']['newScrollLock'] = self.env['runtime']['inputDriver'].getLedState(2)
        self.env['runtime']['debug'].writeDebugOut("currInput " + str(self.env['input']['currInput'] ) ,debug.debugLevel.INFO)              
        if self.noKeyPressed():
            self.env['input']['prevInput'] = []
            self.setLedState = True
            self.handleDeviceGrab()           
            
    def handleLedStates(self, mEvent):
        if not self.setLedState:
            return self.setLedState
        if mEvent['EventName'] == 'KEY_NUMLOCK':
            if mEvent['EventState'] == 1 and not self.env['input']['newNumLock'] == 1:
                self.env['runtime']['inputDriver'].toggleLedState() 
                return False
            if mEvent['EventState'] == 0 and not self.env['input']['newNumLock'] == 0:
                self.env['runtime']['inputDriver'].toggleLedState()                                                                        
                return False
        if mEvent['EventName'] == 'KEY_CAPSLOCK':   
            if mEvent['EventState'] == 1 and not self.env['input']['newCapsLock'] == 1:
                self.env['runtime']['inputDriver'].toggleLedState(1)              
                return False
            if mEvent['EventState'] == 0 and not self.env['input']['newCapsLock'] == 0:
                self.env['runtime']['inputDriver'].toggleLedState(1)                                                                         
                return False                                      
        if mEvent['EventName'] == 'KEY_SCROLLLOCK':  
            if mEvent['EventState'] == 1 and not self.env['input']['newScrollLock'] == 1:
                self.env['runtime']['inputDriver'].toggleLedState(2)              
                return False
            if mEvent['EventState'] == 0 and not self.env['input']['newScrollLock'] == 0:
                self.env['runtime']['inputDriver'].toggleLedState(2)                                                                       
                return False
        return self.setLedState

    def grabAllDevices(self):
        if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
            try:
                self.env['runtime']['inputDriver'].grabAllDevices()
            except Exception as e:
                pass                
    def ungrabAllDevices(self):
        if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
            try:
                self.env['runtime']['inputDriver'].ungrabAllDevices()
            except Exception as e:
                pass
    def handlePlugInputDevice(self, eventData):
        self.env['runtime']['inputManager'].updateInputDevices(eventData)
            
    def updateInputDevices(self, newDevice = None):
        try:
            self.env['runtime']['inputDriver'].updateInputDevices(newDevice)  
        except:
            pass
        self.setExecuteDeviceGrab()
        try:
            if self.env['runtime']['screenManager']:
                self.handleDeviceGrab()
        except:
            pass
    def removeAllDevices(self):
        try:
            self.env['runtime']['inputDriver'].removeAllDevices()
        except:
            pass

    def convertEventName(self, eventName):
        if not eventName:
            return ''
        if eventName == '':
            return ''
        eventName = eventName.upper()
        if eventName == 'KEY_LEFTCTRL':
            eventName = 'KEY_CTRL'         
        elif eventName == 'KEY_RIGHTCTRL':
            eventName = 'KEY_CTRL'
        elif eventName == 'KEY_LEFTSHIFT':
            eventName = 'KEY_SHIFT'
        elif eventName == 'KEY_RIGHTSHIFT':
            eventName = 'KEY_SHIFT'
        elif eventName == 'KEY_LEFTALT':
            eventName = 'KEY_ALT'
        elif eventName == 'KEY_RIGHTALT':
            eventName = 'KEY_ALT'
        elif eventName == 'KEY_LEFTMETA':
            eventName = 'KEY_META'
        elif eventName == 'KEY_RIGHTMETA':
            eventName = 'KEY_META'            
        if self.isFenrirKey(eventName):
            eventName = 'KEY_FENRIR'
        if self.isScriptKey(eventName):
            eventName = 'KEY_SCRIPT'            
        return eventName

    def clearEventBuffer(self):
        try:
            self.env['runtime']['inputDriver'].clearEventBuffer()
        except Exception as e:
            pass              
    def setLastDeepestInput(self, currentDeepestInput):
        self.lastDeepestInput = currentDeepestInput
    def clearLastDeepInput(self):
        self.lastDeepestInput = []  
    def getLastInputTime(self):
        return self.lastInputTime           
    def getLastDeepestInput(self):
        return self.lastDeepestInput 
    def writeEventBuffer(self):
        try:
            if self.env['runtime']['settingsManager'].getSettingAsBool('keyboard', 'grabDevices'):
                self.env['runtime']['inputDriver'].writeEventBuffer()
            self.clearEventBuffer()
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("Error while writeUInput",debug.debugLevel.ERROR)
            self.env['runtime']['debug'].writeDebugOut(str(e),debug.debugLevel.ERROR)

    def noKeyPressed(self):
        return self.env['input']['currInput'] == []
    def isKeyPress(self):
        return (self.env['input']['prevInput'] == []) and (self.env['input']['currInput'] != [])
    def getPrevDeepestShortcut(self):
        shortcut = []
        shortcut.append(self.env['input']['shortcutRepeat'])
        shortcut.append(self.getLastDeepestInput())
        return str(shortcut)
        
    def getPrevShortcut(self):
        shortcut = []
        shortcut.append(self.env['input']['shortcutRepeat'])
        shortcut.append(self.env['input']['prevInput'])
        return str(shortcut)

    def getCurrShortcut(self, inputSequence = None):
        shortcut = []
        shortcut.append(self.env['input']['shortcutRepeat'])
        if inputSequence:
            shortcut.append(inputSequence)
        else:        
            shortcut.append(self.env['input']['currInput'])
        if len(self.env['input']['prevInput']) < len(self.env['input']['currInput']):
            if self.env['input']['shortcutRepeat'] > 1  and not self.shortcutExists(str(shortcut)):
                shortcut = []
                self.env['input']['shortcutRepeat'] = 1
                shortcut.append(self.env['input']['shortcutRepeat'])
                shortcut.append(self.env['input']['currInput'])     
        self.env['runtime']['debug'].writeDebugOut("currShortcut " + str(shortcut) ,debug.debugLevel.INFO)                      
        return str(shortcut)
        
    def currKeyIsModifier(self):
        if len(self.getLastDeepestInput()) != 1:
            return False
        return (self.env['input']['currInput'][0] =='KEY_FENRIR') or (self.env['input']['currInput'][0] == 'KEY_SCRIPT')
    
    def isFenrirKey(self, eventName):
        return eventName in self.env['input']['fenrirKey']
    
    def isScriptKey(self, eventName):
        return eventName in self.env['input']['scriptKey']
    
    def getCommandForShortcut(self, shortcut):
        if not self.shortcutExists(shortcut):
            return '' 
        return self.env['bindings'][shortcut]

    def shortcutExists(self, shortcut):
        return(shortcut in self.env['bindings'])
    def loadShortcuts(self, kbConfigPath=fenrirPath + '/../../config/keyboard/desktop.conf'):
        kbConfig = open(kbConfigPath,"r")
        while(True):
            invalid = False
            line = kbConfig.readline()
            if not line:
                break
            line = line.replace('\n','')
            if line.replace(" ","") == '':
                continue            
            if line.replace(" ","").startswith("#"):
                continue
            if line.count("=") != 1:
                continue
            sepLine = line.split('=')
            commandName = sepLine[1].upper()
            sepLine[0] = sepLine[0].replace(" ","")
            sepLine[0] = sepLine[0].replace("'","")
            sepLine[0] = sepLine[0].replace('"',"")
            keys = sepLine[0].split(',')
            shortcutKeys = []
            shortcutRepeat = 1
            shortcut = []
            for key in keys:
                try:
                    shortcutRepeat = int(key)
                except:
                    if not self.isValidKey(key.upper()):
                        self.env['runtime']['debug'].writeDebugOut("invalid key : "+ key.upper() + ' command:' +commandName ,debug.debugLevel.WARNING)                    
                        invalid = True
                        break
                    shortcutKeys.append(key.upper()) 
            if invalid:
                continue
            shortcut.append(shortcutRepeat)
            shortcut.append(sorted(shortcutKeys))
            if len(shortcutKeys) != 1 and not 'KEY_FENRIR' in shortcutKeys:
                self.env['runtime']['debug'].writeDebugOut("invalid shortcut (missing KEY_FENRIR): "+ str(shortcut) + ' command:' +commandName ,debug.debugLevel.ERROR)                    
                continue            
            self.env['runtime']['debug'].writeDebugOut("Shortcut: "+ str(shortcut) + ' command:' +commandName ,debug.debugLevel.INFO, onAnyLevel=True)    
            self.env['bindings'][str(shortcut)] = commandName   
        kbConfig.close()
        # fix bindings 
        self.env['bindings'][str([1, ['KEY_F1', 'KEY_FENRIR']])] = 'TOGGLE_TUTORIAL_MODE'
    def isValidKey(self, key):
        return key in inputData.keyNames        
