#!/usr/bin/env python

# Copyright (C) 2005 Osmo Salomaa
#
# This file is part of Gaupol.
#
# Gaupol 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.
#
# Gaupol 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 Gaupol; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


"""Gaupol start script"""


# Determination of correct paths for running from source directory vs. running
# installed adapted from Gazpacho by Lorenzo Gil Sanchez.


import gettext
import locale
import logging
import optparse
import os
import sys


# Set up logger.
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
logger = logging.getLogger()


def check_dependencies():
    """Check existance and versions of dependencies."""

    # Python
    if sys.version_info[:3] < (2, 4, 0):
        logger.critical('Python 2.4 or later is required to run Gaupol.')
        raise SystemExit(1)

    # GTK
    try:
        import gtk
        if gtk.pygtk_version < (2, 8, 0):
            raise ImportError
    except ImportError:
        logger.critical('PyGTK 2.8.0 or later is required to run Gaupol.')
        raise SystemExit(1)

    # Glade support in GTK
    try:
        import gtk.glade
    except ImportError:
        logger.critical('Glade support in PyGTK is required to run Gaupol')
        raise SystemExit(1)

def check_paths():
    """
    Determine paths of Gaupol files.

    Gaupol can be run from either the source directory or from install
    location after installation. Paths to use will be determined based on
    the gaupol.gtk.paths module.
    """
    current_dir = os.path.dirname(os.path.abspath(sys.argv[0]))

    if os.path.isfile(os.path.join(current_dir, 'data', 'gaupol.desktop')):
        prepare_source_run(current_dir)
    else:
        prefix = os.path.abspath(os.path.join(current_dir, '..'))
        prepare_installed_run(prefix)

def parse_options():
    """
    Parse given options and arguments.

    Return: options, arguments
    """
    usage = 'gaupol [options] [files]'
    description = \
        'Start Gaupol and open files. Options, except --help, are mostly ' \
        'useful only for developers and will only work (properly) when run ' \
        'in the source directory.'
    formatter = optparse.IndentedHelpFormatter(2, 42, None, True)
    parser = optparse.OptionParser(
        description=description,
        usage=usage,
        formatter=formatter
    )

    parser.add_option(
        '-t',
        '--no-translation',
        action='store_true',
        dest='no_translation',
        default=False,
        help='ignore possible translation (use english)'
    )

    parser.add_option(
        '-d',
        '--documentation',
        action='store_true',
        dest='documentation',
        default=False,
        help='view pydoc documentation of code'
    )

    parser.add_option(
        '-c',
        '--check',
        action='store_true',
        dest='pycheck',
        default=False,
        help='run pychecker on all code'
    )

    parser.add_option(
        '-p',
        '--profile',
        action='store',
        type='int',
        metavar='AMOUNT',
        dest='profile',
        default=0,
        help='profile with hotshot and output AMOUNT entries'
    )

    parser.add_option(
        '-x',
        '--execute',
        action='store',
        type='str',
        metavar='PATH',
        dest='execute',
        default='',
        help='execute gaupol module(s) for testing, ' \
             'PATH: file path, module path or "all"'
    )

    return parser.parse_args(sys.argv)

def prepare_eggs():
    """Move eggs to sys.path so that they are importable."""

    # PyEnchant uses the evil egg detouring import-unabler system since 1.1.4.
    # As an egg PyEnchant is called "pyenchant", as a module "enchant".
    try:
        import enchant
    except ImportError:
        try:
            import pkg_resources
            try:
                pkg_resources.require('pyenchant')
            except pkg_resources.DistributionNotFound:
                pass
        except ImportError:
            pass
    except enchant.Error:
        pass

def prepare_gettext():
    """Prepare internationalization using gettext."""

    import gtk.glade
    from gaupol.gtk.paths import LOCALE_DIR

    locale.setlocale(locale.LC_ALL, '')

    gettext.bindtextdomain('gaupol', LOCALE_DIR)
    gettext.textdomain('gaupol')

    gtk.glade.bindtextdomain('gaupol', LOCALE_DIR)
    gtk.glade.textdomain('gaupol')

def prepare_installed_run(prefix):
    """Prepare path information for running installed."""

    python_dir = 'python%d.%d' % sys.version_info[:2]
    lib_dir = os.path.join(prefix, 'lib', python_dir, 'site-packages')

    if lib_dir not in sys.path:
        sys.path.insert(0, lib_dir)

def prepare_source_run(prefix):
    """Prepare path information for running from source directory."""

    lib_dir = os.path.join(prefix, 'lib')
    if lib_dir not in sys.path:
        sys.path.insert(0, lib_dir)

    from gaupol.gtk import paths

    paths.DATA_DIR   = os.path.join(prefix, 'data'           )
    paths.GLADE_DIR  = os.path.join(prefix, 'data'  , 'glade')
    paths.ICON_DIR   = os.path.join(prefix, 'data'  , 'icons')
    paths.UI_DIR     = os.path.join(prefix, 'data'  , 'ui'   )
    paths.LOCALE_DIR = os.path.join(prefix, 'locale'         )

if __name__ == '__main__':

    opts, args = parse_options()

    check_dependencies()
    check_paths()
    if not opts.no_translation:
        prepare_gettext()
    prepare_eggs()

    # The world is not big enough for PyChecker and Psyco.
    if not opts.pycheck:
        try:
            import psyco
            psyco.profile()
        except ImportError:
            logger.info('Psyco not found.')

    # View documentation.
    if opts.documentation:
        import pydoc
        import threading
        from gaupol.base.util import wwwlib
        os.putenv('PYTHONPATH', 'lib')
        threading.Thread(target=pydoc.gui).start()
        wwwlib.open_url('http://localhost:7464/gaupol.html')

    # Run PyChecker.
    elif opts.pycheck:
        import pychecker.checker
        from gaupol.gtk import main
        main.main(args[1:])

    # Profile.
    elif opts.profile:
        import hotshot
        import hotshot.stats
        from gaupol.gtk import main
        profile = hotshot.Profile('gaupol.prof')
        profile.runcall(main.main, args[1:])
        profile.close()
        stats = hotshot.stats.load('gaupol.prof')
        stats.sort_stats('time', 'calls')
        stats.print_stats(opts.profile)
        os.remove('gaupol.prof')

    # Run tests.
    elif opts.execute:
        if opts.execute == 'all':
            for (dirpath, dirnames, filenames) in os.walk('lib'):
                for filename in filenames:
                    if filename.endswith('.py'):
                        path = os.path.join(dirpath, filename)
                        print path
                        execfile(path)
        else:
            path = opts.execute
            if not os.path.isfile(path):
                path = path.replace('.', os.sep) + '.py'
                path = os.path.join('lib', path)
            execfile(path)

    # Run normal.
    else:
        from gaupol.gtk import main
        main.main(args[1:])
