#!/usr/bin/env python2.6
#coding=utf8
#
#            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
#                    Version 2, December 2004
#
# Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
#
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
#            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
#   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
#  0. You just DO WHAT THE FUCK YOU WANT TO.

import sys
import gtk
import webkit
import json
import glib
import optparse

class ConfigurationError(Exception):
	''' Exception raised when reading a bad configuration file. '''
	pass

class ConfigurationReader(object):
	
	def __init__(self, filename):
		
		self._conf = None
		
		try:
			fconf = open(filename, 'rb')
		except IOError, err:
			raise ConfigurationError(str(err))
		else:
			try:
				self._conf = json.load(fconf)
			except ValueError, err:
				raise ConfigurationError(str(err))
		finally:
			fconf.close()

	def get_title(self):
		return self._conf.get('title', '')

	def get_root_view(self):
		return self._conf.get('view', [])
		
		
class DivideApp(object):
	
	def __init__(self):
		self._pages = []
		self._win = gtk.Window()
		self._main = gtk.VBox()
		self._bt_fullscreen = gtk.ToggleButton()
		self._title = gtk.Label()
		self._title.set_alignment(0, 0.50)
		self._title.set_padding(5, 0)
		
		self._win.set_title('Divide')
		self._bt_fullscreen.set_image(gtk.image_new_from_stock(
					gtk.STOCK_FULLSCREEN, gtk.ICON_SIZE_SMALL_TOOLBAR))
		hbox = gtk.HBox()
		hbox.pack_start(self._title)
		hbox.pack_start(self._bt_fullscreen, fill=False, expand=False)
		self._main.pack_start(hbox, expand=False, padding=3)
		self._win.add(self._main)
		
		self._bt_fullscreen.connect('clicked', self._cb_fullscreen)
		self._win.connect('destroy', lambda w: gtk.main_quit())
		
		self._win.show_all()
	
	def _cb_fullscreen(self, widget=None):
		if widget.get_active():
			self._win.fullscreen()
		else:
			self._win.unfullscreen()
	
	def fullscreen(self):
		self._win.fullscreen()
		self._bt_fullscreen.set_active(True)
	
	def configure(self, conf, options=None):
		''' Read configuration and create corresponding GTK widgets. '''

		self._title.set_markup(conf.get_title())
		view = self._configure_view(conf.get_root_view(), options)
		self._main.add(view)
		self._main.show_all()
		
	def _configure_view(self, view, options=None):
		''' Create widget for a specific view, called recursively in
			case of sub-views. '''

		if view.get('type', 'view') == 'page':
			wk = webkit.WebView()
			sw = gtk.ScrolledWindow()
			
			if options is not None and options.hide_scrollbars:
				sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
				
			sw.set_size_request(
				view.get('width', -1), 
				view.get('height', -1)
			)
			
			sw.add(wk)
			
			self._pages.append((
				wk, 
				view.get('url'), 
				view.get('auto_refresh'), 
				sw, 
				view.get('auto_scroll', {})
			))
			
			return sw
			
		elif view.get('type', 'view') == 'view':		
			if view.get('split', 'vertically') == 'vertically':
				box = gtk.HBox()
			elif view.get('split', 'vertically') == 'horizontally':
				box = gtk.VBox()
			else:
				raise ConfigurationError(('Split type is vertically ',
											'or horizontally only'))
			
			if 'sub' not in view:
				raise ConfigurationError('View MUST have a "sub" item.')
			
			for item in view.get('sub'):
				box.add(self._configure_view(item, options))
			
			return box
			
		else:
			raise ConfigurationError('Type of view is view or page')
	
	def open_all(self):
		''' Open all configured pages in web-browsers, and create
			timeouts for auto_reloading and auto_scrolling. '''
			
		for page in self._pages:
			page[0].open(page[1])
			
			if page[2] is not None:
				glib.timeout_add_seconds(
					page[2], 
					lambda wk: wk.reload_bypass_cache() or True, 
					page[0]
				)
			
			if 'x' in page[4]:
				glib.timeout_add(
					page[4]['x'].get('milli', 1), 
					self._cb_scroll, 
					'x', 
					page[3].get_hadjustment(), 
					page[4]['x']
				)
			
			if 'y' in page[4]:
				glib.timeout_add(
					page[4]['y'].get('milli', 1), 
					self._cb_scroll, 
					'y', 
					page[3].get_vadjustment(), 
					page[4]['y']
				)

	def _cb_scroll(self, orientation, adj, settings):
		''' Callback called by timeout for page auto_scrolling. '''
		
		maxi = adj.get_upper() - adj.get_page_size()
		
		if maxi < 0: # Page do not scroll!
			return True


		if (settings.get('pause', 0) and not settings.get('current_pause', 0) 
						and (adj.get_value() >= maxi or adj.get_value() == 0)):
			settings['current_pause'] = settings['pause'] + 1

		if adj.get_value() >= maxi:
			if settings.get('return', False):
				settings.update({'left_to_right': False})
			else:
				adj.set_value(0)
		elif settings.get('return', False) and adj.get_value() == 0:
			settings.update({'left_to_right': True})

		if settings.get('current_pause', 0):
			settings['current_pause'] = settings['current_pause'] - 1
		
		if not settings.get('current_pause', 0):
			if settings.get('left_to_right', True):
				adj.set_value(adj.get_value() + settings.get('increment', 10))
			else:
				adj.set_value(adj.get_value() - settings.get('increment', 10))
			
		return True

if __name__ == '__main__':
	op = optparse.OptionParser()
	
	op.add_option('-f', '--fullscreen', 
		action='store_true', 
		default=False, 
		help='Start in fullscreen mode'
	)
	
	op.add_option('-s', '--hide-scrollbars', 
		action='store_true', 
		default=False, 
		help='Hide scrollbars'
	)
	
	(options, args) = op.parse_args()
	
	if len(args) != 1:
		op.error('I need a config file !')
	
	try:
		cr = ConfigurationReader(args[0])
		da = DivideApp()
		da.configure(cr, options)
		da.open_all()
	except ConfigurationError, err:
		print 'Error in configuration: %s' % str(err)
		sys.exit(1)
	
	if options.fullscreen:
		da.fullscreen()
	
	gtk.main()
