#!/usr/bin/env python
# Copyright (C) 2006, Red Hat, Inc.
# Copyright (C) 2009, One Laptop Per Child Association Inc
#
# 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import os
import sys
import time
import subprocess
import shutil

if os.environ.get('SUGAR_LOGGER_LEVEL', '') == 'debug':
    print '%r STARTUP: Starting the shell' % time.time()
    sys.stdout.flush()

import gettext
import logging

import gconf
import gtk
import gobject
import dbus.glib
import wnck

try:
    import xklavier
except ImportError:
    logging.debug('Could not load xklavier for keyboard configuration')

gtk.gdk.threads_init()
dbus.glib.threads_init()

def cleanup_logs(logs_dir):
    """Clean up the log directory, moving old logs into a numbered backup
    directory.  We only keep `_MAX_BACKUP_DIRS` of these backup directories
    around; the rest are removed."""
    if not os.path.isdir(logs_dir):
        os.makedirs(logs_dir)

    backup_logs = []
    backup_dirs = []
    for f in os.listdir(logs_dir):
        path = os.path.join(logs_dir, f)
        if os.path.isfile(path):
            backup_logs.append(f)
        elif os.path.isdir(path):
            backup_dirs.append(path)

    if len(backup_dirs) > 3:
        backup_dirs.sort()
        root = backup_dirs[0]
        for f in os.listdir(root):
            os.remove(os.path.join(root, f))
        os.rmdir(root)

    if len(backup_logs) > 0:
        name = str(int(time.time()))
        backup_dir = os.path.join(logs_dir, name)
        os.mkdir(backup_dir)
        for log in backup_logs:
            source_path = os.path.join(logs_dir, log)
            dest_path = os.path.join(backup_dir, log)
            os.rename(source_path, dest_path)

def start_ui_service():
    from jarabe.view.service import UIService

    ui_service = UIService()
    ui_service.start()

def start_session_manager():
    from jarabe.model.session import get_session_manager

    session_manager = get_session_manager()
    session_manager.start()

def unfreeze_dcon_cb():
    logging.debug('STARTUP: unfreeze_dcon_cb')
    from jarabe.model import screen

    screen.set_dcon_freeze(0)

def setup_frame_cb():
    logging.debug('STARTUP: setup_frame_cb')
    from jarabe import frame
    frame.get_view()

def setup_keyhandler_cb():
    logging.debug('STARTUP: setup_keyhandler_cb')
    from jarabe.view import keyhandler
    from jarabe import frame
    keyhandler.setup(frame.get_view())

def setup_journal_cb():
    logging.debug('STARTUP: setup_journal_cb')
    from jarabe.journal import journalactivity
    journalactivity.start()

def show_software_updates_cb():
    logging.debug('STARTUP: show_software_updates_cb')
    if os.path.isfile(os.path.expanduser('~/.sugar-update')):
        from jarabe.desktop import homewindow
        home_window = homewindow.get_instance()
        home_window.get_home_box().show_software_updates_alert()

def setup_notification_service_cb():
    from jarabe.model import notifications
    notifications.init()

def setup_file_transfer_cb():
    from jarabe.model import filetransfer
    filetransfer.init()

def setup_keyboard_cb():
    logging.debug('STARTUP: setup_keyboard_cb')

    gconf_client = gconf.client_get_default()

    try:
        display = gtk.gdk.display_get_default()
        if display is not None:
            engine = xklavier.Engine(display)
        else:
            logging.debug('setup_keyboard_cb: Could not get default display.')
            return

        configrec = xklavier.ConfigRec()
        configrec.get_from_server(engine)

        layouts = gconf_client.get_list(\
            '/desktop/sugar/peripherals/keyboard/layouts', gconf.VALUE_STRING)
        layouts_list = []
        variants_list = []
        for layout in layouts:
            layouts_list.append(layout.split('(')[0])
            variants_list.append(layout.split('(')[1][:-1])

        if layouts_list is not None and layouts_list is not [] \
                and variants_list is not None and variants_list is not []:
            configrec.set_layouts(layouts_list)
            configrec.set_variants(variants_list)

        model = gconf_client.get_string(\
            '/desktop/sugar/peripherals/keyboard/model')
        if model:
            configrec.set_model(model)

        options = gconf_client.get_list(\
            '/desktop/sugar/peripherals/keyboard/options', gconf.VALUE_STRING)
        if options is not [] and options is not None:
            configrec.set_options(options)

        configrec.activate(engine)
    except Exception:
        logging.exception('Error during keyboard configuration')

