#! /usr/bin/env python
# -.- coding: utf-8 -.-
#
# Zeitgeist Explorer
#
# Copyright © 2012-2013 Manish Sinha <manishsinha@ubuntu.com>.
# Copyright © 2011-2012 Collabora Ltd.
#             By Siegfried-A. Gevatter Pujals <siegfried@gevatter.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 2 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 Lesser 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/>.

from gi.repository import Gtk, Gdk, Pango, Gio, GdkPixbuf, GLib

from datetime import datetime

from zgexplorer.eventwidgets import EventDetailsViewer, EventsTreeView, EventsViewer
from zgexplorer.remote import get_zeitgeist

from zgexplorer.datamodel import Event, Subject, Interpretation, \
    Manifestation, StorageState, ResultType, TimeRange

class ApplicationsViewer(Gtk.VBox):

    _client = None

    def __init__(self, window):
        super(ApplicationsViewer, self).__init__()

        self.main_window = window
        self._client = get_zeitgeist()

        self.spacing = 6
        self.margin = 12
                
        self.actor_name = {}

        self.desc_entry = Gtk.Label(xalign=0,yalign=0,wrap=True)
        self.pack_start(self.desc_entry, False, False, 6)

        self.hbox = Gtk.HBox()
        self.pack_start(self.hbox, True, True, 12)

        list_vbox = Gtk.VBox()
        self.hbox.pack_start(list_vbox, False, False, 0)

        apps_vbox = Gtk.VBox()
        list_vbox.pack_start(apps_vbox, True, True, 0)
        self.apps = Gtk.ListStore(str, str, GdkPixbuf.Pixbuf)
        self.apps_tree = Gtk.TreeView(model=self.apps)
        self.apps_tree.connect("cursor-changed", self.on_treeview_selected)
        self.apps_tree.connect("key-release-event", self.on_key_pressed)
        self.apps_tree.set_size_request(200, 600)
        self.apps_tree.set_properties(  'border_width',1,
                                        'visible',True,
                                        'rules_hint',True,
                                        'headers_visible',False)

        scroll = Gtk.ScrolledWindow(None, None)
        scroll.add(self.apps_tree)
        scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scroll.set_shadow_type(Gtk.ShadowType.IN)
        scroll.set_border_width(1)
        apps_vbox.pack_start(scroll, True, True, 0)

        column_pix_name = Gtk.TreeViewColumn(_('Applications'))
        column_pix_name.set_resizable(True)
        self.apps_tree.append_column(column_pix_name)

        pixbuf_rend = Gtk.CellRendererPixbuf()
        column_pix_name.pack_start(pixbuf_rend, False)
        column_pix_name.add_attribute(pixbuf_rend, "pixbuf", 2)
        name_rend = Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END)
        column_pix_name.pack_start(name_rend, False)
        column_pix_name.add_attribute(name_rend, "markup", 1)

        self.toolbar = Gtk.Toolbar(icon_size=1)
        self.toolbar.set_style(Gtk.ToolbarStyle.ICONS)
        self.toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR)
        self.toolbar.get_style_context().set_junction_sides(Gtk.JunctionSides.TOP)
        list_vbox.pack_start(self.toolbar, False, False, 3)

        list_refresh = Gtk.ToolButton.new(None, _("Refresh"))
        list_refresh.set_icon_name("view-refresh-symbolic")
        list_refresh.connect("clicked", self.on_list_refresh)
        self.toolbar.insert(list_refresh, 0)
        list_remove = Gtk.ToolButton.new(None, _("Delete all events for selected Application"))
        list_remove.set_icon_name("list-remove-symbolic")
        list_remove.connect("clicked", self.on_list_remove)
        self.toolbar.insert(list_remove, 1)

        self.viewer = ActorViewer(self.main_window)
        self.hbox.pack_start(self.viewer, True, True, 3)

        # The data for polling the actors
        self.template = Event.new_for_values(subjects=[Subject()])

        self.populate_actors()
        self.show_all()

    def on_list_refresh(self, button):
        self.populate_actors()
    
    def on_list_remove(self, button):
        self.remove_selected()
    
    def on_key_pressed(self, treeview, key):
        if key.keyval == Gdk.KEY_Delete:
            self.remove_selected()
        
    def remove_selected(self):
        selection = self.apps_tree.get_selection()
        if selection is not None:
            model, _iter = selection.get_selected()
            if _iter is not None:
                sel_actor = model.get(_iter, 0)[0]
                question_name = self.actor_name[sel_actor] if sel_actor in self.actor_name else sel_actor
                question_text = "Do you want to remove all the events for Application '{0}'?".format(question_name)
                dialog = Gtk.MessageDialog(self.main_window, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, question_text)
                response = dialog.run()
                if response == Gtk.ResponseType.YES:
                    self.del_template = Event.new_for_values(subjects=[Subject()], actor=sel_actor)
                    self._client.find_event_ids_for_templates(
                        [self.del_template],
                        self.on_actor_eventids,
                        timerange=TimeRange.until_now(),
                        result_type = ResultType.MostRecentEvents,
                        num_events = 100)
                dialog.destroy()
                    
                
                
    def on_actor_eventids(self, ids):
        ids = [int(id) for id in ids]
        self._client.delete_events(ids, reply_handler=self.on_remove_successful)
        
    def on_remove_successful(self, ids):
        self.viewer.clear()
        self.populate_actors()

    def populate_actors_callback(self, events):
        miscs = []
        self.apps.clear()
        self.actor_name.clear()
        for event in events:
            actor = event.get_actor()
            try:
                app_info = Gio.DesktopAppInfo.new(actor.replace("application://", ""))
                self.apps.append([actor, 
                                app_info.get_display_name(),
                                self._get_pixbuf_from_gio_icon(
                                    app_info.get_icon())
                                ])
                self.actor_name[actor] = app_info.get_display_name()
            except TypeError as e:
                if actor.strip() != "":
                    miscs.append([actor, actor, None])
        for misc in miscs:
            self.apps.append(misc)

    def populate_actors(self):
        self._client.find_events_for_templates(
                [self.template], 
                self.populate_actors_callback,
                timerange=TimeRange.until_now(),
                result_type = ResultType.MostPopularActor, 
                num_events = 100)

    def on_treeview_selected(self, treeview):
        selection = self.apps_tree.get_selection()
        if selection is not None:
            model, _iter = selection.get_selected()
            if _iter is not None:
                index = model.get(_iter, 0)[0]
                self.viewer.show(index)
 
    def _get_pixbuf_from_gio_icon(self, gio_icon):
        self._icon_theme = Gtk.IconTheme.get_default ()
        icon_info = self._icon_theme.lookup_by_gicon(gio_icon, 
                                            16, 
                                            Gtk.IconLookupFlags.FORCE_SVG)
        if icon_info is not None:
            try:
                pix = icon_info.load_icon()
            except gio.Error:
                return None
        else:
            pix = None
        return pix

