# GNU Solfege - eartraining for GNOME
# Copyright (C) 2000, 2001, 2002, 2003  Tom Cato Amundsen
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import configureoutput
import errno, sys
import shutil

import soundcard, mpd
import lessonfile
import statistics
import os
import cfg, utils

class SolfegeApp(cfg.ConfigUtils):
    def __init__(self, argv, ui):
        cfg.ConfigUtils.__init__(self, 'solfege-app')
        self.m_argv = argv
        self.m_ui = ui
        self.check_rcfile()
        self.m_teachers = {}
        self.m_running_exercise = None
        self.lessonfile_manager = lessonfile.LessonFileManager()
        self.m_sound_init_exception = None
        self.setup_sound()
    def check_rcfile(self):
        if cfg.get_int("app/rcfileversion") > 1:
            cfg.drop_user_config()
    def setup_sound(self):
        if sys.platform == 'win32' and \
                    cfg.get_string("sound/type") == "sequencer-device":
            # just in case c:\home\solfegercX.Y is wrong
            cfg.set_string("sound/type", "winsynth")
        if '--no-sound' in self.m_argv \
           or cfg.get_string("sound/type") == "fake-synth":
            soundcard.initialise_using_fake_synth('--verbose-sound-init' in self.m_argv)
        elif cfg.get_string("sound/type") == "winsynth":
            try:
                soundcard.initialise_winsynth(cfg.get_int("sound/synth_number"),
                      verbose_init='--verbose-sound-init' in self.m_argv)
            except:
                cfg.set_int("sound/synth_number", 0)
                soundcard.initialise_winsynth(cfg.get_int("sound/synth_number"),
                      verbose_init='--verbose-sound-init' in self.m_argv)
        elif cfg.get_string("sound/type") == "external-midiplayer":
            soundcard.initialise_external_midiplayer(
                    cfg.get_string("sound/commandline"),
                    verbose_init='--verbose-sound-init' in self.m_argv)
        elif cfg.get_string("sound/type") == '':
            self.m_ui.display_error_message(
"""You should configure sound
from the 'Sound' page of
the preferences window.
""")
        elif cfg.get_string("sound/type") == "sequencer-device":
            if not configureoutput.HAVE_LINUX_AWE_VOICE_H and \
               cfg.get_string("sound/card_info") == "awe":
                       cfg.set_string("sound/card_info", "");
            try:
                soundcard.initialise_devicefile(
                             cfg.get_string("sound/device_file"),
                             cfg.get_int("sound/synth_number"),
                             cfg.get_string("sound/card_info"),
                             verbose_init='--verbose-sound-init' in self.m_argv)
            except (soundcard.SoundInitException, OSError), e:
                self.m_sound_init_exception = e
                soundcard.initialise_using_fake_synth(True)
    def display_sound_init_error_message(self, e):
        if isinstance(e, soundcard.SoundInitException):
            self.m_ui.display_error_message(
            """%s""" % e)
        elif e.errno == errno.EACCES:
            self.m_ui.display_error_message(
"""The sound init failed: %s
The errno EACCES indicates that you don't have write
permission to the device.""" % e)
        elif e.errno == errno.EBUSY:
            self.m_ui.display_error_message(
"""The sound init failed: %s
It seems like some other program is using the device. You
should try to quit that other program and restart Solfege."""
 % e)
        else:
            self.m_ui.display_error_message(
"""The sound init failed: %s
It seems like your kernel don't have the correct
sound modules installed, or that they are wrongly
configured. You can check the 'Sound' page in the
preferences window, but I don't think anything there
can help you. (This program need better sound init
code to handle situations like this.)"""
 % errno.errorcode[e.errno])
    def play_happy_sound(self):
        mpd.play_music(r"\staff\relative c'{c16 e g a}", 180, 8,
               cfg.get_int('config/preferred_instrument_velocity'))
    def play_sad_sound(self):
        mpd.play_music(r"\staff\relative c'{<c,,8 cis>", 80, 58,
               cfg.get_int('config/preferred_instrument_velocity'))
    def please_help_me(self):
        if self.m_ui.m_viewer != 'docviewer':
            self.handle_href('%s-help.html' % self.m_ui.m_viewer)
    def handle_href(self, href, display_docfile_set_adj=1):
        if self.m_ui.m_viewer:
            if display_docfile_set_adj == 1:
                # we get here when we click on urls, because we want to
                # save the place in the current document when we load the
                # new one. We don't get here if handle_href is called from
                # history_back.
                self.m_ui.m_history.set_adj_of_current(self.m_ui.box_dict['docviewer'].get_vadjustment().value)
        protocol, action, fn, anchor, lessoncollection, lessonfile, config = \
           utils.parse_url(href)
        if protocol == None:
            self.m_ui.display_docfile(fn, anchor)
        elif protocol == 'solfege':
            if action == 'all-lessonfiles':
                self.m_ui.display_html(self.lessonfile_manager.m_htmldoc)
                self.m_ui.m_history.add('solfege:all-lessonfiles')
            else:
                if lessonfile:
                    filepath = os.path.join(self.get_string('lessoncollections/%s' %lessoncollection), lessonfile)
                    if not os.path.isfile(filepath):
                        self.m_ui.display_error_message("Lessonfile not found:\n%s" % filepath)
                        return
                if (self.m_ui.m_viewer == 'docviewer'
                    and self.m_running_exercise != None
                    and self.m_running_exercise != fn) or \
                   (self.m_ui.m_viewer != 'docviewer'):
                       self.m_ui.box_dict[self.m_running_exercise].on_end_practise()
                       self.m_running_exercise = None
                _old_viewer = self.m_ui.m_viewer
                if not self.m_teachers.has_key(fn):
                    n = utils.exercise_name_to_module_name(fn)
                    exec("import %s" % n)
                    self.m_teachers[fn] = locals()[n].Teacher(fn, self)
                    # if we don't have a teacher, then the Gui has not been
                    # initialized either
                    self.m_ui.initialise_exercise(self.m_teachers[fn])
                    self.m_teachers[fn].g_view = self.m_ui.box_dict[fn]
                self.m_teachers[fn].configure_exercise(lessoncollection, lessonfile, config)
                self.m_ui.activate_exercise(href)
                if not (_old_viewer == 'docviewer'
                        and self.m_running_exercise != None
                        and self.m_running_exercise == fn):
                    self.m_ui.box_dict[self.m_ui.m_viewer].on_start_practise()
                self.m_running_exercise = fn
        elif protocol == 'http':
            os.system(self.get_string("config/web_browser") % href)
        elif protocol == 'mailto':
            os.system(self.get_string("config/mua") % href)
        else:
            print "unknown link type", protocol
    def quit_program(self):
        cfg.sync()
        for k in self.m_teachers.keys():
            if self.m_teachers[k].m_statistics is not None:
                self.m_teachers[k].m_statistics.save_data()
        if soundcard.synth:
            soundcard.synth.close()


