#!/usr/bin/python
# -*- coding: utf-8 -*-
### BEGIN LICENSE
# Copyright (C) 2009 <Marc Gariépy> <mgariepy@revolutionlinux.com> Révolution Linux
#This program is free software: you can redistribute it and/or modify it
#under the terms of the GNU General Public License version 3  or (at your option)
#any later version, as published by the Free Software Foundation.
#
#This program is distributed in the hope that it will be useful, but
#WITHOUT ANY WARRANTY; without even the implied warranties of
#MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
### END LICENSE

import sys
import os
import gtk
import grp
import shutil

import gettext
from gettext import gettext as _
gettext.textdomain("edubuntu-menueditor")

# Check if we are working in the source tree or from the installed
# package and mangle the python path accordingly
if os.path.dirname(sys.argv[0]) != ".":
    if sys.argv[0][0] == "/":
        fullPath = os.path.dirname(sys.argv[0])
    else:
        fullPath = os.getcwd() + "/" + os.path.dirname(sys.argv[0])
else:
    fullPath = os.getcwd()
sys.path.insert(0, os.path.dirname(fullPath))

from profilemanager import AboutProfilemanagerDialog, ProfileManagerModels, ProfilenameDialog
from profilemanager.profilemanagerconfig import getdatapath

class ProfilemanagerWindow(gtk.Window):
    __gtype_name__ = "ProfilemanagerWindow"
    TARGETS = [
        ( 'Row', gtk.TARGET_SAME_APP, 0),
    ]

    def __init__(self):
        """__init__ - This function is typically not called directly.
        Creation a ProfilemanagerWindow requires redeading the associated ui
        file and parsing the ui definition extrenally,
        and then calling ProfilemanagerWindow.finish_initializing().

        Use the convenience function NewProfilemanagerWindow to create
        ProfilemanagerWindow object.

        """
        pass

    def finish_initializing(self, builder):
        """finish_initalizing should be called after parsing the ui definition
        and creating a ProfilemanagerWindow object with it in order to finish
        initializing the start of the new ProfilemanagerWindow instance.

        """
        #get a reference to the builder and set up the signals
        self.builder = builder
        self.builder.connect_signals(self)

        #code for other initialization actions should be added here

        # load all needed object
        self.tvGroups = self.builder.get_object("tvGroups")
        self.tvMenus = self.builder.get_object("tvMenus")
        self.tvGroupsManager = self.builder.get_object("tvGroupsManager")
        self.menuPopup = self.builder.get_object("menuPopup")
        
        # Setup models
        self.tvGroupsModel = ProfileManagerModels.GroupsModel()
        self.tvMenusModel = ProfileManagerModels.MenusModel()
        self.tvGroupsManagerModel = ProfileManagerModels.GroupsManagerModel(self.tvGroupsModel)

        # Fill treeview
        self.setup_tvGroups()
        self.setup_tvMenus()
        self.setup_tvGroupsManager()

        # Adding DND for tvMenus and tvGroups
        self.tvMenus.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.TARGETS, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_MOVE|gtk.gdk.ACTION_COPY)
        self.tvGroups.enable_model_drag_dest( self.TARGETS, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_MOVE|gtk.gdk.ACTION_COPY)
        self.tvMenus.connect('drag-data-get', self.on_drag)
        self.tvGroups.connect('drag-data-received',self.on_drop, self.tvMenus)

        # This should be added later to enable dnd on both side.
        self.tvMenus.enable_model_drag_dest( self.TARGETS, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_MOVE|gtk.gdk.ACTION_COPY)
        self.tvGroups.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.TARGETS, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_MOVE|gtk.gdk.ACTION_COPY)
        self.tvGroups.connect('drag-data-get', self.on_drag)
        self.tvMenus.connect('drag-data-received', self.on_drop, self.tvGroups)

    def setup_tvGroups(self):
        self.tvGroups.set_model(self.tvGroupsModel)
        self.tvGroups.set_headers_visible(False)

        # setup column Name
        column = gtk.TreeViewColumn(_("Name"))
        cell = gtk.CellRendererText()
        column.pack_start(cell, False)
        column.set_attributes(cell, text = self.tvGroupsModel.GROUP_NAME)
        self.tvGroups.append_column(column)
        # setup column gid
        column = gtk.TreeViewColumn(_("Gid"))
        cell = gtk.CellRendererText()
        column.pack_start(cell, False)
        column.set_attributes(cell, text = self.tvGroupsModel.GROUP_GID)
        self.tvGroups.append_column(column)

    def setup_tvMenus(self):
        self.tvMenus.set_model(self.tvMenusModel)
        self.tvMenus.set_headers_visible(False)

        #setup column Name
        column = gtk.TreeViewColumn(_("Menu name"))
        cell = gtk.CellRendererText()
        column.pack_start(cell, False)
        column.set_attributes(cell, text = self.tvMenusModel.MENU_NAME)
        self.tvMenus.append_column(column)
        #setup column Path
        column = gtk.TreeViewColumn(_("Menu path"))
        cell = gtk.CellRendererText()
        column.pack_start(cell, False)
        column.set_attributes(cell, text = self.tvMenusModel.MENU_PATH)
        self.tvMenus.append_column(column)

    def setup_tvGroupsManager(self):
        self.tvGroupsManager.set_model(self.tvGroupsManagerModel)
        self.tvGroupsManager.set_headers_visible(False)

        column = gtk.TreeViewColumn(_("Groups"))
        cell = gtk.CellRendererText()
        column.pack_start(cell, False)
        column.set_attributes(cell, text = self.tvGroupsManagerModel.GROUP)
        self.tvGroupsManager.append_column(column)

        column = gtk.TreeViewColumn(_("Menu name"))
        cell = gtk.CellRendererText()
        column.pack_start(cell, False)
        column.set_attributes(cell, text = self.tvGroupsManagerModel.MENU_NAME)
        self.tvGroupsManager.append_column(column)
        column = gtk.TreeViewColumn(_("menu_path"))
        cell = gtk.CellRendererText()
        column.pack_start(cell, False)
        column.set_attributes(cell, text = self.tvGroupsManagerModel.FILE_PATH)
        self.tvGroupsManager.append_column(column)

    def add_listing_to_model(self):
        # make sur we have all needed data before inserting it.
        basedir = "/etc/desktop-profiles/"
        data = {}
        name = ""
        if self.dict_data.has_key("MENU_NAME") and self.dict_data.has_key("MENU_PATH") and self.dict_data.has_key("GROUP"):
            name = self.dict_data["GROUP"] + "-" + self.dict_data["MENU_NAME"]
            data["GROUP"] = self.dict_data["GROUP"]
            data["FILE_PATH"] = os.path.join(basedir, name + ".listing")
            data["XDG_DATA"] = os.path.join(self.dict_data["MENU_PATH"], "share")
            data["XDG_CONFIG"] = os.path.join(self.dict_data["MENU_PATH"], "xdg")
            self.tvGroupsManagerModel.fill_model({name:data})

    def on_cmiviewsystemgroups_toggled(self, status):
        if status.get_active():
            self.tvGroupsModel.fill_model(self.tvGroupsModel.get_system_groups())
            self.tvGroupsManagerModel.cleanup_groups()
        else:
            self.tvGroupsModel.remove_groups(self.tvGroupsModel.get_system_groups())

    def on_drag(self, treeview, drag_context, selection_data, info, eventtime):
        self.dict_data = {}
        selection = treeview.get_selection()
        model, iter = selection.get_selected()
        if iter:
            if model == self.tvGroupsModel:
                self.dict_data["GROUP"] = model[iter][model.GROUP_NAME]
                self.dict_data["ITER"] = iter
            else:
                self.dict_data["MENU_NAME"] = model[iter][model.MENU_NAME]
                self.dict_data["MENU_PATH"] = model[iter][model.MENU_PATH]

    def on_drop(self, treeview, drag_context, x, y, selection_data, info, timestamp, src_treeview):
        target_path, drop_position = treeview.get_dest_row_at_pos(x, y)
        if not (drop_position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE or drop_position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER):
            print _("you need to drop into an item")
            return

        model = treeview.get_model()
        iter = model.get_iter(target_path)
        if iter:
            if model == self.tvGroupsModel:
                if not self.dict_data.has_key("GROUP") and not self.dict_data.has_key("ITER"):
                    self.dict_data["GROUP"] = model[iter][model.GROUP_NAME]
                    self.dict_data["ITER"] = iter
            elif not self.dict_data.has_key("MENU_NAME") and not self.dict_data.has_key("MENU_PATH"):
                self.dict_data["MENU_NAME"] = model[iter][model.MENU_NAME]
                self.dict_data["MENU_PATH"] = model[iter][model.MENU_PATH]
            self.add_listing_to_model()

    def on_tv_button_press_event(self, treeview, event):
        if event.button == 3:
            time = event.time
            pathinfo = treeview.get_path_at_pos(int(event.x),int(event.y))
            if pathinfo is not None:
                path, col, cellx, celly = pathinfo
                treeview.grab_focus()
                treeview.set_cursor(path, col, 0)
                # Show menu item only if they are user added.
                selection = treeview.get_selection()
                model, iter = selection.get_selected()
                if model == self.tvMenusModel:
                    self.builder.get_object("menuImport").set_property("visible", True)
                    self.builder.get_object("menuDelete").set_property("visible", True)
                    self.builder.get_object("menuRemove").set_property("visible", False)
                    if model[iter][model.MENU_PATH].startswith("/etc/edubuntu-menueditor/"):
                        self.builder.get_object("menuDelete").set_property("sensitive",True)
                    else:
                        self.builder.get_object("menuDelete").set_property("sensitive",False)
                    self.menuPopup.popup( None, None, None, event.button, time)
                elif model == self.tvGroupsManagerModel:
                    self.builder.get_object("menuImport").set_property("visible", False)
                    self.builder.get_object("menuDelete").set_property("visible", False)
                    self.builder.get_object("menuRemove").set_property("visible", True)
                    self.menuPopup.popup(None, None, None, event.button, time)
            else:
                if treeview == self.tvMenus:
                    self.builder.get_object("menuImport").set_property("visible", True)
                    self.builder.get_object("menuDelete").set_property("visible", True)
                    self.builder.get_object("menuRemove").set_property("visible", False)
                    self.builder.get_object("menuDelete").set_property("sensitive",False)
                    self.menuPopup.popup( None, None, None, event.button, time)
            return True

    def on_menuSave_activate(self, widget):
        self.tvGroupsManagerModel.save_all_new_files()

    def on_menuDelete_activate(self, widget):
        selection = self.tvMenus.get_selection()
        model, iter = selection.get_selected()
        menu_name = model[iter][model.MENU_NAME]
        dialog = gtk.MessageDialog(type = gtk.MESSAGE_QUESTION, \
            message_format = _("Are you sure you want to delete ") \
            + menu_name + _(" from the disk ?"), buttons = gtk.BUTTONS_YES_NO )
        response = dialog.run()
        if response == gtk.RESPONSE_YES:
            shutil.rmtree(model[iter][model.MENU_PATH])
            model.remove(iter)
        dialog.destroy()

    def on_menuImport_activate(self, widget):
        file = ""
        filechooser = self.create_filechooser_open()
        response = filechooser.run()
        if response == gtk.RESPONSE_OK:
            file = filechooser.get_filename()
        filechooser.destroy()
        if file != "":
            suggest_name = os.path.basename(file).split(".tar.gz")[0]
            name = self.ask_user(suggest_name)
            if name != "":
                self.tvMenusModel.import_archive(name, file)

    def on_menuRemove_activate(self, widget):
        selection = self.tvGroupsManager.get_selection()
        model, iter = selection.get_selected()
        profile_path = model[iter][model.FILE_PATH]
        if os.path.exists(profile_path):
            dialog = gtk.MessageDialog(type = gtk.MESSAGE_QUESTION, \
                message_format = _("Are you sure you want to delete ") \
                + profile_path + _(" from the disk ?"), buttons = gtk.BUTTONS_YES_NO)
            response = dialog.run()
            dialog.destroy()
            if response == gtk.RESPONSE_NO:
                return
            os.remove(profile_path)
        self.tvGroupsModel.append_group_if_valid(model[iter][model.GROUP])
        model.remove(iter)

    def ask_user(self,suggest_name):
        name = ""
        NewProfilenameDialog = ProfilenameDialog.NewProfilenameDialog()
        NewProfilenameDialog.set_name(suggest_name)
        response = NewProfilenameDialog.run()
        if response == gtk.RESPONSE_OK:
            name = NewProfilenameDialog.name
        NewProfilenameDialog.destroy()
        tmp = ""
        for ch in name:
            if ch.isalnum() or ch == '.' or ch == '-' or ch == '_':
                tmp+=ch
            else:
                tmp+='_'
        return tmp

    def create_filechooser_open(self):
        buttons = ( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, \
                    gtk.STOCK_OPEN, gtk.RESPONSE_OK)
        filechooser = gtk.FileChooserDialog(_("Open..."), None, \
                                            gtk.FILE_CHOOSER_ACTION_OPEN, \
                                            buttons)
        filter = gtk.FileFilter()
        filter.set_name(_("Archive"))
        filter.add_pattern("*.tar.gz")
        filechooser.add_filter(filter)
        filter = gtk.FileFilter()
        filter.set_name(_("All files"))
        filter.add_pattern("*")
        filechooser.add_filter(filter)

        return filechooser

    def open_dialog(self):
        filename = ""
        filedialog = self.create_filechooser_open()
        response = filedialog.run()
        if response == gtk.RESPONSE_OK:
            filename = filedialog.get_filename()
        filedialog.destroy()
        return filename

    def about(self, widget, data=None):
        """about - display the about box for profilemanager """
        about = AboutProfilemanagerDialog.NewAboutProfilemanagerDialog()
        response = about.run()
        about.destroy()

    def launch_help(self, widget, data=None):
        import webbrowser
        webbrowser.open("https://wiki.ubuntu.com/Edubuntu/Documentation/Edubuntu-menueditor")

    def quit(self, widget, data=None):
        """quit - signal handler for closing the ProfilemanagerWindow"""
        self.destroy()

    def on_destroy(self, widget, data=None):
        """on_destroy - called when the ProfilemanagerWindow is close. """
        #clean up code for saving application state should be added here

        gtk.main_quit()

def NewProfilemanagerWindow():
    """NewProfilemanagerWindow - returns a fully instantiated
    ProfilemanagerWindow object. Use this function rather than
    creating a ProfilemanagerWindow directly.
    """

    if not gtk.gdk.display_get_default():
        logging.critical("Display not found")
        sys.exit(1)

    #look for the ui file that describes the ui
    ui_filename = os.path.join(getdatapath(), 'ui', 'ProfilemanagerWindow.ui')
    if not os.path.exists(ui_filename):
        ui_filename = None

    builder = gtk.Builder()
    builder.add_from_file(ui_filename)
    window = builder.get_object("profilemanager_window")
    window.finish_initializing(builder)
    return window

if __name__ == "__main__":
    #support for command line options
    import logging, optparse
    parser = optparse.OptionParser(version="%prog %ver")
    parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="Show debug messages")
    (options, args) = parser.parse_args()

    #set the logging level to show debug messages
    if options.verbose:
        logging.basicConfig(level=logging.DEBUG)
        logging.debug('logging enabled')

    #run the application
    window = NewProfilemanagerWindow()
    window.show()
    gtk.main()

