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

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

from fenrirscreenreader.core import debug
from fenrirscreenreader.utils import line_utils
import string, time, re

class outputManager():
    def __init__(self):
        self.lastEcho = ''

    def initialize(self, environment):
        self.env = environment
        self.env['runtime']['settingsManager'].loadDriver(
            self.env['runtime']['settingsManager'].getSetting('speech', 'driver'), 'speechDriver')
        self.env['runtime']['settingsManager'].loadDriver(
            self.env['runtime']['settingsManager'].getSetting('sound', 'driver'), 'soundDriver')

    def shutdown(self):
        self.env['runtime']['settingsManager'].shutdownDriver('soundDriver')
        self.env['runtime']['settingsManager'].shutdownDriver('speechDriver')
        
    def presentText(self, text, interrupt=True, soundIcon='', ignorePunctuation=False, announceCapital=False, flush=True):
        if text == '':
            return
        if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'readNumbersAsDigits') and len(text.strip()) > 1:
            text = re.sub(r"(\d)", r"\1 ", text).rstrip()
        self.env['runtime']['debug'].writeDebugOut("presentText:\nsoundIcon:'"+soundIcon+"'\nText:\n" + text, debug.debugLevel.INFO)
        if self.playSoundIcon(soundIcon, interrupt):
            self.env['runtime']['debug'].writeDebugOut("soundIcon found", debug.debugLevel.INFO)
            return
        if (len(text) > 1) and (text.strip(string.whitespace) == ''):
            return
        toAnnounceCapital = announceCapital and text[0].isupper()
        if toAnnounceCapital:
            if self.playSoundIcon('capital', False):
                toAnnounceCapital = False
        self.lastEcho = text
        self.speakText(text, interrupt, ignorePunctuation, toAnnounceCapital)

    def getLastEcho(self):
        return self.lastEcho

    def speakText(self, text, interrupt=True, ignorePunctuation=False, announceCapital=False):
        if not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'):
            self.env['runtime']['debug'].writeDebugOut("Speech disabled in outputManager.speakText", debug.debugLevel.INFO)
            return
        if self.env['runtime']['speechDriver'] == None:
            self.env['runtime']['debug'].writeDebugOut("No speechDriver in outputManager.speakText", debug.debugLevel.ERROR)
            return
        if interrupt:
            self.interruptOutput()
        try:
            self.env['runtime']['speechDriver'].setLanguage(self.env['runtime']['settingsManager'].getSetting('speech', 'language'))
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("setting speech language in outputManager.speakText", debug.debugLevel.ERROR)
            self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)
        
        try:
            self.env['runtime']['speechDriver'].setVoice(self.env['runtime']['settingsManager'].getSetting('speech', 'voice'))
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("Error while setting speech voice in outputManager.speakText", debug.debugLevel.ERROR)
            self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)        
        
        try:
            if announceCapital:
                self.env['runtime']['speechDriver'].setPitch(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'capitalPitch'))            
            else:
                self.env['runtime']['speechDriver'].setPitch(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'pitch'))
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("setting speech pitch in outputManager.speakText", debug.debugLevel.ERROR)
            self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)            
        
        try:
            self.env['runtime']['speechDriver'].setRate(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'rate'))
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("setting speech rate in outputManager.speakText", debug.debugLevel.ERROR)
            self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)            
        
        try:
            self.env['runtime']['speechDriver'].setModule(self.env['runtime']['settingsManager'].getSetting('speech', 'module'))
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("setting speech module in outputManager.speakText", debug.debugLevel.ERROR)
            self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)

        try:
            self.env['runtime']['speechDriver'].setVolume(self.env['runtime']['settingsManager'].getSettingAsFloat('speech', 'volume'))
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("setting speech volume in outputManager.speakText ", debug.debugLevel.ERROR)
            self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)            
        
        try:
            if self.env['runtime']['settingsManager'].getSettingAsBool('general', 'newLinePause'):        
                cleanText = text.replace('\n', ' , ')
            else:
                cleanText = text.replace('\n', ' ')

            cleanText = self.env['runtime']['textManager'].replaceHeadLines(cleanText)        
            cleanText = self.env['runtime']['punctuationManager'].proceedPunctuation(cleanText, ignorePunctuation) 
            cleanText = re.sub(' +$', ' ', cleanText)            
            self.env['runtime']['speechDriver'].speak(cleanText)
            self.env['runtime']['debug'].writeDebugOut("Speak: "+ cleanText, debug.debugLevel.INFO)                
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("\"speak\" in outputManager.speakText ", debug.debugLevel.ERROR)
            self.env['runtime']['debug'].writeDebugOut(str(e), debug.debugLevel.ERROR)            

    def interruptOutput(self):
        try:
            self.env['runtime']['speechDriver'].cancel()
            self.env['runtime']['debug'].writeDebugOut("Interrupt speech", debug.debugLevel.INFO)
        except:
            pass

    def playSoundIcon(self, soundIcon='', interrupt=True):
        if soundIcon == '':
            return False
        soundIcon = soundIcon.upper()
        if not self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'):
            self.env['runtime']['debug'].writeDebugOut("Sound disabled in outputManager.playSoundIcon", debug.debugLevel.INFO)
            return False  

        try:
            e = self.env['soundIcons'][soundIcon]
        except:
            self.env['runtime']['debug'].writeDebugOut("SoundIcon doesnt exist: " + soundIcon, debug.debugLevel.WARNING)
            return False

        if self.env['runtime']['soundDriver'] == None:
            self.env['runtime']['debug'].writeDebugOut("No soundDriver in outputManager.playSoundIcon:  soundDriver not loaded", debug.debugLevel.ERROR)
            return False

        try:
            self.env['runtime']['soundDriver'].setVolume(self.env['runtime']['settingsManager'].getSettingAsFloat('sound', 'volume'))
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::setVolume: " + str(e), debug.debugLevel.ERROR)

        try:
            self.env['runtime']['soundDriver'].playSoundFile(self.env['soundIcons'][soundIcon], interrupt)
            return True
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::playSoundFile: " + str(e), debug.debugLevel.ERROR)
            return False

        return False

    def playFrequence(self, frequence, duration, interrupt=True):
        if not self.env['runtime']['settingsManager'].getSettingAsBool('sound', 'enabled'):
            self.env['runtime']['debug'].writeDebugOut("Sound disabled in outputManager.playFrequence", debug.debugLevel.INFO)
            return False

        if frequence < 1 or frequence > 20000:
            self.env['runtime']['debug'].writeDebugOut("outputManager.playFrequence::Filefrequence is out of range:" + str(frequence), debug.debugLevel.INFO)
            return False

        if self.env['runtime']['soundDriver'] == None:
            self.env['runtime']['debug'].writeDebugOut("No soundDriver in outputManager.playFrequence: soundDriver not loaded", debug.debugLevel.ERROR)
            return False

        try:
            self.env['runtime']['soundDriver'].setVolume(self.env['runtime']['settingsManager'].getSettingAsFloat('sound', 'volume'))
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::setVolume: " + str(e), debug.debugLevel.ERROR)
        adjustVolume = 0.0
        try:
            adjustVolume = 1.0 - (frequence / 20000)
        except:
            pass
        if adjustVolume > 9.0:
            adjustVolume = 9.0

        try:
            self.env['runtime']['soundDriver'].playFrequence(frequence, duration, adjustVolume, interrupt)
            return True
        except Exception as e:
            self.env['runtime']['debug'].writeDebugOut("outputManager.playSoundIcon::playSoundFile: " + str(e), debug.debugLevel.ERROR)
            return False

        return False

    def tempDisableSpeech(self):
        if self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled'): 
            self.presentText(_("speech temporary disabled"), soundIcon='SpeechOff', interrupt=True)
            self.env['commandBuffer']['enableSpeechOnKeypress'] = True
            self.env['runtime']['settingsManager'].setSetting('speech', 'enabled', str(not self.env['runtime']['settingsManager'].getSettingAsBool('speech', 'enabled')))
            self.interruptOutput()

    def announceActiveCursor(self, interrupt_p=False):
        if self.env['runtime']['cursorManager'].isReviewMode():
            self.presentText(' review cursor ', interrupt=interrupt_p)
        else:
            self.presentText(' text cursor ', interrupt=interrupt_p)
