#!/usr/bin/env python3
# -*- coding: utf-8 -*-

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

from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import module_utils
import os, inspect, time

currentdir = os.path.dirname(os.path.realpath(os.path.abspath(inspect.getfile(inspect.currentframe()))))
fenrirPath = os.path.dirname(currentdir)

class vmenuManager():
    def __init__(self):
        self.menuDict = {}
        self.currIndex = None
        self.currMenu = ''
        self.active = False
        self.reset = True
        self.useTimeout = True
        self.searchText = ''
        self.lastSearchTime = time.time()
    def initialize(self, environment):
        self.env = environment
        # use default path
        self.defaultVMenuPath = fenrirPath+ "/commands/vmenu-profiles/" + self.env['runtime']['inputManager'].getShortcutType()
        # if there is no user configuration
        if self.env['runtime']['settingsManager'].getSetting('menu', 'vmenuPath') != '':
            self.defaultVMenuPath = self.env['runtime']['settingsManager'].getSetting('menu', 'vmenuPath')
            if not self.defaultVMenuPath.endswith('/'):
                self.defaultVMenuPath += '/'
            self.defaultVMenuPath += self.env['runtime']['inputManager'].getShortcutType()

        self.createMenuTree()
        self.closeAfterAction = False
    def shutdown(self):
        pass
    def clearSearchText(self):
        self.searchText = ''
    def searchEntry(self, value, forceReset = False):
        if self.currIndex == None:
            return ''
        if self.reset or forceReset:
            self.clearSearchText()
        else:
            if self.useTimeout:
                if time.time() - self.lastSearchTime > 1:
                    self.clearSearchText()
        self.searchText += value.upper()
        self.lastSearchTime = time.time()
        startIndex = self.getCurrIndex()
        while True:
            if not self.nextIndex():
                return ''
            entry = self.getCurrentEntry()
            if entry.upper().startswith(self.searchText):
                return entry
            if startIndex == self.getCurrIndex():
                return ''

    def setCurrMenu(self, currMenu = ''):
        self.currIndex = None
        self.currMenu = ''
        if currMenu != '':
            currMenu += ' ' + _('Menu')
            try:
                t = self.menuDict[currMenu]
                l = list(self.menuDict.keys())
                self.currIndex = [l.index(currMenu)]
            except Exception as e:
                print(e)
                self.currMenu = ''
                self.currIndex = None
                return
            if self.incLevel():
                self.currMenu = currMenu
            else:
                self.currMenu = ''
                self.currIndex = None
    def getCurrMenu(self):
        return self.currMenu
    def getActive(self):
        return self.active
    def togglelVMenuMode(self, closeAfterAction = True):
        self.setActive(not self.getActive(), closeAfterAction)
    def setActive(self, active, closeAfterAction = True):
        if self.env['runtime']['helpManager'].isTutorialMode():
            return
        self.active = active
        if self.active:
            self.closeAfterAction = closeAfterAction
            try:
                self.createMenuTree()
            except Exception as e:
                print(e)
            try:
                if self.currMenu != '':
                    self.setCurrMenu(self.currMenu)
                if self.currIndex == None:
                    if len(self.menuDict) > 0:
                        self.currIndex = [0]
            except Exception as e:
                print(e)
            try:
                # navigation
                self.env['bindings'][str([1, ['KEY_ESC']])] = 'TOGGLE_VMENU_MODE'
                self.env['bindings'][str([1, ['KEY_UP']])] = 'PREV_VMENU_ENTRY'
                self.env['bindings'][str([1, ['KEY_DOWN']])] = 'NEXT_VMENU_ENTRY'
                self.env['bindings'][str([1, ['KEY_SPACE']])] = 'CURR_VMENU_ENTRY'
                self.env['bindings'][str([1, ['KEY_LEFT']])] = 'DEC_LEVEL_VMENU'
                self.env['bindings'][str([1, ['KEY_RIGHT']])] = 'INC_LEVEL_VMENU'
                self.env['bindings'][str([1, ['KEY_ENTER']])] = 'EXEC_VMENU_ENTRY'
                # search
                self.env['bindings'][str([1, ['KEY_A']])] = 'SEARCH_A'
                self.env['bindings'][str([1, ['KEY_B']])] = 'SEARCH_B'
                self.env['bindings'][str([1, ['KEY_C']])] = 'SEARCH_C'
                self.env['bindings'][str([1, ['KEY_D']])] = 'SEARCH_D'
                self.env['bindings'][str([1, ['KEY_E']])] = 'SEARCH_E'
                self.env['bindings'][str([1, ['KEY_F']])] = 'SEARCH_F'
                self.env['bindings'][str([1, ['KEY_G']])] = 'SEARCH_G'
                self.env['bindings'][str([1, ['KEY_H']])] = 'SEARCH_H'
                self.env['bindings'][str([1, ['KEY_I']])] = 'SEARCH_I'
                self.env['bindings'][str([1, ['KEY_J']])] = 'SEARCH_J'
                self.env['bindings'][str([1, ['KEY_K']])] = 'SEARCH_K'
                self.env['bindings'][str([1, ['KEY_L']])] = 'SEARCH_L'
                self.env['bindings'][str([1, ['KEY_M']])] = 'SEARCH_M'
                self.env['bindings'][str([1, ['KEY_N']])] = 'SEARCH_N'
                self.env['bindings'][str([1, ['KEY_O']])] = 'SEARCH_O'
                self.env['bindings'][str([1, ['KEY_P']])] = 'SEARCH_P'
                self.env['bindings'][str([1, ['KEY_Q']])] = 'SEARCH_Q'
                self.env['bindings'][str([1, ['KEY_R']])] = 'SEARCH_R'
                self.env['bindings'][str([1, ['KEY_S']])] = 'SEARCH_S'
                self.env['bindings'][str([1, ['KEY_T']])] = 'SEARCH_T'
                self.env['bindings'][str([1, ['KEY_U']])] = 'SEARCH_U'
                self.env['bindings'][str([1, ['KEY_V']])] = 'SEARCH_V'
                self.env['bindings'][str([1, ['KEY_W']])] = 'SEARCH_W'
                self.env['bindings'][str([1, ['KEY_X']])] = 'SEARCH_X'
                self.env['bindings'][str([1, ['KEY_Y']])] = 'SEARCH_Y'
                self.env['bindings'][str([1, ['KEY_Z']])] = 'SEARCH_Z'
            except Exception as e:
                print(e)
        else:
            try:
                self.currIndex = None
                self.env['bindings'] = self.env['runtime']['settingsManager'].getBindingBackup()
            except:
                pass
    def createMenuTree(self, resetIndex = True):
        if resetIndex:
            self.currIndex = None
        menu = self.fs_tree_to_dict( self.defaultVMenuPath)
        if menu:
            self.menuDict = menu
        # index still valid?
        if self.currIndex != None:
            try:
                r = self.getValueByPath(self.menuDict, self.currIndex)
                if r == {}:
                    self.currIndex = None
            except:
                self.currIndex = None        
    def executeMenu(self):
        if self.currIndex == None:
            return
        try:
            command = self.getValueByPath(self.menuDict, self.currIndex)
            if not command == None:
                command.run()
                if self.closeAfterAction:
                    self.setActive(False)
        except Exception as e:
            try:
                self.incLevel()
                text = self.getCurrentEntry()
                self.env['runtime']['outputManager'].presentText(text, interrupt=True)                
            except:
                print(e)

    def incLevel(self):
        if self.currIndex == None:
            return False
        try:
            r = self.getValueByPath(self.menuDict, self.currIndex +[0])
            if r == {}:
                return False
        except:
            return False
        self.currIndex.append(0)
        return True
    def decLevel(self):
        if self.currIndex == None:
            return False
        if self.currMenu != '':
            if len(self.currIndex) <= 2:
                return False
        elif len(self.currIndex) == 1:
            return False
        self.currIndex = self.currIndex[:len(self.currIndex) - 1]
        return True
    def nextIndex(self):
        if self.currIndex == None:
            return False
        if self.currIndex[len(self.currIndex) - 1] + 1 >= len(self.getNestedByPath(self.menuDict, self.currIndex[:-1])):
           self.currIndex[len(self.currIndex) - 1] = 0 
        else:
            self.currIndex[len(self.currIndex) - 1] += 1
        return True
    def getCurrIndex(self):
        if self.currIndex == None:
            return 0        
        return self.currIndex[len(self.currIndex) - 1]
    def prevIndex(self):
        if self.currIndex == None:
            return False
        if self.currIndex[len(self.currIndex) - 1] == 0:
           self.currIndex[len(self.currIndex) - 1] = len(self.getNestedByPath(self.menuDict, self.currIndex[:-1])) - 1
        else:
            self.currIndex[len(self.currIndex) - 1] -= 1
        return True

    def getCurrentEntry(self):
        return self.getKeysByPath(self.menuDict, self.currIndex)[self.currIndex[-1]]
    def fs_tree_to_dict(self, path_):
        for root, dirs, files in os.walk(path_):
            tree = {d + ' ' + _('Menu'): self.fs_tree_to_dict(os.path.join(root, d)) for d in dirs if not d.startswith('__')}
            for f in files:
                try:
                    fileName, fileExtension = os.path.splitext(f)
                    fileName = fileName.split('/')[-1]
                    if fileName.startswith('__'):
                        continue
                    command = self.env['runtime']['commandManager'].loadFile(root + '/' + f)
                    tree.update({fileName + ' ' + _('Action'): command})
                except Exception as e:
                    print(e)
            return tree  # note we discontinue iteration trough os.walk
    def getNestedByPath(self, complete, path):
        path = path.copy()
        if path != []:
            index = list(complete.keys())[path[0]]
            nested = self.getNestedByPath(complete[index], path[1:])
            return nested
        else:
            return complete


    def getKeysByPath(self, complete, path):
        if not isinstance(complete, dict):
            return[]
        d = complete
        for i in path[:-1]:
            d = d[list(d.keys())[i]]
        return list(d.keys())

    def getValueByPath(self, complete, path):
        if not isinstance(complete, dict):
            return complete
        d = complete.copy()
        for i in path:
            d = d[list(d.keys())[i]]
        return d
