#!/usr/bin/env python
# -*- mode: python; coding: koi8-r; -*-

import tempfile
import os

import gtk, gtk.glade
import gobject
glade = gtk.glade

from bookmarks import Book
from bookbuffer import BookBuffer
from miscutils import get_glade_file, fix_description, fix_filename, \
     error_dialog, OpenFileDialog



class BookInfoWindow(gobject.GObject):

    # booknarks treeview
    COLUMN_AUTHOR      = 0
    COLUMN_NAME        = 1
    COLUMN_PERCENT     = 2
    COLUMN_DESCRIPTION = 3
    COLUMN_MARK        = 4 # invisible: mark number

    # categories treeview
    COLUMN_CHECK = 0
    COLUMN_CATEGORY = 1

    # binary-content treeview
    COLUMN_ID            = 0
    COLUMN_CONTENT_TYPE  = 1
    COLUMN_BINARY_NUMBER = 2

    width = 400
    height = 300

    categories_list = []

    def __init__(self, book):

        gobject.GObject.__init__(self)

        self.book_buffer = None

        glade_file = get_glade_file()
        self.wTree = glade.XML(glade_file, 'book_info_window')

        self.window = self.wTree.get_widget('book_info_window')
        self.window.resize(self.width, self.height)

        dic = {
            'apply_clicked_cb'                 : lambda w: self.apply(),
            'close_clicked_cb'                 : lambda w: self.window.destroy(),
            'apply_bookmark_clicked_cb'        : self.apply_bookmark_clicked_cb,
            'delete_bookmark_clicked_cb'       : self.delete_bookmark_clicked_cb,
            'bookinfo_notebook_switch_page_cb' : self.notebook_switch_page_cb,
            }
        self.wTree.signal_autoconnect(dic)

        self.bookinfo_notebook = self.wTree.get_widget('bookinfo_notebook')
        self.file_name_label = self.wTree.get_widget('file_name_label')
        self.name_entry = self.wTree.get_widget('name_entry')
        self.author_entry = self.wTree.get_widget('author_entry')
        description_textview = self.wTree.get_widget('description_textview')
        self.description_buffer = description_textview.get_buffer()
        self.file_type_label = self.wTree.get_widget('file_type_label')
        #self.categories_label = self.wTree.get_widget('categories_label')

        # bookmarks treeview
        treeview = self.wTree.get_widget('bookmarks_treeview')

        model = gtk.ListStore(gobject.TYPE_STRING, # author
                              gobject.TYPE_STRING, # name
                              gobject.TYPE_INT,    # percent
                              gobject.TYPE_STRING, # description
                              gobject.TYPE_INT)    # mark number
        self.bookmarks_model = model

        for text, label in ((self.COLUMN_AUTHOR,      'Author'),
                            (self.COLUMN_NAME,        'Name'),
                            (self.COLUMN_PERCENT,     '%'),
                            (self.COLUMN_DESCRIPTION, 'Description')):
            column = gtk.TreeViewColumn(label, gtk.CellRendererText(), text=text)
            column.set_resizable(True)
            column.set_sort_column_id(text)
            treeview.append_column(column)

        selection = treeview.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)
        selection.connect('changed', lambda w: self.bookmark_show_selected())

        treeview.connect('row-activated', self.bookmark_row_activated_cb)

        self.bookmarks_treeview = treeview

        self.bookmark_textbuffer = self.wTree.get_widget('bookmark_textview').get_buffer()

        self.bookmarks_paned = self.wTree.get_widget('bookmarks_paned')

        # categories
        treeview = self.wTree.get_widget('categories_treeview')

        model = gtk.ListStore(gobject.TYPE_BOOLEAN,
                              gobject.TYPE_STRING)
        self.categories_model = model

        renderer = gtk.CellRendererToggle()
        renderer.connect('toggled', self.category_check_toggled, model)
        column = gtk.TreeViewColumn('', renderer, active=self.COLUMN_CHECK)
        treeview.append_column(column)

        column = gtk.TreeViewColumn('Category', gtk.CellRendererText(),
                                    text=self.COLUMN_CATEGORY)
        column.set_resizable(True)
        column.set_sort_column_id(self.COLUMN_CATEGORY)
        treeview.append_column(column)

        self.categories_treeview = treeview

        for cat in self.categories_list:
            iter = model.append()
            model.set(iter,
                      self.COLUMN_CHECK, True,
                      self.COLUMN_CATEGORY, cat)
        treeview.set_model(model)


        # binary content
        treeview = self.wTree.get_widget('binary_treeview')

        model = gtk.ListStore(gobject.TYPE_STRING, # id
                              gobject.TYPE_STRING, # content-type
                              gobject.TYPE_INT)    # binary-number
        self.binary_model = model

        self.binary_image = self.wTree.get_widget('binary_image')

        for text, label in ((self.COLUMN_ID, 'Id'),
                            (self.COLUMN_CONTENT_TYPE, 'Content Type')):
            column = gtk.TreeViewColumn(label, gtk.CellRendererText(), text=text)
            column.set_resizable(True)
            column.set_sort_column_id(text)
            treeview.append_column(column)

        treeview.connect('row-activated',
                         (lambda w, row, col: self.save_binary()))

        selection = treeview.get_selection()
        selection.connect('changed', (lambda w: self.show_binary()))

        self.binary_treeview = treeview

        self.set_book(book)

        self.window.show()


    def bookmark_row_activated_cb(self, w, row, col):
        iter = self.bookmarks_model.get_iter(row)
        mark_number = self.bookmarks_model.get_value(iter, self.COLUMN_MARK)
        self.emit('goto-bookmark', mark_number)


    def category_check_toggled(self, cell, path, model):
        iter = model.get_iter((int(path),))
        check = not model.get_value(iter, self.COLUMN_CHECK)

        num_check = 0
        i = model.get_iter_first()
        while i:
            num_check += model.get_value(i, self.COLUMN_CHECK)
            i = model.iter_next(i)

        # minimum one has been checked
        if num_check == 1 and check == 0: return

        model.set(iter, self.COLUMN_CHECK, check)
        cat = model.get_value(iter, self.COLUMN_CATEGORY)
        self.emit('categories-changed', cat, check)


    def set_book(self, book):
        self.book = book
        self.bookinfo_notebook.set_current_page(0)
        #self.binary_treeview.get_selection().unselect_all()
        self.file_name_label.set_text(fix_filename(self.book.filename))
        self.author_entry.set_text(self.book.author)
        self.name_entry.set_text(self.book.name)
        self.description_buffer.set_text(self.book.description)
        self.update_bookmarks()
        self.file_type_label.set_text(self.book.file_type)

        # update categories
        model = self.categories_model
        def set_check(model, path, iter, book):
            if model.get_value(iter, self.COLUMN_CATEGORY) in book.categories:
                model.set(iter, self.COLUMN_CHECK, True)
            else:
                model.set(iter, self.COLUMN_CHECK, False)
        model.foreach(set_check, book)

        #self.window.set_title('PyBookReader - Info')
        self.binary_image.set_from_stock(gtk.STOCK_MISSING_IMAGE,
                                         gtk.ICON_SIZE_DND)
        #gtk.STOCK_NEW

        self.book_buffer = None


    def apply(self):
        self.book.name = self.name_entry.get_text()
        self.book.author = self.author_entry.get_text()
        start, end = self.description_buffer.get_bounds()
        self.book.description = self.description_buffer.get_text(start,
                                                                 end, True)
        self.emit('book-info-changed')


    def get_selected_list(self):
        sel = self.bookmarks_treeview.get_selection()
        selected_list = []
        sel.selected_foreach(lambda model, path, iter:
                             selected_list.append((model, path, iter)))
        return selected_list

    def bookmark_show_selected(self):
        selected_list = self.get_selected_list()
        if len(selected_list) != 1:
            self.bookmark_textbuffer.set_text('')
            return

        model, path, iter = selected_list[0]
        mark = model.get_value(iter, self.COLUMN_MARK)
        m = self.book.get_mark(int(mark))
        if m:
            self.bookmark_textbuffer.set_text(m.description)


    def apply_bookmark_clicked_cb(self, w):
        selected_list = self.get_selected_list()
        if len(selected_list) != 1:
            return

        start, end = self.bookmark_textbuffer.get_bounds()
        text = self.bookmark_textbuffer.get_text(start, end)

        model, path, iter = selected_list[0]
        mark = model.get_value(iter, self.COLUMN_MARK)
        m = self.book.get_mark(int(mark))
        m.description = text

        self.update_bookmarks()
        self.emit('bookmark-removed')


    def delete_bookmark_clicked_cb(self, w):
        selected_list = self.get_selected_list()
        if len(selected_list) == 0:
            return
        for model, path, iter in selected_list:
            mark = model.get_value(iter, self.COLUMN_MARK)
            self.book.remove_bookmark(int(mark))
        self.update_bookmarks()
        self.emit('bookmark-removed')


    def update_bookmarks(self):
        model = self.bookmarks_model
        model.clear()
        for mark in self.book.marks_list:
            iter = model.append()
            desc = fix_description(mark.description, 100)
            model.set(iter,
                      self.COLUMN_NAME, mark.name,
                      self.COLUMN_AUTHOR, mark.author,
                      self.COLUMN_PERCENT, int(mark.position*100),
                      self.COLUMN_DESCRIPTION, desc,
                      self.COLUMN_MARK, mark.number)
        self.bookmarks_treeview.set_model(model)


    def notebook_switch_page_cb(self, w, p, page):

        if page == 3 and not self.book_buffer: # advanced
            self.update_binary_content()


    def update_binary_content(self):

        self.book_buffer = BookBuffer()
        self.book_buffer.set_book(self.book)
        try:
            self.binary_content = self.book_buffer.binary_content()
        except IOError, err:
            error_dialog(self.window, err)
            return

        model = self.binary_model
        model.clear()

        n = 0
        for id, ct, data, offset in self.binary_content:
            iter = model.append()
            model.set(iter,
                      self.COLUMN_ID, id,
                      self.COLUMN_CONTENT_TYPE, ct,
                      self.COLUMN_BINARY_NUMBER, n)
            n += 1
        self.binary_treeview.set_model(model)


    def get_binary_data(self):
        sel = self.binary_treeview.get_selection()
        model, iter = sel.get_selected()
        if not iter: return None
        num_bin = model.get_value(iter, self.COLUMN_BINARY_NUMBER)
        return self.binary_content[num_bin]


    def show_binary(self):
        bin_data = self.get_binary_data()
        if not bin_data: return
        id, content_type, data, offset = bin_data

        tmp_file = tempfile.mktemp()
        try:
            open(tmp_file, 'w').write(data)
            pb = gtk.gdk.pixbuf_new_from_file(tmp_file)
            #pb = gtk.gdk.pixbuf_new_from_inline(len(data), data, True)
            self.binary_image.set_from_pixbuf(pb)
        finally:
            os.remove(tmp_file)


    def save_binary(self):
        id, content_type, data, offset = self.get_binary_data()
        if not data: return

        dialog = OpenFileDialog(self.window, save_as=1, filename=id)
        filename = dialog.filename
        if filename:
            try:
                open(filename, 'w').write(data)
            except IOError, err:
                error_dialog(self.window, 'Can\'t write file %s: %s' \
                             % (filename, err[1]))


##----------------------------------------------------------------------

## signals
gobject.signal_new('bookmark-removed', BookInfoWindow,
                   gobject.SIGNAL_RUN_LAST,
                   gobject.TYPE_NONE, ())
gobject.signal_new('book-info-changed', BookInfoWindow,
                   gobject.SIGNAL_RUN_LAST,
                   gobject.TYPE_NONE, ())
gobject.signal_new('categories-changed', BookInfoWindow,
                   gobject.SIGNAL_RUN_LAST,
                   gobject.TYPE_NONE,
                   (gobject.TYPE_STRING, gobject.TYPE_BOOLEAN))
gobject.signal_new('goto-bookmark', BookInfoWindow,
                   gobject.SIGNAL_RUN_LAST,
                   gobject.TYPE_NONE,
                   (gobject.TYPE_INT,))


