#!/usr/bin/env python

# Copyright (C) 2003, 2006, 2007 Brailcom, o.p.s.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# This program 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

import unittest
import time

from .client import PunctuationMode, CallbackType, SSIPClient, Scope, Speaker


class _SSIPClientTest(unittest.TestCase):
        
    def setUp(self):
        self._client = SSIPClient('test')
        self._client.set_language('en')
        self._client.set_rate(30)

    def tearDown(self):
        self._client.close()

class AutomaticTest(_SSIPClientTest):
    """A set of tests which may be evaluated automatically.

    Please put all tests which require a user to listen to their output to the
    VoiceTest below.

    """
    def test_callbacks(self):
        # TODO: This needs to be fixed. There is no guarantee that
        # the message will start in one second nor is there any
        # guarantee that it will start at all. It can be interrupted
        # by other applications etc. Also there is no guarantee that
        # the cancel will arrive on time and the end callback will be
        # received on time. Also the combination cancel/end does not have
        # to work as expected and SD and the interface can still be ok.
        # -- Hynek Hanke
        self._client.set_output_module('flite')
        called = {CallbackType.BEGIN: [],
                  CallbackType.CANCEL: [],
                  CallbackType.END: []}
        self._client.speak("This message should get interrupted.  It is "
                           "hopefully long enough to last more than 1 second.",
                           callback=lambda type: called[type].append('msg1'))
        self._client.speak("This second message should not be spoken at all.",
                           callback=lambda type: called[type].append('msg2'))
        time.sleep(1)
        self._client.cancel()
        self._client.speak("Hi.",
                           callback=lambda type: called[type].append('msg3'))
        # Wait for pending events...
        time.sleep(3)
        started, canceled, ended = [called[t] for t in (CallbackType.BEGIN,
                                                        CallbackType.CANCEL,
                                                        CallbackType.END)]
        assert started == ['msg1', 'msg3'] and ended == ['msg3'] and \
               'msg1' in canceled and 'msg2' in canceled and \
               'msg3' not in canceled, \
               (called,
                "This failure only indicates a possible error.  The test "
                "depends on proper timing and results may warry depending "
                "on the used output module and other conditions.  See the "
                "code of this test method if you want to investigate "
                "further.")

    

class VoiceTest(_SSIPClientTest):
    """This set of tests requires a user to listen to it.

    The success or failure of the tests defined here can not be detected
    automatically.

    """
    
    def test_escapes(self):
        c = self._client
        c.speak("Testing data escapes:")
        c.set_punctuation(PunctuationMode.ALL)
        c.speak(".")
        c.speak("Marker at the end.\r\n.\r\n")
        c.speak(".\r\nMarker at the beginning.")
    
    def test_voice_properties(self):
        c = self._client
        c.speak("Testing voice properties:")
        c.set_pitch(-100)
        c.speak("I am fat Billy")
        c.set_pitch(100)
        c.speak("I am slim Willy")
        c.set_pitch(0)
        c.set_rate(100)
        c.speak("I am quick Dick.")
        c.set_rate(-80)
        c.speak("I am slow Joe.")
        c.set_rate(0)
        c.set_pitch(100)
        c.set_volume(-50)
        c.speak("I am quiet Mariette.")
        c.set_volume(100)
        c.speak("I am noisy Daisy.")

    def test_other_commands(self):
        c = self._client
        c.speak("Testing other commands:")
        c.char("a")
        c.key("shift_b")
        c.sound_icon("empty")
        
    def test_lists(self):
         c = self._client
         for module in  c.list_output_modules():
             c.set_output_module(module)
             print("**", module)
             c.speak(module +"using default voice")
             for name, lang, variant in c.list_synthesis_voices():
                 print(" -", module, name, lang, variant)
                 c.set_synthesis_voice(name)
                 c.speak(module +" using voice "+ name)
             for name, lang, variant in c.list_synthesis_voices("fr"):
                 print(" -", module, name, lang, variant)
                 assert lang.startswith("fr")

if __name__ == '__main__':
    unittest.main()
