#!/usr/bin/env python
#
# This file is part of Canola
# Copyright (C) 2007-2009 Instituto Nokia de Tecnologia
# Contact: Renato Chencarek <renato.chencarek@openbossa.org>
#          Eduardo Lima (Etrunko) <eduardo.lima@openbossa.org>
#
# 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.
#

import os
import sys
import ecore
import ecore.evas
import evas
from optparse import OptionParser

import terra.core.log as log
from terra.core.manager import Manager
from terra.core.plugin_prefs import PluginPrefs

pjoin = os.path.join
pexists = os.path.exists
pisfile = os.path.isfile

mger = None
home_path = os.path.expanduser("~")
cnl_base_path = pjoin(home_path, ".canola")
cnl_theme_path = pjoin(cnl_base_path, "theme")
cnl_prefs_path = pjoin(cnl_base_path, "prefs")

default_theme = pjoin(cnl_theme_path, "theme.edj")
default_conf_theme = pjoin(cnl_theme_path, "conf.edj")
default_font_config = pjoin(cnl_base_path, "fonts.conf")
default_config_file = os.getenv("CNL_CONFIG_FILE",
                                pjoin(os.sep, "etc", "canola.conf"))

def acquire_dbus_service_name():
    import dbus
    bus = dbus.SessionBus()
    bo = bus.get_object("org.freedesktop.DBus",
                        "/org/freedesktop/DBus",
                        introspect=False)
    bi = dbus.Interface(bo, "org.freedesktop.DBus")
    try:
        ret = bi.RequestName("org.openbossa.canola", dbus.UInt32(0))
    except Exception, e:
        log.error("error [%s] while acquiring D-Bus service name for Canola, "
                  "exiting ...", e, exc_info=True)
        sys.exit(1)
    else:
        if not ret:
            log.error("unknown error while acquiring D-Bus service name for "
                      "Canola, exiting ...")
            sys.exit(1)

def setup_etk():
    global default_conf_theme
    # XXX: fallback to local theme directory during development
    if not pisfile(default_conf_theme):
        default_conf_theme = "data/etk-themes/default/default.edj"
    import etk
    etk.theme_widget_set_from_path(default_conf_theme)

def setup_dot_canola():
    version = pjoin(cnl_base_path, "version")
    version_check = "2.0"
    version_str = "2.0.0"

    def init_dot_canola():
        os.makedirs(cnl_base_path, 0700)
        open(version, "w").write(version_str)

    def remove_and_init():
        import shutil
        shutil.rmtree(cnl_base_path)
        init_dot_canola()

    if not pexists(cnl_base_path):
        init_dot_canola()
        return

    if not pexists(version): # Canola 1.X
        remove_and_init()
        return

    ver = open(version, "r").readline().strip()
    if not ver.startswith(version_check):  # not Canola 2.0
        remove_and_init()
        return

def check_prefs():
    system_props = mger.get_class("SystemProperties")() # XXX

    if not pexists(cnl_prefs_path):
        os.makedirs(cnl_prefs_path, 0700)

    settings = PluginPrefs("settings")
    scanned_folders = PluginPrefs("scanned_folders")
    default_dirs = system_props.DEFAULT_DIRS

    def setup_paths_if_required(pref, key):
        if pref.get(key, None) is None:
            v = default_dirs.get(key, [])
            lst = []
            for p in v:
                if pexists(p):
                    lst.append(p)
            if lst:
                pref[key] = lst

    for k in ("audio", "photo", "video"):
        for s in (settings, scanned_folders):
            setup_paths_if_required(s, k)

    if not settings.get("cover_path", None):
        cover = pjoin(cnl_base_path, "covers")
        settings["cover_path"] = cover

    if not settings.get("download_path", None):
        dd = system_props.download_dirs_get()
        for dpath, _ in dd:
            if not system_props.is_mounted(os.path.dirname(dpath)):
                continue
            settings["download_path"] = dpath
            break
        else:  # if nothing is mounted, just default to first choice
            settings["download_path"] = dd[0][0]

    temp_dir = settings.get("temp_dir", None)

    if temp_dir is None:
        temp_dir = pjoin(cnl_base_path, "tmp")
        settings["temp_dir"] = temp_dir

    if not pexists(temp_dir):
        os.makedirs(temp_dir, 0700)

    settings.save()
    scanned_folders.save()

def check_themes():
    themes_dir = mger.terra_config.themes_dir
    if not os.path.isabs(themes_dir):
        themes_dir = pjoin(os.getcwd(), themes_dir)

    if not pexists(cnl_theme_path):
        os.makedirs(cnl_theme_path, 0700)

    if not pexists(default_theme):
        if os.path.lexists(default_theme):
            os.unlink(default_theme)
        os.symlink(pjoin(themes_dir, "default.edj"), default_theme)

    if not pexists(default_conf_theme):
        if os.path.lexists(default_conf_theme):
            os.unlink(default_conf_theme)
        os.symlink(pjoin(themes_dir, "conf.edj"), default_conf_theme)



