# Copyright (C) 2011 Canonical
#
# Authors:
#  Michael Vogt
#
# 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; version 3.
#
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA

import os
import logging
from softwarecenter.enums import APP_INSTALL_PATH_DELIMITER

LOG = logging.getLogger(__name__)


class GMenuSearcher(object):

    def __init__(self):
        self._found = None

    def _search_gmenu_dir(self, dirlist, needle):
        if not dirlist[-1]:
            return
        from gi.repository import GMenu
        dir_iter = dirlist[-1].iter()
        current_type = dir_iter.next()
        while current_type is not GMenu.TreeItemType.INVALID:
            if current_type == GMenu.TreeItemType.DIRECTORY:
                self._search_gmenu_dir(
                    dirlist + [dir_iter.get_directory()], needle)
            elif current_type == GMenu.TreeItemType.ENTRY:
                item = dir_iter.get_entry()
                desktop_file_path = item.get_desktop_file_path()
                # direct match of the desktop file name and the installed
                # desktop file name
                if os.path.basename(desktop_file_path) == needle:
                    self._found = dirlist + [item]
                    return
                # if there is no direct match, take the part of the path after
                # "applications" (e.g. kde4/amarok.desktop) and
                # change "/" to "__" and do the match again - this is what
                # the data extractor is doing
                if "applications/" in desktop_file_path:
                    path_after_applications = desktop_file_path.split(
                        "applications/")[1]
                    if needle == path_after_applications.replace(
                            "/", APP_INSTALL_PATH_DELIMITER):
                        self._found = dirlist + [item]
                        return
            current_type = dir_iter.next()

    def get_main_menu_path(self, desktop_file, menu_files_list=None):
        if not desktop_file:
            return
        from gi.repository import GMenu
        from gi.repository import GObject
        # use the system ones by default, but allow override for
        # easier testing
        if menu_files_list is None:
            menu_files_list = ["applications.menu", "settings.menu"]
        for n in menu_files_list:
            if n.startswith("/"):
                tree = GMenu.Tree.new_for_path(n, 0)
            else:
                tree = GMenu.Tree.new(n, 0)
            try:
                tree.load_sync()
            except GObject.GError as e:
                LOG.warning("could not load GMenu path: %s" % e)
                return

            root = tree.get_root_directory()
            self._search_gmenu_dir([root],
                                   os.path.basename(desktop_file))
            # retry search for app-install-data desktop files
            if not self._found and ":" in os.path.basename(desktop_file):
                # the desktop files in app-install-data have a layout
                # like "pkg:file.desktop" so we need to take that into
                # account when searching
                desktop_file = os.path.basename(desktop_file).split(":")[1]
                self._search_gmenu_dir([root], desktop_file)
            return self._found


# these are the old static bindinds that are no longer required
# (this is just kept here in case of problems with the dynamic
#  GIR and the old gtk2 gtk ui)
class GMenuSearcherGtk2(object):

    def __init__(self):
        self._found = None

    def _search_gmenu_dir(self, dirlist, needle):
        if not dirlist[-1]:
            return

        import gmenu
        for item in dirlist[-1].get_contents():
            mtype = item.get_type()
            if mtype == gmenu.TYPE_DIRECTORY:
                self._search_gmenu_dir(dirlist + [item], needle)
            elif item.get_type() == gmenu.TYPE_ENTRY:
                desktop_file_path = item.get_desktop_file_path()
                # direct match of the desktop file name and the installed
                # desktop file name
                if os.path.basename(desktop_file_path) == needle:
                    self._found = dirlist + [item]
                    return
                # if there is no direct match, take the part of the path after
                # "applications" (e.g. kde4/amarok.desktop) and
                # change "/" to "__" and do the match again - this is what
                # the data extractor is doing
                if "applications/" in desktop_file_path:
                    path_after_applications = desktop_file_path.split(
                        "applications/")[1]
                    if needle == path_after_applications.replace(
                            "/", APP_INSTALL_PATH_DELIMITER):
                        self._found = dirlist + [item]
                        return

    def get_main_menu_path(self, desktop_file, menu_files_list=None):
        if not desktop_file:
            return
        import gmenu
        # use the system ones by default, but allow override for
        # easier testing
        if menu_files_list is None:
            menu_files_list = ["applications.menu", "settings.menu"]
        for n in menu_files_list:
            tree = gmenu.lookup_tree(n)
            self._search_gmenu_dir([tree.get_root_directory()],
                                   os.path.basename(desktop_file))
            if self._found:
                return self._found