class ActorViewer(Gtk.VBox):

    _client = None

    def __init__(self, window):
        super(ActorViewer, self).__init__()

        self.main_window = window
        self._client = get_zeitgeist()

        self.spacing = 6
        self.margin = 12
        self.events = []
        
        list_vbox = Gtk.VBox()
        self.pack_start(list_vbox, True, True, 0)
        
        self.apps = Gtk.TreeStore(str, str, str, bool, int)
        self.apps_tree = Gtk.TreeView(model=self.apps)
        self.apps_tree.connect("key-release-event", self.on_key_pressed)
        self.apps_tree.set_size_request(600, 600)
        self.apps_tree.set_properties(  'border_width',1,
                                        'visible',True,
                                        'rules_hint',True,
                                        'headers_visible',False)

        scroll = Gtk.ScrolledWindow(None, None)
        scroll.add(self.apps_tree)
        scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scroll.set_shadow_type(Gtk.ShadowType.IN)
        scroll.set_border_width(1)
        list_vbox.pack_start(scroll, True, True, 0)
        
        column_time = Gtk.TreeViewColumn(_('Time Stamp'))
        column_time.set_resizable(True)
        column_time.set_min_width(400)
        self.apps_tree.append_column(column_time)
        time_rend = Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END)
        column_time.pack_start(time_rend, False)
        column_time.add_attribute(time_rend, "markup", 0)

 
        column_ev_inter = Gtk.TreeViewColumn(_('Interpretation'))
        column_ev_inter.set_resizable(True)
        self.apps_tree.append_column(column_ev_inter)
        ev_inter_rend = Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END)
        column_ev_inter.pack_start(ev_inter_rend, False)
        column_ev_inter.add_attribute(ev_inter_rend, "markup", 1)


        column_ev_manifes = Gtk.TreeViewColumn(_('Manifestation'))
        column_ev_manifes.set_resizable(True)
        self.apps_tree.append_column(column_ev_manifes)
        ev_manifes_rend = Gtk.CellRendererText(ellipsize=Pango.EllipsizeMode.END)
        column_ev_manifes.pack_start(ev_manifes_rend, False)
        column_ev_manifes.add_attribute(ev_manifes_rend, "markup", 2)
        
        # Toolbar icon
        self.toolbar = Gtk.Toolbar(icon_size=1)
        self.toolbar.set_style(Gtk.ToolbarStyle.ICONS)
        self.toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR)
        self.toolbar.get_style_context().set_junction_sides(Gtk.JunctionSides.TOP)
        list_vbox.pack_start(self.toolbar, False, False, 3)

        list_refresh = Gtk.ToolButton.new(None, _("Refresh"))
        list_refresh.set_icon_name("view-refresh-symbolic")
        list_refresh.connect("clicked", self.on_list_refresh)
        self.toolbar.insert(list_refresh, 0)
        list_remove = Gtk.ToolButton.new(None, _("Delete all events for selected Application"))
        list_remove.set_icon_name("list-remove-symbolic")
        list_remove.connect("clicked", self.on_events_delete_pressed)
        self.toolbar.insert(list_remove, 1)

        self.actor=""
        self.template = Event.new_for_values(subjects=[Subject()], actor=self.actor)
        
        self.apps_tree.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)

    def on_events_delete_pressed(self, button):
        self.delete_selected_events()
    
    def on_key_pressed(self, treeview, key):
        if key.keyval == Gdk.KEY_Delete:
            self.delete_selected_events()
            
    def delete_selected_events(self):
        selection = self.apps_tree.get_selection()
        if selection is not None:
            iters={}
            for_deletion = []
            model, rows = selection.get_selected_rows()
            for row in rows:
                row = str(row)
                if ":" not in row:
                    iters[str(row)] = self.apps.get_iter(row)
            if len(list(iters.keys())) > 0:
                for row, _iter in list(iters.items()):
                    if _iter is not None:
                        lis = model.get(_iter,0)[0]
                        event = self.events[int(row)]
                        event_id = event.get_id()
                        timestamp = self.get_timestamp_from_event(event)
                        if timestamp == lis:
                            for_deletion.append(event_id)
                question_text = "Do you want to remove all the selected events"
                dialog = Gtk.MessageDialog(self.main_window, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, question_text)
                response = dialog.run()
                if response == Gtk.ResponseType.YES:
                    self._client.delete_events(for_deletion, reply_handler=self.on_remove_successful)
                dialog.destroy()
    
    def on_remove_successful(self, ids):
        self.show(self.actor)
        
    def on_list_refresh(self, button):
        self.show(self.actor)
    
    def clear(self):
        self.apps.clear()

    def show(self, actor):
        self.actor = actor
        self.apps.clear()
        self.template.set_actor(actor)
        self._client.find_events_for_templates(
                [self.template], 
                self.populate_events_callback,
                timerange=TimeRange.until_now(),
                result_type = ResultType.MostRecentEvents, 
                num_events = 100)

    def get_timestamp_from_event(self, event):
        ev_time = datetime.fromtimestamp(int(event.get_timestamp())/1000)
        return ev_time.strftime("%a, %x %X")
        
    def populate_events_callback(self, events):
        self.events = events
        for event in events:
            _iter = self.apps.append(None, 
                                [self.get_timestamp_from_event(event),
                                event.get_interpretation().split("#")[-1],
                                event.get_manifestation().split("#")[-1],
                                True, event.get_id()])
            for subject in event.get_subjects():
                uri = subject.get_uri().strip()
                try:
                    file_inst = Gio.file_new_for_uri(uri)
                    uri_scheme = file_inst.get_uri_scheme()
                    if uri_scheme == "file":
                        uri = file_inst.get_path()
                    elif uri_scheme == "application":
                        try:
                            app_info = Gio.DesktopAppInfo.new(uri.replace("application://", ""))
                            app_name = app_info.get_display_name()
                            uri = "{0} - {1}".format(app_name, uri) if app_name != "" else uri
                        except TypeError as e:
                            pass
                except GLib.ConvertError:
                    pass
                inter = subject.get_interpretation().split("#")[-1]
                manifes = subject.get_manifestation().split("#")[-1]
                if uri != "":
                    self.apps.append(_iter, [uri, inter, manifes, False, -1])
                
        self.apps_tree.expand_all()
