#!/usr/bin/env python
# Copyright (C) 2008, One Laptop Per Child
# Author: Sayamindu Dasgupta <sayamindu@laptop.org>
#
# 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 gtk, gobject
import evince
from sugar.datastore import datastore

import gnomevfs

import shutil, sys, os, os.path

from gettext import gettext as _

class ViewerToolbar(gtk.Toolbar):
    __gtype_name__ = 'ViewerToolbar'

    __gsignals__ = {
        'needs-update-size': (gobject.SIGNAL_RUN_FIRST,
                              gobject.TYPE_NONE,
                              ([]))
    }

    def __init__(self, evince_view):
        gtk.Toolbar.__init__(self)
        self.set_style(gtk.TOOLBAR_ICONS)

        self._evince_view = evince_view
        self._document = None

        self._prev = gtk.ToolButton(gtk.STOCK_GO_UP)
        self._prev.connect('clicked', self._prev_cb)
        self.insert(self._prev, -1)
        self._prev.props.sensitive = False
        self._prev.show()

        self._next = gtk.ToolButton(gtk.STOCK_GO_DOWN)
        self._next.connect('clicked', self._next_cb)
        self.insert(self._next, -1)
        self._next.props.sensitive = False
        self._next.show()
        
        
        self._page_spinner_adjustment = \
            gtk.Adjustment(value=1, lower=1, upper=0, step_incr=1, 
            page_incr=1, page_size=1)
        self._page_spinner_adjustment_value_changed_id = \
            self._page_spinner_adjustment.connect('value-changed', 
            self._page_spinner_adjustment_value_changed_cb)
            
        self._page_spinner = \
            gtk.SpinButton(adjustment=self._page_spinner_adjustment, 
            climb_rate=0.2, digits=0)
        self._page_spinner.props.sensitive = False
        
        item = gtk.ToolItem()
        item.add(self._page_spinner)
        self.insert(item, -1)
        item.show_all()

        separator = gtk.SeparatorToolItem()
        separator.set_draw(True)
        separator.set_expand(False)
        self.insert(separator, -1)
        separator.show()
                    
        self._zoom_out = gtk.ToolButton(gtk.STOCK_ZOOM_OUT)
        self._zoom_out.connect('clicked', self._zoom_out_cb)
        self.insert(self._zoom_out, -1)
        self._zoom_out.show()

        self._zoom_in = gtk.ToolButton(gtk.STOCK_ZOOM_IN)
        self._zoom_in.connect('clicked', self._zoom_in_cb)
        self.insert(self._zoom_in, -1)
        self._zoom_in.show()

        self._zoom_to_width = gtk.ToolButton(gtk.STOCK_ZOOM_FIT)
        self._zoom_to_width.connect('clicked', self._zoom_to_width_cb)
        self.insert(self._zoom_to_width, -1)
        self._zoom_to_width.show()

        separator1 = gtk.SeparatorToolItem()
        separator1.set_draw(False)
        separator1.set_expand(True)
        self.insert(separator1, -1)
        separator1.show()

        self._save = gtk.ToolButton(gtk.STOCK_SAVE)
        self._save.connect('clicked', self._save_cb)
        self.insert(self._save, -1)
        self._save.show()
        
        self._update_zoom_buttons()

    def zoom_in(self):
        self._evince_view.props.sizing_mode = evince.SIZING_FREE
        self._evince_view.zoom_in()
        self._update_zoom_buttons()

    def _zoom_in_cb(self, button):
        self.zoom_in()

    def zoom_out(self):
        self._evince_view.props.sizing_mode = evince.SIZING_FREE
        self._evince_view.zoom_out()
        self._update_zoom_buttons()
        
    def _zoom_out_cb(self, button):
        self.zoom_out()

    def zoom_to_width(self):
        self._evince_view.props.sizing_mode = evince.SIZING_FIT_WIDTH
        self.emit('needs-update-size')
        self._update_zoom_buttons()
        return False

    def _zoom_to_width_cb(self, button):
        self.zoom_to_width()

    def _save_cb(self, button):
        doc_info = self._document.get_info()
        fpath = sys.argv[1] #XXX: Bleh

        # Try to figure out if this thing is downloaded from the 
        # internet or is a local file (eg: from the library)
        # If this is a downloaded file, we need some extra 
        # magic (http://lists.laptop.org/pipermail/sugar/2008-October/009147.html)
        if os.path.basename(os.path.dirname(fpath)) == 'plugtmp':
            local = False
            dest = os.path.expandvars('$SUGAR_ACTIVITY_ROOT/instance')
            shutil.copy2(fpath, dest)
            fpath = os.path.join(dest, os.path.basename(fpath))
            os.chmod(fpath, 0644) #XXX: Hopefully this is right
        else:
            local = True

        entry = datastore.create()
        entry.set_file_path(fpath)

        # For certain sites, PDFs get saved as foo.php, etc 
        # An example would be the Nepali repository @ pustakalay.org
        # We need to force file sniffing here, otherwise the file gets
        # stored in the datastore with the mimetype application/x-php, etc
        file_info = gnomevfs.get_file_info(fpath, \
                gnomevfs.FILE_INFO_GET_MIME_TYPE| \
                gnomevfs.FILE_INFO_FORCE_SLOW_MIME_TYPE| \
                gnomevfs.FILE_INFO_FOLLOW_LINKS|gnomevfs.FILE_INFO_DEFAULT)

        entry.metadata['mime_type'] = file_info.mime_type

        if doc_info.title:
            entry.metadata['title'] = doc_info.title
        else:
            entry.metadata['title'] = os.path.basename(sys.argv[1])

        datastore.write(entry)

        entry.destroy()

    def _update_zoom_buttons(self):
        self._zoom_in.props.sensitive = self._evince_view.can_zoom_in()
        self._zoom_out.props.sensitive = self._evince_view.can_zoom_out()

    def set_document(self, document):
        self._document = document
        
        page_cache = self._document.get_page_cache()
        page_cache.connect('page-changed', self._page_changed_cb)
        
        self._page_spinner.props.sensitive = True
        self._page_spinner_adjustment.props.upper = self._document.get_n_pages()
        
        self._update_zoom_buttons()
        self._update_nav_buttons()
        
    def _prev_cb(self, button):
        self._evince_view.previous_page()
    
    def _next_cb(self, button):
        self._evince_view.next_page()
        
    def _update_nav_buttons(self):
        current_page = self._document.get_page_cache().get_current_page()
        self._prev.props.sensitive = current_page > 0
        self._next.props.sensitive = \
            current_page < self._document.get_n_pages() - 1
            
        self._page_spinner_adjustment.handler_block(self._page_spinner_adjustment_value_changed_id)
        self._page_spinner_adjustment.set_value(current_page + 1)
        self._page_spinner_adjustment.handler_unblock(self._page_spinner_adjustment_value_changed_id)
 
    def _page_changed_cb(self, page, proxy):
        self._update_nav_buttons()
        
    def _page_spinner_adjustment_value_changed_cb(self, adjustment):
        page = adjustment.get_value() - 1
        if self._document:
            self._document.get_page_cache().set_current_page(int(page))

def toolbar_needs_update_size_cb(widget, view, scrolledwindow):
    view.update_view_size(scrolledwindow)

def main(filename):
    evince.evince_embed_init()
    evince.job_queue_init()

    document = evince.factory_get_document('file://' + filename)

    win = gtk.Window()
    win.connect('destroy', lambda w: gtk.main_quit())
    vbox = gtk.VBox()
    scrolledwindow = gtk.ScrolledWindow()

    xft_dpi = gtk.settings_get_default().get_property('gtk-xft-dpi')

    view = evince.View()
    view.set_screen_dpi(xft_dpi/1024)
    view.set_document(document)

    scrolledwindow.add(view)

    toolbar = ViewerToolbar(view)
    toolbar.connect('needs-update-size', 
        toolbar_needs_update_size_cb, view, scrolledwindow)
    toolbar.set_document(document)
    # We need to wait for sometime before calling this
    gobject.timeout_add(1200, toolbar.zoom_to_width)
    
    vbox.pack_start(toolbar, expand=False, fill = False)
    vbox.pack_start(scrolledwindow)
    win.add(vbox)

    win.show_all()

    gtk.main()

if __name__ == '__main__':
    main(sys.argv[1]) 
