# -*- coding: utf-8 -*-
# Elisa - Home multimedia server
# Copyright (C) 2006-2008 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 3.
# 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.


__maintainer__ = 'Benjamin Kampmann <benjamin@fluendo.com>'

from menu_entry_builder import MenuEntryBuilder

from elisa.core import common
from elisa.core.media_uri import MediaUri

from xdg import Menu, DesktopEntry
from xdg.IconTheme import getIconPath

from twisted.internet import defer, threads

import os

class XdgEntryBuilder(MenuEntryBuilder):
    """
    Build MenuEntries for the type 'xdg_menu', 'xdg_desktop_node',
    'xdg_desktop_path'
    """

    def menu_entry_identifiers__get(self):
#        return ['xdg_menu', 'xdg_desktop_node', 'xdg_desktop_path']
        return ['xdg_desktop_path']

    def build_menu_entry(self, parent, node_xml):
        xdg_type = node_xml.get('type')

        if xdg_type == 'xdg_menu':
            pass

        elif xdg_type == 'xdg_desktop_node':
            pass

        elif xdg_type == 'xdg_desktop_path':
            path = node_xml.find('Path')
            if path == None:
                self.warning("%s: is missing the Path-Tag. Skipped" %
                node_xml)
                return defer.succeed([])

            path = path.text
            if not os.path.isdir(path):
                self.warning("'%s' is not a directory!" % path)
                return defer.succeed([])

            dfr = threads.deferToThread(os.listdir, path)
            dfr.addCallback(self._got_directory_list, parent, path)
            return dfr

        return defer.succeed([])

    def _node_from_desktop_file(self, path):
        """
        returns a Deferred with the model (contaning already an action) as
        callback result. If the model could not been created the callback
        result is a None
        """
        plugin_registry = common.application.plugin_registry

        def got_action(action, model, d):
            model.activate_action = action
            action.executable = d.getExec().split(' ')[0]
            action.path = d.getPath()
            return model

        def got_model(model, d):
            model.text = d.getName()
            icon = getIconPath(d.getIcon())
            uri = MediaUri('file://%s' % icon)
            model.thumbnail_source =  uri 
            model.has_children = False
            action_dfr = defer.maybeDeferred(plugin_registry.create_component,
                                            'xmlmenu:spawn_process_action')
            action_dfr.addCallback(got_action, model, d)
            return action_dfr

        def got_desktop(d):
            if d.getNoDisplay() or d.getHidden() or len(d.getExec()) == 0:
                return None

            model_dfr = defer.maybeDeferred(plugin_registry.create_component,
                                            'base:menu_node_model')
            model_dfr.addCallback(got_model, d)
            return model_dfr            

        dfr = threads.deferToThread(DesktopEntry.DesktopEntry, path)
        dfr.addCallback(got_desktop)

        return dfr

    def _got_directory_list(self, list, parent, path):
        idx = 0

        dfr = defer.Deferred()
        models = []

        def got_model(model, list):
            if model != None:
                parent.children.append(model)
                models.append(model)
            next_node(list)

        def next_node(list):
            if len(list) == 0:
                dfr.callback(models)
                return

            next = list.pop(0)

            if not next[-8:] == '.desktop':
                next_node(list)
                return

            real_path = "%s/%s" % (path, next)
            next_dfr = self._node_from_desktop_file(real_path)
            next_dfr.addCallback(got_model, list)

        if len(list) == 0:
            return defer.succeed([])

        next_node(list)

        return dfr
