#!/usr/bin/python
# -*- coding: utf-8 -*-
# Elisa - Home multimedia server
# Copyright (C) 2007 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 2.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Elisa with Fluendo's plugins.
#
# The GPL part of Elisa is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Elisa" in the root directory of this distribution package
# for details on that license.

"""
Initializing and running Elisa.
"""

import sys
import os
import site

# FIXME: horrible hack to work around the fact that when elisa.exe is built
# with py2exe the __file__ module variable is not defined.
import inspect
__file__ = os.path.abspath(inspect.currentframe().f_code.co_filename)


def _is_uninstalled():
    # Are we running Elisa development version (uninstalled)?
    script_dir = os.path.dirname(os.path.abspath(__file__))
    base_path = os.path.normpath(os.path.join(script_dir, '..'))
    return (os.path.basename(base_path) == 'elisa-core')


def _get_prefix():
    # Get the root path of the development version (uninstalled), or that of
    # the Windows installed version.
    checkout_path = os.environ.get('ELISA_BRANCH_PATH')
    if checkout_path:
        return checkout_path
    elif sys.argv[0].endswith('elisa.exe'):
        # Windows specific
        return sys.prefix
    else:
        # The script is elisa-core/bin/elisa
        file_path = os.path.abspath(__file__)
        core_path = os.path.dirname(file_path)
        prefix = os.path.join(core_path, '..', '..')
        return os.path.normpath(prefix)


def _fix_path():
    """
    When running the development version (uninstalled), add the elisa-core and
    elisa-plugins directories to the path.
    """
    prefix = _get_prefix()
    elisa_plugins = os.path.join(prefix, 'elisa-plugins')
    elisa_core = os.path.join(prefix, 'elisa-core')

    if os.path.exists(elisa_core):
        sys.path.insert(0, elisa_core)

    if os.path.exists(elisa_plugins):
        sys.path.insert(1, elisa_plugins)


def _add_site_dirs():
    """
    Add the directory containing locally installed plugin eggs to the path.
    """
    config_dir = os.path.join(os.path.expanduser('~'), '.elisa-0.5')
    local_plugins_dir = os.path.join(config_dir, 'plugins')
    if os.path.isdir(local_plugins_dir):
        path = sys.path
        sys.path = []
        site.addsitedir(local_plugins_dir)
        sys.path.extend(path)


def _setup_reactor():
    # Install the glib2 Twisted reactor
    from twisted.internet import glib2reactor
    glib2reactor.install()


def _setup_gstreamer():
    import pygst
    pygst.require('0.10')


def _init_logging(log_to_file):
    from elisa.core import log
    log.init(log_to_file)
    log.logTwisted()


def _parse_options(args):
    from twisted.python import usage
    from elisa.core.options import Options

    options = Options()

    try:
        options.parseOptions(args[1:])
    except usage.UsageError, errortext:
        print '%s: %s' % (args[0], errortext)
        print '%s: Try --help for usage details.' % (args[0])
        sys.exit(1)

    return options


def _start_reactor_with_ipython():
    from twisted.internet import reactor

    reactor.simulate()
    reactor.startRunning()
    try:
        import IPython
        IPython.Shell.IPShellGTK([], locals()).mainloop()
    except ImportError:
        print "You need to install IPython in order to open an interactive " \
              "shell."


def _build_splash_screen():
    from elisa.core.utils.splash_screen import SplashScreen
    if SplashScreen:
        return SplashScreen()
    else:
        return None


def _start_reactor():
    from twisted.internet import reactor
    reactor.run()


def _start_application(options, splash):
    from elisa.core.application import Application
    from elisa.core import common
    from twisted.internet import reactor

    app = Application(options['config_file'],
                      show_tracebacks=options['tracebacks'], splash=splash)
    common.set_application(app)

    def initialize_done(result):
        return app.start()

    def initialize_failure(failure):
        print 'Elisa failed to initialize:', failure

    dfr = app.initialize()
    dfr.addCallbacks(initialize_done, initialize_failure)

    # this could lead to an ugly "'NoneType' object is
    # unsubscriptable" in twisted, when the reactor gets killed from
    # the outside. Bug is reported and fixed in twisted-svn/trunk:
    # http://twistedmatrix.com/trac/ticket/2265
    reactor.addSystemEventTrigger('before', 'shutdown', app.stop)


def _setup_environment():
    import platform
    system = platform.system()

    # 'Fix' the PYTHONPATH. We need to do that:
    #   - for the development version (uninstalled)
    #   - for the Windows installed version (run from elisa.exe)
    if _is_uninstalled() or system == 'Windows':
        _fix_path()

    if system == 'Windows':
        from mswin32 import win_set_env
        win_set_env.set_runtime_env()

    _add_site_dirs()

    # FIXME: importing pkg_resources is needed just after new site dirs
    #        have been added so that the right egg distributions are
    #        chosen when importing elisa.core and the plugins
    import pkg_resources


def main():
    _setup_environment()

    # Done as early as possible
    _setup_reactor()

    _setup_gstreamer()

    options = _parse_options(sys.argv)
    if not options['headless']:
        splash = _build_splash_screen()
    else:
        splash = None

    if options['log']:
        _init_logging(True)
    else:
        _init_logging(False)

    from twisted.internet import reactor
    
    # First go to the main loop so that the splash screen can show up
    reactor.callLater(0.01, _start_application, options, splash=splash)

    if options['shell']:
        _start_reactor_with_ipython()
    else:
        _start_reactor()


if __name__ == '__main__':
    main()