def apply_font_config(path):
    if not pexists(path):
        return
    import edje
    from ConfigParser import ConfigParser
    cp = ConfigParser()
    cp.read(path)
    for text_class in cp.sections():
        font = cp.get(text_class, "font")
        size = cp.getint(text_class, "size")
        edje.text_class_set(text_class, font, size)


def parse_geometry(option, opt, value, parser):
    try:
        w, h = value.split("x")
        w = int(w)
        h = int(h)
    except Exception, e:
        raise optparse.OptionValueError("Invalid format for %s" % option)
    parser.values.geometry = (w, h)


def process_cmdline():
    usage = "usage: %prog [options]"
    op = OptionParser(usage=usage)

    engines = list(ecore.evas.engines_get())
    if "buffer" in engines:
        engines.remove("buffer")
    engines.append("xyz")

    op.add_option("-e", "--engine", type="choice",
                  choices=engines, default=None,
                  help=("which display engine to use (%s)." %
                        ", ".join(engines)))
    op.add_option("-n", "--no-fullscreen", action="store_true",
                  help="do not launch in fullscreen")
    op.add_option("-g", "--geometry", type="string", metavar="WxH",
                  action="callback", callback=parse_geometry,
                  default=(800, 480),
                  help="use given window geometry")
    op.add_option("-F", "--font-config", default=default_font_config,
                  help="Path to font configuration")
    op.add_option("-f", "--fps", type="int", default=50,
                  help="frames per second to use, default=%default")
    op.add_option("-t", "--theme", default=default_theme,
                  help="Path to theme (.edj) to use. Default=%default")
    op.add_option("-v", "--verbose", default=0, action="count",
                  help=("increase verbosity, can be used multiple times. Effect: "
                        "info (-v), debug (-v -v). Interferes with --quiet."))
    op.add_option("-q", "--quiet", default=0, action="count",
                  help=("increase quiet (less verbose), can be used multiple "
                        "times. Effect: error (-q), fatal (-q -q). Interferes "
                        "with --verbose."))
    op.add_option("-p", "--profile", action="store_true",
                  help="run canola with a profiler and output stats")
    op.add_option("-c", "--config", default=default_config_file,
                  action="store", type="string", dest="config_file",
                  help="Path to canola configuration file (default: %default)")

    return op.parse_args()

## Main ;-)

# Handle options and create output window
options, args = process_cmdline()

log_level_default = log.WARNING
log_level = log_level_default + 10 * (options.quiet - options.verbose)
log.setLevel(log_level)

# check and setup .canola for user
setup_dot_canola()

mger = Manager(options.config_file)

check_prefs()
check_themes()

apply_font_config(options.font_config)

if not pisfile(options.theme):
    log.warning("nonexistent theme %s, using default instead" % options.theme)
    options.theme = default_theme

if not pisfile(options.theme):
    raise SystemExit("No theme found.")

w, h = options.geometry
ee = ecore.evas.new(engine_name=options.engine, w=w, h=h)
log.debug("ecore evas: %s" % ee)
if ee is None:
    name = options.engine
    if name is None:
        name = "<automatic>"
    log.error("coult not create engine called '%s' with size %dx%d", name, w, h)
    raise SystemExit("No ecore evas engine available.")

ee.fullscreen = not options.no_fullscreen
ecore.animator_frametime_set(1.0 / options.fps)

if options.profile:
    import hotshot, hotshot.stats
    prof = hotshot.Profile("canola.prof")
    prof.start()

# Load and setup UI
ee.title = "Canola"
ee.name_class = ("Canola", "Canola")
ee.evas.font_hinting_set(evas.EVAS_FONT_HINTING_AUTO)

bg = ee.evas.Rectangle(color=(0, 0, 0, 255))
bg.size = ee.evas.size
bg.show()
ee.data["bg"] = bg

MainController = mger.get_class("MainController")
if MainController is None:
    log.error("no plugin for main controller, exiting ...")
    sys.exit(1)

# start everything ;-)
mc = MainController(ee, os.path.realpath(options.theme))
mc.view.size = ee.evas.size
mc.view.show()
ee.data["canola"] = mc.view

def resize_cb(ee):
    ee.data["bg"].size = ee.evas.size
    ee.data["canola"].size = ee.evas.size
ee.callback_resize = resize_cb


def post_show_setup():
    acquire_dbus_service_name()
    setup_etk()
    return False
ecore.timer_add(0.1, post_show_setup)

ee.show()
ecore.main_loop_begin()
mc.cleanup()

if options.profile:
    prof.stop()
    stats = hotshot.stats.load("canola.prof")
    stats.strip_dirs()
    stats.sort_stats("cumulative", "time", "calls")
    stats.print_stats()
