# -*- coding: utf-8 -*-
#
# Graphical interface for the eSpeak speech synthesizer
#
# Copyright © 2009-2012 Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com>
# Copyright © 2009 Joe Burmeister <joe.a.burmeister@googlemail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import gtk
import gobject

class VoiceBox:

    AUTODETECT_LABEL = _("Detect automatically")
    SEPARATOR_KEY = 'separator'

    _gui_object = None
    _language_manager = None

    def __init__(self, gui_object, language_manager):
        self._gui_object = gui_object
        self._language_manager = language_manager
        self._initialize()

    def _initialize(self):
        store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
        self._gui_object.set_model(store)
        
        languages_autodetect = self._language_manager.get_languages(autodetect=True)
        languages_other = self._language_manager.get_languages(autodetect=False)
        
        if self._language_manager.autodetect_supported:
	        store.append([self.AUTODETECT_LABEL, 'autodetect'])
        if languages_autodetect:
	        store.append(['Available Languages', self.SEPARATOR_KEY])
        for voice in languages_autodetect:
            store.append([voice.name.capitalize(), voice.identifier])
        if languages_other and self._language_manager.autodetect_supported:
	        store.append(['Languages without auto-detection', self.SEPARATOR_KEY])
        for voice in languages_other:
            store.append([voice.name.capitalize(), voice.identifier])
    
        cellr = gtk.CellRendererText()
        self._gui_object.pack_start(cellr)
        self._gui_object.add_attribute(cellr, 'text', 0)
        self._gui_object.set_row_separator_func(lambda model, _iter:
            model.get_value(_iter, 1) == self.SEPARATOR_KEY)
        self._gui_object.connect('key-press-event', self._on_voicebox_keypress)

    def get_model(self):
        return self._gui_object.get_model()

    def set_voice(self, voice):
        values = [x[1] for x in self._gui_object.get_model()]
        try:
            self._gui_object.set_active(values.index(voice))
        except ValueError:
            print "Voice \"%s\" is not available." % voice
    
    def get_voice(self):
        """
        Returns a tuple (voice_name, voice_id).
        """
        store = self._gui_object.get_model()
        active = store[self._gui_object.get_active()]
        return (active[0], active[1])
    
    def set_guess(self, guess):
        store = self._gui_object.get_model()
        store[0][0] = self.AUTODETECT_LABEL if not guess.good else \
            '%s [%s]' % (self.AUTODETECT_LABEL, guess.get_display_name())
    
    def _on_voicebox_keypress(self, voicebox, event):
        """ Iterates the selection over the languages starting with the
            typed character. """
        position = self._gui_object.get_active()
        store = self._gui_object.get_model()
        letter = event.string.upper()
        if not letter:
            return
        self._gui_object.set_active(
           	 self._find_voice_position(start=letter, from_position=position+1))
    
    def _find_voice_position(self, start=None, complete=None, from_position=0):
        """ Returns the position of the first voice whose name matches
            the value provided in `complete` or starts with the character
            given in `start`.
            
            The optional parameter `from_position' sets the position from
            which _find_voice_position should start searching. If it is
            different from zero, _find_voice_position will start searching
            again from the start, until completing the circle (reaching the
            value in from_position).
            
            Only one of `start` and `complete` can be used at the same time. """
        
        store = self._gui_object.get_model()
        needle = start or complete
        values = [x[0] if x[1] != self.SEPARATOR_KEY else ' ' for x in store]
        if start:
            values = [value[0] for value in values]
        try:
            return values[from_position:].index(needle) + from_position
        except ValueError:
        	try:
        		return values[:from_position].index(needle)
        	except ValueError:
	            return -1
