# 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 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 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 St, Fifth Floor, Boston, MA  02110-1301  USA

import os
from gi.repository import Gtk
import logging
from gi.repository import GObject
from gettext import gettext as _

from sugar3.graphics.toolbutton import ToolButton
from sugar3.activity.activity import get_bundle_path, get_activity_root
from sugar3.graphics.style import *

logger = logging.getLogger('infoslicer')

PUBLISH  = 0
TITLE    = 1

class BookView(Gtk.VBox):
    def sync(self):
        if not self._changing:
            return
        GObject.source_remove(self._changing)
        index, column = self.tree.get_cursor()
        self._cursor_changed(index)

    def __init__(self, book, name, tooltip, custom):
        GObject.GObject.__init__(self)
        self.book = book
        self._changing = None
        self._check = None

        title = Gtk.Toolbar()

        # title checkbox

        if custom:
            self._check = Gtk.CheckButton()
            self._check.props.can_focus = False
            self._check.props.tooltip_text = \
                    _('Articles are ready to be published')
            self._check.connect('toggled', self._check_toggled_cb)
            check_box = Gtk.HBox()
            check_box.set_size_request(50, -1)
            check_box.pack_start(self._check, True, False, 0)
            tool_item = Gtk.ToolItem()
            tool_item.add(check_box)
            tool_item.show()
            title.insert(tool_item, -1)
        else:
            tool_item = Gtk.ToolItem()
            tool_item.add(Gtk.Label(label='  '))
            tool_item.show()
            title.insert(tool_item, -1)

        # title caption

        caption_label = Gtk.Label(label=name)
        caption_label.props.tooltip_text = tooltip
        caption_label.modify_fg(Gtk.StateType.NORMAL, COLOR_WHITE.get_gdk_color())
        caption_box = Gtk.HBox()
        caption_box.pack_start(caption_label, False, False, 0)
        caption = Gtk.EventBox()
        caption.add(caption_box)
        caption.modify_bg(Gtk.StateType.NORMAL, COLOR_TOOLBAR_GREY.get_gdk_color())

        tool_item = Gtk.ToolItem()
        tool_item.add(caption)
        tool_item.show()
        title.insert(tool_item, -1)

        separator = Gtk.SeparatorToolItem()
        separator.props.draw = False
        separator.set_expand(True)
        title.insert(separator, -1)

        # create article button

        if custom:
            create = ToolButton('add')
            create.set_tooltip(_('Create new article'))
            create.connect('clicked', self._create_cb)
            title.insert(create, -1)
        else:
            logger.debug('BookView(%s): listen for new articles' % name)
            self.book.connect('article-added', self._article_added_cb)

        # delete article button

        delete = ToolButton('edit-delete')
        delete.set_tooltip(_('Delete current article'))
        delete.connect('clicked', self._delete_cb)
        title.insert(delete, -1)

        # move buttons

        downward = ToolButton('down')
        downward.set_tooltip(_('Move article downward'))
        downward.connect('clicked', self._swap_cb, +1)
        title.insert(downward, -1)

        upward = ToolButton('up')
        upward.set_tooltip(_('Move article upward'))
        upward.connect('clicked', self._swap_cb, -1)
        title.insert(upward, -1)

        # tree

        self.store = Gtk.ListStore(bool, str)
        self.tree = Gtk.TreeView(self.store)
        self.tree.props.headers_visible = False
        self.tree.connect('cursor-changed', self._cursor_changed_cb)

        cell = Gtk.CellRendererToggle()
        cell.connect('toggled', self._cell_toggled_cb)
        cell.props.activatable = True

        # FIXME: insert_column_with_attributes does not exist on pygobject
        # column = self.tree.insert_column_with_attributes(0, '', cell, active=0)

        logging.debug('TODO: this is a workaround due '
                      'https://bugzilla.gnome.org/show_bug.cgi?id=679415')

        column = Gtk.TreeViewColumn('Wiki', cell)
        column.props.sizing = Gtk.TreeViewColumnSizing.FIXED
        column.props.fixed_width = 50
        column.props.visible = custom

        self.tree.insert_column(column, 0)

        cell = Gtk.CellRendererText()
        cell.connect('edited', self._cell_edited_cb)
        cell.props.editable = True

        # FIXME: insert_column_with_attributes does not exist on pygobject
        # self.tree.insert_column_with_attributes(1, '', cell, text=1)

        logging.debug('TODO: this is a workaround due '
                      'https://bugzilla.gnome.org/show_bug.cgi?id=679415')

        column = Gtk.TreeViewColumn('Custom', cell, text=1)
        self.tree.insert_column(column, 1)

        for i in self.book.index:
            self.store.append((i['ready'], i['title']))

        # scrolled tree

        tree_scroll = Gtk.ScrolledWindow()
        tree_scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        tree_scroll.add(self.tree)

        self.pack_start(title, False, False, 0)
        self.pack_start(tree_scroll, True, True, 0)

        if len(self.store):
            self.tree.set_cursor(0, self.tree.get_column(1), False)
            if custom:
                self._update_check(self.store[0][PUBLISH])

        self.show_all()

    def _article_added_cb(self, book, article):
        logger.debug('_article_added_cb: new article %s' % article)

        self.book.props.article = article
        self.store.append((False, article))

    def _create_cb(self, widget):
        def find_name(list, prefix, uniq):
            name = uniq == 0 and prefix or ('%s %d' % (prefix, uniq))
            if not [i for i in list if i[TITLE] == name]:
                return name
            return find_name(list, prefix, uniq+1)

        if self._changing:
            GObject.source_remove(self._changing)
            self._changing = None

        name = find_name(self.store, _('New article'), 0)
        self.book.props.article = name
        self.store.append((False, name))
        self.tree.set_cursor(len(self.store)-1, self.tree.get_column(1), True)
        self._update_check(self.store[-1][PUBLISH])

    def _delete_cb(self, widget):
        path, focus_column = self.tree.get_cursor()

        if not path:
            return

        if self._changing:
            GObject.source_remove(self._changing)
            self._changing = None

        index = path.get_indices()[0]

        self.book.remove(self.store[index][TITLE])
        self.store.remove(self.tree.props.model.get_iter(index))

        if len(self.store):
            if index >= len(self.store):
                index -= 1
            self.tree.set_cursor(index, self.tree.get_column(1), False)
            self._update_check(self.store[index][PUBLISH])

    def _swap_cb(self, widget, delta):
        path, focus_column = self.tree.get_cursor()

        if not path:
            return

        old_index = path.get_indices()[0]
        new_index = old_index + delta

        if new_index < 0:
            new_index = len(self.store) - 1
        elif new_index >= len(self.store):
            new_index = 0

        self.book.index[old_index], self.book.index[new_index] = \
                self.book.index[new_index], self.book.index[old_index]
        self.store.swap(self.tree.props.model.get_iter(old_index),
                self.tree.props.model.get_iter(new_index))

    def _check_toggled_cb(self, widget):
        for i, entry in enumerate(self.store):
            entry[PUBLISH] = widget.props.active
            self.book.index[i]['ready'] = widget.props.active
        self._check.props.inconsistent = False

    def _update_check(self, value):
        if not self._check:
            return

        for i in self.store:
            if i[PUBLISH] != value:
                self._check.props.inconsistent = True
                return
        self._check.props.inconsistent = False
        self._check.props.active = value

    def _cell_toggled_cb(self, cell, index):
        value = not self.store[index][PUBLISH]
        self.store[index][PUBLISH] = value
        self.book.index[int(index)]['ready'] = value
        self._update_check(value)

    def _cursor_changed_cb(self, widget):
        if self._changing:
            GObject.source_remove(self._changing)

        index, column = self.tree.get_cursor()

        if index != None:
            self._changing = GObject.timeout_add(500, self._cursor_changed,
                    index)

    def _cursor_changed(self, index):
        self.book.props.article = self.store[index][TITLE]
        self._changing = None
        return False

    def _cell_edited_cb(self, cell, index, newtext):
        logger.debug('_cell_edited_cb(%s, %s)' % (index, newtext))

        # Disallowed chars are < > and &
        if newtext == "" or newtext.isspace() or '&' in newtext \
                or '<' in newtext or '>' in newtext:
            return

        # If there is already an article with the new name in the theme,
        # then we ignore the name change and highlight the existing article
        overides = [i for i, row in enumerate(self.store)
                if row[TITLE] == newtext]
        if overides:
            self.tree.set_cursor(overides[0], self.tree.get_column(1), False)
            return

        self.book.props.article.article_title = newtext
        self.store[index][TITLE] = newtext
