# -*- coding: utf-8 -*-

#  Copyright © 2011-2013  B. Clausius <barcc@gmx.de>
#
#  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.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.

# Taken from bzr-gtk
# Original Filename: branchview/treeview.py
# Original Copyright:
#__copyright__ = "Copyright © 2005 Canonical Ltd."
#__author__    = "Daniel Schierbeck <daniel.schierbeck@gmail.com>"

from __future__ import print_function, division

from xml.sax.saxutils import unescape

from gi.repository import GLib
from gi.repository import Gtk
from gi.repository import GObject
from gi.repository import Pango

from .bzr_const import NULL_REVISION


class LogView(GObject.Object):

    __gsignals__ = {
        'revision-selected': (GObject.SignalFlags.RUN_FIRST,
                              None,
                              (str, int, str, int)),
        'revision-activated': (GObject.SignalFlags.RUN_FIRST,
                              None,
                              (object, object)),
        'refreshed': (GObject.SignalFlags.RUN_FIRST, None,
                              (str, int)),
    }
    
    REVID, REVNO, SUMMARY, MESSAGE, COMMITTER, TIMESTAMP, TAGS, AUTHORS = range(8)
    
    def __init__(self, builder, model):
        GObject.Object.__init__(self)
        
        self.path = None
        self.model = model
        self.selection_changed_idle_pending = False
        
        self.treeview = builder.get_object('treeview_log')
        self.construct_treeview(builder)
        self.treeview.set_model(self.model)
        
    def construct_treeview(self, builder):
        # combined revno/summary interactive search
        #
        # the row in a logmodel is considered "matched" if a REVNO *starts*
        # from the key (that is the key is found in a REVNO at the offset 0)
        # or if a MESSAGE *contains* the key anywhere (that is, the key is
        # found case insensitively in a MESSAGE at any offset)
        def search_equal_func(model, unused_column, key, titer):
            if model.get_value(titer, self.REVNO).startswith(key):
                return False
            message = model.get_value(titer, self.MESSAGE)
            return message is None or key.lower() not in message.lower()
                
        self.treeview.set_search_equal_func(search_equal_func, None)
        self.treeview.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        
        self.treeview.connect("cursor-changed", self._on_selection_changed)
        self.treeview.connect("row-activated", self._on_revision_activated)
        self.treeview.connect("query-tooltip", self._on_query_tooltip)
        
        self.column_numbers = {}
        
        cell = builder.get_object('cellrenderer_revno')
        self.revno_column = builder.get_object("treeviewcolumn_revno")
        self.revno_column.add_attribute(cell, "text", self.REVNO)
        self.column_numbers[self.revno_column] = self.REVNO
        
        cell = Gtk.CellRendererText()
        cell.set_property("width-chars", 65)
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
        self.summary_column = builder.get_object("treeviewcolumn_summary")
        # expand=True is not available in glade, so create the cell here
        self.summary_column.pack_start(cell, True)
        self.summary_column.add_attribute(cell, "markup", self.SUMMARY)
        self.column_numbers[self.summary_column] = self.MESSAGE
        
        cell = Gtk.CellRendererText()
        cell.set_property("width-chars", 15)
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
        self.authors_column = builder.get_object("treeviewcolumn_authors")
        self.authors_column.pack_start(cell, True)
        self.authors_column.add_attribute(cell, "text", self.AUTHORS)
        self.column_numbers[self.authors_column] = self.AUTHORS
        
        cell = Gtk.CellRendererText()
        cell.set_property("width-chars", 20)
        cell.set_property("ellipsize", Pango.EllipsizeMode.END)
        self.date_column = builder.get_object("treeviewcolumn_date")
        self.date_column.pack_start(cell, True)
        self.date_column.add_attribute(cell, "text", self.TIMESTAMP)
        self.column_numbers[self.date_column] = self.TIMESTAMP
        
    def get_revision_2(self):
        """Return revision id and revno of currently selected revision, or None."""
        selected_rows = self.treeview.get_selection().get_selected_rows()[1]
        try:
            first_selected = min(selected_rows)
            last_selected = max(selected_rows)
        except ValueError:
            if self.path is None:
                #FIXME: gedit2->gedit3: there should be at least one row and self.path != None
                return None, 0, None, 0
            it1 = it2 = self.model.get_iter(self.path)
        else:
            it1 = self.model.get_iter(first_selected)
            it2 = self.model.get_iter(last_selected)
        revid_newest, revno_newest = self.model.get(it1, self.REVID, self.REVNO)
        if revid_newest is None:
            return None, 0, None, 0
        it2 = self.model.iter_next(it2)
        if it2:
            revid_oldest, revno_oldest = self.model.get(it2, self.REVID, self.REVNO) 
        else:
            revid_oldest, revno_oldest = NULL_REVISION, 0
        return revid_newest, int(revno_newest or 0), revid_oldest, int(revno_oldest or 0)
        
    def get_message(self):
        if self.path is None:
            #FIXME: gedit2->gedit3: there should be at least one row and self.path != None
            return ''
        message = self.model.get_value(self.model.get_iter(self.path), self.MESSAGE)
        return message and unescape(message)
        
    def set_cursor(self):
        self.path = None
        self.treeview.set_cursor(Gtk.TreePath.new_first(), None, False)
        
    def resize_columns(self):
        for column in [self.revno_column, self.authors_column]:
            cell = column.get_cells()[0]
            column.set_fixed_width(cell.get_size(self.treeview, None)[2] + cell.props.xpad*2)
        
    def _on_selection_changed(self, treeview):
        """callback for when the treeview changes."""
        path, unused_focus = treeview.get_cursor()
        if path is not None:
            self.path = path
        if not self.selection_changed_idle_pending:
            self.selection_changed_idle_pending = True
            GLib.idle_add(self._on_selection_changed_idle)
        
    def _on_selection_changed_idle(self):
        self.selection_changed_idle_pending = False
        revid_new, revno_new, revid_old, revno_old = self.get_revision_2()
        self.emit('revision-selected', revid_new, revno_new, revid_old, revno_old)
        
    def _on_revision_activated(self, unused_widget, path, col):
        self.emit('revision-activated', path, col)
        
    def _on_query_tooltip(self, unused_widget, x, y, keyboard_mode, tooltip):
        if keyboard_mode:
            return False
        try:
            tpath, column, x, y = self.treeview.get_path_at_pos(x, y)
        except TypeError:
            return False
        titer = self.model.get_iter(tpath)
        column_number = self.column_numbers[column]
        value = self.model.get_value(titer, column_number)
        if value is None or value == '':
            return False
        if column_number == self.MESSAGE:
            value = unescape(value)
        tooltip.set_custom(Gtk.Label(label=str(value).rstrip()))
        return True
        