def setup_window_manager():
    logging.debug('STARTUP: window_manager')

    # have to reset cursor(metacity sets it on startup)
    if subprocess.call('echo $DISPLAY; xsetroot -cursor_name left_ptr', shell=True):
        logging.warning('Can not reset cursor')

    if subprocess.call('metacity-message disable-keybindings',
            shell=True):
        logging.warning('Can not disable metacity keybindings')

def bootstrap():
    setup_window_manager()

    from jarabe.view import launcher
    launcher.setup()

    gobject.idle_add(setup_frame_cb)
    gobject.idle_add(setup_keyhandler_cb)
    gobject.idle_add(setup_journal_cb)
    gobject.idle_add(setup_notification_service_cb)
    gobject.idle_add(setup_file_transfer_cb)
    gobject.idle_add(show_software_updates_cb)

    if sys.modules.has_key('xklavier'):
        gobject.idle_add(setup_keyboard_cb)

def set_fonts():
    client = gconf.client_get_default()
    face = client.get_string('/desktop/sugar/font/default_face')
    size = client.get_float('/desktop/sugar/font/default_size')
    settings = gtk.settings_get_default()
    settings.set_property("gtk-font-name", "%s %f" % (face, size))

def main():
    try:
        from sugar import env
        # Remove temporary files. See http://bugs.sugarlabs.org/ticket/1876
        data_dir = os.path.join(env.get_profile_path(), 'data')
        shutil.rmtree(data_dir, ignore_errors=True)
        os.makedirs(data_dir)
        cleanup_logs(env.get_logs_path())
    except OSError, e:
        # logs cleanup is not critical; it should not prevent sugar from
        # starting if (for example) the disk is full or read-only.
        print 'logs cleanup failed: %s' % e

    from sugar import logger
    # NOTE: This needs to happen so early because some modules register translatable
    # strings in the module scope.
    from jarabe import config
    gettext.bindtextdomain('sugar', config.locale_path)
    gettext.bindtextdomain('sugar-toolkit', config.locale_path)
    gettext.textdomain('sugar')

    from jarabe.desktop import homewindow
    from jarabe.model import sound
    from jarabe import intro

    logger.start('shell')

    client = gconf.client_get_default()
    client.set_string('/apps/metacity/general/mouse_button_modifier',
                      'disabled')

    timezone = client.get_string('/desktop/sugar/date/timezone')
    if timezone is not None and timezone:
        os.environ['TZ'] = timezone

    set_fonts()

    # this must be added early, so that it executes and unfreezes the screen
    # even when we initially get blocked on the intro screen
    gobject.idle_add(unfreeze_dcon_cb)

    intro.check_profile()

    start_ui_service()
    start_session_manager()

    sound.restore()

    sys.path.append(config.ext_path)

    icons_path = os.path.join(config.data_path, 'icons')
    gtk.icon_theme_get_default().append_search_path(icons_path)

    # open homewindow before window_manager to let desktop appear fast
    home_window = homewindow.get_instance()
    home_window.show()

    screen = wnck.screen_get_default()
    screen.connect('window-manager-changed', __window_manager_changed_cb)

    try:
        gtk.main()
    except KeyboardInterrupt:
        print 'Ctrl+C pressed, exiting...'

def __window_manager_changed_cb(screen):
    wm_name = screen.get_window_manager_name()
    if wm_name is not None:
        screen.disconnect_by_func(__window_manager_changed_cb)
        bootstrap()

main()
