# Copyright 2006 Brailcom, o.p.s.
#
# Author: Tomas Cerha <cerha@brailcom.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

"""Provides an Orca speech server for Speech Dispatcher backend."""

__id__        = "$Id: $"
__version__   = "$Revision: $"
__date__      = "$Date: 2006-08-16 $"
__author__    = "Tomas Cerha <cerha@brailcom.org>"
__copyright__ = "Copyright (c) 2006 Brailcom, o.p.s."
__license__   = "LGPL"

import debug 
import speechserver
from orca_i18n import _

class SpeechServer(speechserver.SpeechServer):
    # See the parent class for documentation.
    _activeServers = {}
    
    def getFactoryName():
        return _("Speech Dispatcher")
    getFactoryName = staticmethod(getFactoryName)

    def _getActiveServers(cls):
        if not cls._activeServers:
            cls('default')
        return cls._activeServers
    _getActiveServers = classmethod(_getActiveServers)

    def getSpeechServers():
        return SpeechServer._getActiveServers().values()
    getSpeechServers = staticmethod(getSpeechServers)

    def getSpeechServer(info=None):
        servers = SpeechServer._getActiveServers()
        if info is not None:
            return servers.get(info)
        elif servers:
            return servers.values()[0]
        else:
            return None
    getSpeechServer = staticmethod(getSpeechServer)

    def shutdownActiveServers():
        for server in SpeechServer.getSpeechServers():
            server.shutdown()
    shutdownActiveServers = staticmethod(shutdownActiveServers)

    # *** Instance methods ***
    
    def __init__(self, id, language=None):
        self._id = id
        self._default_language = language
        try:
            self._init()
        except ImportError:
            debug.println(debug.LEVEL_SEVERE,
                          "Speech Dispatcher interface not installed.")
        else:
            self.__class__._activeServers[self.getInfo()] = self

    def _init(self):
        import speechd
        self._rate = 60
        self._pitch = 0
        self._client = speechd.SSIPClient('Orca', component=self._id)
        if self._default_language is not None:
            self._client.set_language(self._default_language)
        self._client.set_rate(self._rate)
        
    def getInfo(self):
        return ("Speech Dispatcher Server (%s)" % self._id, self._id)

    def getVoiceFamilies(self):
        from speechserver import VoiceFamily
        return (VoiceFamily({speechserver.VoiceFamily.NAME: 'Default',
                             speechserver.VoiceFamily.GENDER: VoiceFamily.MALE,
                             speechserver.VoiceFamily.LOCALE: 'en'}),
                #VoiceFamily({VoiceFamily.NAME: 'MALE2',
                #             VoiceFamily.GENDER: VoiceFamily.MALE,
                #             VoiceFamily.LOCALE: 'en'}),
                )

    def speak(self, text=None, acss=None, interrupt=True):
        if interrupt:
            self._client.cancel()
        if text:
            self._client.speak(text)
            
    def queueText(self, text="", acss=None):
        self.speak(text, acss, interrupt=False)

    def speakUtterances(self, list, acss=None, interrupt=True):
        if interrupt:
            self._client.cancel()
        for utterance in list:
            if utterance:
                self._client.speak(utterance)

    def sayAll(self, utteranceIterator, progressCallback):
        for context, acss in utteranceIterator:
            self.speak(context.utterance, acss, interrupt=False)

    def speakCharacter(self, character, acss=None):
        self._client.char(character)

    def increaseSpeechRate(self, step=5):
        newvalue = self._rate + step*2
        if newvalue <= 100:
            self._rate = newvalue
            self._client.set_rate(newvalue)

    def decreaseSpeechRate(self, step=5):
        newvalue = self._rate - step*2
        if newvalue >= -100:
            self._rate = newvalue
            self._client.set_rate(newvalue)

    def increaseSpeechPitch(self, step=0.5):
        newvalue = int(self._pitch + step*20)
        if newvalue <= 100:
            self._pitch = newvalue
            self._client.set_pitch(newvalue)

    def decreaseSpeechPitch(self, step=0.5):
        newvalue = int(self._pitch - step*20)
        if newvalue >= -100:
            self._pitch = newvalue
            self._client.set_pitch(newvalue)

    def stop(self):
        self._client.cancel()

    def shutdown(self):
        self._client.close()
        del self.__class__._activeServers[self.getInfo()]

    def reset(self, text=None, acss=None):
        self._client.cancel()
        self._client.close()
        self._init()


def _test():
    """Self test."""
    s = SpeechServer('test')
    s.speak("This is a Speech Dispatcher backend test.");

if __name__=="__main__":
    _test()
    
