#!/usr/bin/env python
# -*- coding: utf-8 -*-

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

#  TwitterScreenlet © papamitra 2008, boamaod 2010
#  Icon © Luc Latulippe 2009 (Creative Commons License)

# TODO
# - gtk.Entry() sizing

import screenlets
# from screenlets import utils
from screenlets.options import StringOption , BoolOption , IntOption , FileOption , DirectoryOption , ListOption , AccountOption , TimeOption , FontOption, ColorOption , ImageOption
from screenlets.options import create_option_from_node
from screenlets import DefaultMenuItem

import pango
import cairo
import pangocairo
import sys
import gtk
import gobject
import os
import urllib
import xml.sax.saxutils
import webbrowser

from ConfigParser import SafeConfigParser

from ThemeParser import ThemeParser

from TwitterBackend import TwitterBackend, TwitterUpdateMethod, Timeline, TwitterResult

import traceback

PI = 3.141596

# get from PidginScreenelt
def scaleGdkPixbuf(pixbuf,size):
	newpixbuf = None
	try:
		icw = pixbuf.get_width()
		ich = pixbuf.get_height()
		aspect = float(icw)/ich
		if aspect < 1: newpixbuf = pixbuf.scale_simple(int(aspect*size),size,1)
		elif aspect > 1: newpixbuf = pixbuf.scale_simple(size,int(size/aspect),1)
		else: newpixbuf = pixbuf.scale_simple(size,size,1)
	except:
		None
	return newpixbuf

def escape_for_pango_markup(string):
	# escapes < > & ' "
	# for pango markup not to break
	if string is None:
		return
	if gtk.pygtk_version >= (2, 8, 0) and gtk.gtk_version >= (2, 8, 0):
		escaped_str = gobject.markup_escape_text(string)
	else:
		escaped_str = xml.sax.saxutils.escape(string, {"'": '&apos;',
													   '"': '&quot;'})

	return escaped_str

X_SIZE = 210
Y_SIZE = 510

# use gettext for translation
import gettext

_ = screenlets.utils.get_translator(__file__)

def tdoc(obj):
	obj.__doc__ = _(obj.__doc__)
	return obj

@tdoc
class TwitterScreenlet (screenlets.Screenlet):
	"""Displays tweets of your friends or latest public tweets and lets you post your own."""

	__name__	= 'TwitterScreenlet'
	__version__	= '0.9.8'
	__author__	= 'Guido Tabbernuk <boamaod@gmail.com>'
	__requires__ = ['python-twitter (>= 0.8~)', 'python-oauth2']
	__desc__	= __doc__	# set description to docstring of class

	__timeout = None
	
	__fixed = None
	__entry = None

	__status_on_tooltip = None

	__twitter = None

	# fix a leak
	__surface = None
	__play = None
	__cr = None
	__pcr = None
	
	__notifier = None
	_TwitterBackend__notifier = None
	access_key = ""
	access_secret = ""
	access_pin = ''

	request_key = ""
	request_secret = ""

	translator = _

	item_font = "Sans Medium 10"
#	account = ["", ""]
	layout = None

	__timeline = Timeline()

	show_public_timeline = True
	num_of_statuses = 20
	update_interval = 320
	show_tooltips = True

	header_height = 26
	footer_height = 35
	user_icon_size = 30
	real_window_height = 500

	window_height = real_window_height - header_height - footer_height

	window_x = 10
	window_y = 10

	window_width = 200

	highlight = -1
	entry_highlighting = True

	#for scroll
	statuses_offset = 0
	_buffer = None
	scroll_width = 20

	public_title = _("Public Tweets")
	friends_title = _("Friends' Tweets")

	status_format = "<span foreground=\"%s\"><b>%s</b></span> <span foreground=\"%s\">%s</span>"
	entry_tooltip = _("Use max 140 chars to make the point...\n<⇧ Shift> + <↵ Enter> to submit")
	status_tooltip = _("Double click to open in browser,\nuse wheel to scroll up/down the list")

	initialized = False

	def __init__ (self, **keyword_args):
		screenlets.Screenlet.__init__(self, width=X_SIZE, height=Y_SIZE,
									  uses_theme=True, **keyword_args)
		if not self.theme:
			self.theme_name="default"

		self.add_options_group(_('Appearance'), _('Presentation of the tweets'))

		self.add_option(BoolOption(_('Appearance'), 'show_public_timeline', self.show_public_timeline,
								   _('Show public timeline'),_('Show public timeline instead of tweets from friends')))

		self.add_option(StringOption(_('Appearance'), 'public_title',
			self.public_title,
			_('Public timeline label'),
			_('Label on the titlebar when showing tweets from public timeline')))

		self.add_option(StringOption(_('Appearance'), 'friends_title',
			self.friends_title,
			_("Followed tweets label"),
			_('Label on the titlebar when showing tweets of people followed')))

		self.add_option(IntOption(_('Appearance'), 'update_interval', 
								  self.update_interval, _('Update interval'), 
								  _('The interval for refreshing status (in seconds)'), min=1, max=9999))

		self.add_option(IntOption(_('Appearance'), 'num_of_statuses', 
								  self.num_of_statuses, _('Number of entries'), 
								  _('Number of tweets to display'),  min=0, max=100))

		self.add_option(FontOption(_('Appearance'), 'item_font', 
				self.item_font, _('Font to use'), 
				_('Font to use to display tweets')))

		self.add_option(BoolOption(_('Appearance'), 'entry_highlighting',
								  self.entry_highlighting, _('Highlight active entry'), 
								  _('Highlight entry under mouse cursor')))

		self.add_option(BoolOption(_('Appearance'), 'show_tooltips',
								  self.show_tooltips, _('Show tooltips'), 
								  _('Do you really want to see tooltips on the widget?')))

		self.add_option(IntOption(_('Appearance'), 'real_window_height',
								  self.real_window_height, _('Window height'), 
								  _('Height of the window'),  min=100, max=9999))

		self.add_option(IntOption(_('Appearance'), _('window_width'),
								  self.window_width, _('Window width'), 
								  _('Width of the window'),  min=150, max=9999))

		self.add_options_group(_('Account'), _('You need to get an Access PIN to authorize Screenlet to access \nyour Twitter account. \n\nPlease empty the PIN field and press Apply to open your Twitter \npage for authorization. Log onto your account to authorize if you \nare not logged on automatically. After getting a PIN code, please \nreturn to this dialog, enter the PIN and press Apply again. If you \nwant to change the account to use just clear the PIN entry field \nand press Apply again.'))

		self.add_option(StringOption(_('Account'), 'access_pin',
			self.access_pin,
			_("Access PIN"),
			_('Empty the field and click Apply to open URL to get Access PIN for the TwitterScreenlet')), realtime=False)

		self.add_option(StringOption(_('Account'), 'access_key', 
			self.access_key, _('Access key'), 
			'', hidden=True))

		self.add_option(StringOption(_('Account'), 'access_secret', 
			self.access_secret, _('Access secret'), 
			'', hidden=True))

		self.add_option(StringOption(_('Account'), 'request_key', 
			self.request_key, 'request key', 
			'', hidden=True))

		self.add_option(StringOption(_('Account'), 'request_secret', 
			self.request_secret, 'request secret', 
			'', hidden=True))

#		self.add_option(AccountOption(_('Account'), 'account', 
#									  self.account, _('Username/password'), 
#									  _('Enter your username and password here...')))

		# scrolling is for tweets
		self.resize_on_scroll = False

		self.__notifier = screenlets.utils.Notifier(self)
		self._TwitterBackend__notifier = self.__notifier
#		self.update_buffer()
#		self.redraw_canvas()

#		gobject.idle_add(self.update)
#		self.__timeout = gobject.timeout_add(3000, self.on_draw, self)

	def __setattr__(self, name, value):
		# call Screenlet.__setattr__ in baseclass (ESSENTIAL!!!!)
		screenlets.Screenlet.__setattr__(self, name, value)

		if not self.initialized:
			return

		if name == "update_interval":

			if value > 0:
				self.__dict__['update_interval'] = value
				if self.__timeout:
					gobject.source_remove(self.__timeout)
				self.__timeout = gobject.timeout_add(int(value) * 1000, self.update)
				print "timeout: " + str(int(value) * 1000)
			else:
				self.__dict__['update_interval'] = 1

		if name == 'access_secret':

			if self.show_public_timeline:
				self.__twitter = TwitterBackend(self, TwitterUpdateMethod.PUBLIC)
			else:
				self.__twitter = TwitterBackend(self, TwitterUpdateMethod.FRIENDS)

			self.__twitter.get_timeline_start()

		if name == 'show_tooltips':
			if self.__entry and self.__fixed:
				if self.show_tooltips:
					self.__entry.set_tooltip_text(self.entry_tooltip)
					self.__fixed.set_tooltip_text(self.status_tooltip)
				else:
					self.__entry.set_tooltip_text("")
					self.__fixed.set_tooltip_text("")

		if name == 'show_public_timeline':
			if self.__twitter:
				if self.show_public_timeline == False: # and self.access_key != '':
					self.__twitter.set_update_method(TwitterUpdateMethod.FRIENDS)
				else:
					self.__twitter.set_update_method(TwitterUpdateMethod.PUBLIC)
				
				self.__twitter.get_timeline_start()

		if name == 'access_pin':
			if self.__twitter and self.initialized:

#				print "PIN '" + self.access_pin + "'"

				if self.access_pin != "*******":

					if(len(self.access_pin) > 0):

						key = self.__twitter.get_access_key(self.access_pin, self.request_key, self.request_secret)
						if key is not None:
							self.access_key = key['oauth_token']
							self.access_secret = key['oauth_token_secret']
							self.__notifier.notify(_("Authentication successful!"))

							self.access_pin = "*******"

						else:
							self.__notifier.notify(_("Problem with your access PIN. A renewal could help!"))
			#				self.access_pin=""
					else:

						response = self.__twitter.open_access_url()
						url = response[0]
						if response[1] is not None and len(url) > 0:
							self.request_key = response[1]['oauth_token']
							self.request_secret = response[1]['oauth_token_secret']
							webbrowser.open_new_tab(url)
		#					self.access_key = ""
		#					self.access_secret = ""
						else:
							self.__notifier.notify(_("Problem connecting Twitter.com to update your access PIN!"))

		if name == 'public_title':
			self.resize_and_redraw()

		if name == 'friends_title':
			self.resize_and_redraw()

		if name == 'num_of_statuses':
			self.resize_and_redraw()

		if name == 'real_window_height':
#			if value < 100:
#				self.__dict__['window_height'] = 100

			for status in self.__timeline.statuses:
				status.buffer = None
			self.resize_and_redraw()

		if name == 'window_width':
#			if value < 100:
#				self.__dict__['window_height'] = 100
			self.__surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, self.window_width-5-self.user_icon_size, 300)
			self.resize_and_redraw()

		if name == 'item_font':
			print self.item_font
			self.resize_and_redraw()

		if name == 'entry_highlighting':
			self.update_buffer()
			self.redraw_canvas()

	def bare_windowsize(self):
		if not self.layout: return
		print "bare windowsize"
		self.window_x = self.layout.window.shadow_size
		self.window_y = 0

		#		self.window_width = self.layout.window.width
		self.window_height = self.real_window_height - self.header_height - self.footer_height;
		self.width = self.window_width + self.layout.window.shadow_size * 2
		self.height = self.header_height + self.footer_height + self.window_height + self.layout.window.shadow_size * 2
		self.modify_entry_pos()

	def resize_and_redraw(self):
		if not self.layout: return
		if not self.__twitter: return

		print "resize and redraw"

		for status in self.__timeline.statuses:
			status.buffer = None
			
		self.bare_windowsize()

		self.update_buffer()
		self.redraw_canvas()
		
	def get_border_width(self):
		if not self.layout: return 0
		ls = self.layout.status
		if ls.enable_border:
			return ls.border_width
		else:
			return 0

	def get_status_height(self, status):

		if not self.layout: return 0
		if not self.initialized:
			return 0
			
			
#		print "get status height"
		
		ls = self.layout.status

		status_text =  self.status_format % (ls.name_color.get_str(), 
						status.GetUser().GetScreenName(),
						ls.text_color.get_str(),
						escape_for_pango_markup(status.GetText()))

		if not self.__cr:
			 self.__cr = cairo.Context(self.__surface)
		self.__cr.clip()
		if not self.__pcr:
			self.__pcr = pangocairo.CairoContext(self.__cr)

		if not self.__play:
			self.__play = self.__pcr.create_layout()
		self.__play.set_markup(status_text)
		self.__play.set_single_paragraph_mode(False)
		self.__play.set_wrap(pango.WRAP_WORD_CHAR)


		font_desc = pango.FontDescription()
		font_desc.set_family(self.item_font)

		temp_buf = str.split(self.item_font)
		real_size=temp_buf[len(temp_buf)-1]
		font_desc.set_size(int(real_size) * pango.SCALE)
		font_desc.set_weight(5)
		self.__play.set_width((self.window_width-5-self.user_icon_size)*1024)
		self.__play.set_alignment(pango.ALIGN_LEFT)
		self.__play.set_ellipsize(pango.ELLIPSIZE_NONE)
		self.__play.set_justify(False)

		self.__play.set_font_description(font_desc)
		self.__pcr.update_layout(self.__play);

		t1, t2 = self.__play.get_extents()
		
	#	x_bearing, y_bearing, width, height, x_advance, y_advance = cr.text_extents(status_text)

	#	print status_text + "\n" + status.GetUser().GetScreenName() + ": " + str(len(status.GetText())) + " / " + str(t2[3]/1024)
		
	#	print status.GetUser().GetScreenName() + ": " + str(len(status.GetText())) + " / " + str(t1[0]) + "," +str(t1[1]) + "," +str(t1[2]) + "," +str(t1[3]) + " --- "+ str(t2[0]) + "," +str(t2[1]) + "," +str(t2[2]) + "," +str(t2[3])
	#	print status.GetUser().GetScreenName() + ": " + str(len(status.GetText())) + " / " + str(height)

		self.status_height = max(self.user_icon_size+5, t2[3]/1024+3)

		return self.status_height
	#		return self.status_height * self.num_of_statuses + self.get_border_width() * (self.num_of_statuses -1)


	def get_status_outer_height(self, status):
		return self.get_status_height(status) + self.get_border_width()
	

	def get_statuses_height(self):

		status_num = min(self.num_of_statuses, len(self.__timeline.statuses))

		adder = 0
		for index in range(status_num):
			status = self.__timeline.statuses[index]
			adder += self.get_status_outer_height(status)

	#	print str(status_num) + " || " + str(adder)

		return adder - self.get_border_width() # last one does not have border



	def modify_entry_pos(self):

		print "mod entry pos"

		#move text entry
		if self.__entry:
			self.__entry.set_size_request(int((self.window_width - 20) * self.scale), -1)

		if self.__fixed:
			self.__fixed.move(self.__entry, int((10 + self.window_x) * self.scale), int((self.window_y + self.header_height + self.window_height + 5) * self.scale))
		self.window.show_all()		

	def update(self):
		if self.__twitter:
			self.__twitter.get_timeline_start()
			print "updating..."

#		from guppy import hpy
#		h = hpy()
#		print h.heap()

		return True # timeout contintue

	def update_false(self):
		if self.__twitter:
			self.__twitter.get_timeline_start()
			print "false updating..."

		self.update_buffer()
		self.redraw_canvas()

		return False # timeout stop

	def on_after_set_atribute(self,name, value):
		"""Called after setting screenlet atributes"""
		#print name + ' is going to change from ' + str(value)
		pass

	def on_before_set_atribute(self,name, value):
		"""Called before setting screenlet atributes"""
		#print name + ' has changed to ' + str(value)
		pass


	def on_create_drag_icon (self):
		"""Called when the screenlet's drag-icon is created. You can supply
		your own icon and mask by returning them as a 2-tuple."""
		return (None, None)

	def on_composite_changed(self):
		"""Called when composite state has changed"""
		pass

	def on_drag_begin (self, drag_context):
		"""Called when the Screenlet gets dragged."""
		pass

	def on_drag_enter (self, drag_context, x, y, timestamp):
		"""Called when something gets dragged into the Screenlets area."""
		pass

	def on_drag_leave (self, drag_context, timestamp):
		"""Called when something gets dragged out of the Screenlets area."""
		pass

	def on_drop (self, x, y, sel_data, timestamp):
		"""Called when a selection is dropped on this Screenlet."""
		return False

	def on_focus (self, event):
		"""Called when the Screenlet's window receives focus."""
		pass

	def on_hide (self):
		"""Called when the Screenlet gets hidden."""
		pass

	def on_init (self):
		"""Called when the Screenlet's options have been applied and the 
		screenlet finished its initialization. If you want to have your
		Screenlet do things on startup you should use this handler."""
		print 'i just got started'

		self.width = self.width
		self.height = self.height

		# add  menu items from xml file
		self.add_default_menuitems(DefaultMenuItem.XML)
		# add menu item
		self.add_menuitem("refresh", _("Refresh"))
		# add default menu items
		self.add_default_menuitems()

		self.__entry = gtk.Entry(140)
		self.__entry.set_size_request(self.window_width,-1)
		self.__entry.set_has_frame(False)
		self.__fixed = gtk.Fixed()
		self.window.add(self.__fixed)
		self.__fixed.put(self.__entry, 0, 0)

#		self.__tooltips = gtk.Tooltip()

		if self.show_tooltips:
			self.__entry.set_tooltip_text(self.entry_tooltip)
			self.__fixed.set_tooltip_text(self.status_tooltip)

			self.bare_windowsize()

		#		self.modify_entry_pos()
		#		if not self.__twitter:
		#			self.__twitter = TwitterBackend(self, TwitterUpdateMethod.PUBLIC)

		#		self.update()

		if self.show_public_timeline:
			self.__twitter = TwitterBackend(self, TwitterUpdateMethod.PUBLIC)
		else:
			self.__twitter = TwitterBackend(self, TwitterUpdateMethod.FRIENDS)

		# because if it's available when starting it just obscures user
		self.access_pin=""

		self.__surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, self.window_width-5-self.user_icon_size, 300)

		self.initialized = True

		if not self.__timeout:
			self.__timeout = gobject.timeout_add(int(self.update_interval) * 1000, self.update)

		gobject.idle_add(self.update_false)

		#		self.update_buffer()
		#		self.redraw_canvas()

		self.resize_and_redraw()

#		print self.width, ", ", self.height

		#	if self.__timeout:
		#		gobject.source_remove(self.__timeout)
		#	self.__timeout = gobject.timeout_add(self.update_interval * 1000, self.update)
		#		print "timeout: " + str(int(value) * 1000)

		#		gobject.idle_add(self.update)
		#		self.__timeout = gobject.timeout_add(3100, self.update_buffer)
		#		self.__timeout = gobject.timeout_add(3200, self.redraw_canvas)
		#		self.__timeout = gobject.timeout_add(1000, self.update_false)

		#		self.window_height = self.header_height + self.footer_height + self.window_height + 2*self.layout.window.shadow_size

		#	print "win height: " + str(self.window_height)

		#	print self.access_key, self.access_secret, self.access_pin, self.request_key, self.request_secret


	def on_key_down(self, keycode, keyvalue, event):
		"""Called when a keypress-event occured in Screenlet's window."""

		if self.__twitter:

			key = gtk.gdk.keyval_name(event.keyval)

			if key == "Return" and (event.state & gtk.gdk.SHIFT_MASK):

	#			print "NUPP KÄIS"

				text = self.__entry.get_text()
				self.__entry.select_region(0, 140)
				self.__entry.set_sensitive(False)
				self.__twitter.post_message_start(text)
				self.__twitter.get_timeline_start()

	def on_load_theme (self):
		"""Called when the theme is reloaded (after loading, before redraw)."""
		options_file = sys.path[0]+"/themes/"+self.theme_name+"/options.conf"
		if os.path.exists(options_file): 
			self.layout = ThemeParser(options_file)
		else:
			raise "Invalid Theme. No options.conf"

		self.resize_and_redraw()

	def on_menuitem_select (self, id):
		"""Called when a menuitem is selected."""
		if id == "refresh":
			print "refresh"
			self.update()

	def get_status_index_under_pointer(self, x, y):
		try:
#		print self.scale
			y *= 1/self.scale
			if y > self.header_height and y < self.height - self.footer_height:
		
				y += self.statuses_offset
					# FIXME:

				status_num = len(self.__timeline.statuses)

				adder = self.header_height
				for index in range(status_num):
		#			print "st " + str(index) + " of " + str(status_num)
					status = self.__timeline.statuses[index]
					inter = self.get_status_outer_height(status)
		#			print str(adder) + " <= " + str(y) + " < " + str(inter+adder)
					if y>=adder and y<inter+adder:
		#			print status.GetUser().GetScreenName()
						return index
					adder += inter
				return -1

		

#				return self.__timeline.statuses[int((y - self.header_height + self.statuses_offset) /
#													(self.status_height + self.get_border_width()) )]

			else:
				return None
		except:
			return None

	def get_status_under_pointer(self, x, y):
		try:
			index = get_status_index_under_pointer(self, x, y)
			if index:
				return self.__timeline.statuses[index]
			else:
				return None
		except:
			return None

	def on_mouse_down (self, event):
		"""Called when a buttonpress-event occured in Screenlet's window. 
		Returning True causes the event to be not further propagated."""
		if event.button == 1:
			status = self.get_status_under_pointer(event.x, event.y)
			if status:
				return True
		return False

	def on_mouse_enter (self, event):
		"""Called when the mouse enters the Screenlet's window."""
		index = self.get_status_index_under_pointer(event.x, event.y)
		if index < 0 or index > len(self.__timeline.statuses): return False
		status = self.__timeline.statuses[index]
		if status and self.highlight != index:
	#		print status.GetUser().GetScreenName()
			self.highlight = index;
			self.update_buffer()
			self.redraw_canvas()

	def on_mouse_leave (self, event):
		"""Called when the mouse leaves the Screenlet's window."""
#		self.hide_tooltip()
#		self.hover = False
#		self.__status_on_tooltip = None
		#print 'mouse leave'
		self.highlight = -1
		self.status = None
		self.update_buffer()
		self.redraw_canvas()

	def on_mouse_move(self, event):
		"""Called when the mouse moves in the Screenlet's window."""

#		print 'mouse moves' + str(event.x) + " / "  + str(event.y)

		index = self.get_status_index_under_pointer(event.x, event.y)
		if index < 0 or index > len(self.__timeline.statuses): return False
		status = self.__timeline.statuses[index]
		if status and self.highlight != index:
	#		print "UUS HAILAIT"
			self.highlight = index
			self.update_buffer()
			self.redraw_canvas()
		if 0:
			if status and status != self.__status_on_tooltip:
				self.show_tooltip("%s\n%s" % (status.GetUser().GetScreenName(), 
									  escape_for_pango_markup(status.GetText()))
						  ,self.x+self.mousex,self.y+self.mousey)
				self.hover = True
				self.__status_on_tooltip = status
			elif status == None:
				self.hide_tooltip()
				self.hover = False
				self.__status_on_tooltip = None
			
	def on_mouse_up (self, event):
		"""Called when a buttonrelease-event occured in Screenlet's window. 
		Returning True causes the event to be not further propagated."""
		if event.button == 1 and self.highlight >= 0:
			status = self.__timeline.statuses[self.highlight]
			if status:
				os.system('xdg-open http://twitter.com/' + status.GetUser().GetScreenName() + ' &')
				return True
		return False

	def on_quit (self):
		"""Callback for handling destroy-event. Perform your cleanup here!"""
		# clear timeout
		if self.__timeout:
			gobject.source_remove(self.__timeout)

	def on_realize (self):
		""""Callback for handling the realize-event."""
		pass

	def on_scale (self):
		"""Called when Screenlet.scale is changed."""
		self.resize_and_redraw()

	def on_scroll_up (self):
		"""Called when mousewheel is scrolled up (button4)."""
		self.statuses_offset -= self.scroll_width
		if self.statuses_offset < 0 : self.statuses_offset = 0
		self.redraw_canvas()
#	print "offset: " + str(self.statuses_offset)
		return True

	def on_scroll_down (self):
		"""Called when mousewheel is scrolled down (button5)."""
		self.statuses_offset += self.scroll_width
#	print "offset: " + str(self.statuses_offset) + " --- " + str(self.get_statuses_height() - self.window_height) + " ("  + str( self.buffer_height) + ")"
		if self.statuses_offset > self.get_statuses_height() - self.window_height:
			if self.get_statuses_height() - self.window_height > 0: 	
				self.statuses_offset = self.get_statuses_height() - self.window_height
			else:
				self.statuses_offset = 0
		self.redraw_canvas()
		return True
	  
	def on_show (self):
		"""Called when the Screenlet gets shown after being hidden."""
		pass

	def on_switch_widget_state (self, state):
		"""Called when the Screenlet enters/leaves "Widget"-state."""
		pass

	def on_unfocus (self, event):
		"""Called when the Screenlet's window loses focus."""
		pass

	def on_draw (self, ctx):
		"""In here we load the theme"""
#		print "on draw (i'm innocent!)"

		if not self.layout: return

		l = self.layout
		ctx.save()
		ctx.scale(self.scale , self.scale)
		ctx.translate(self.window_x, self.window_y)

		#draw shadow
		if l.window.shadowed:
			shadow_size = l.window.shadow_size
			self.draw_shadow(ctx, -self.window_x, -self.window_y, self.window_width, self.real_window_height ,shadow_size,l.window.shadow_color)

		# draw header
		ctx.save()
		self.round_rectangle(ctx, 0, 0, self.window_width, self.header_height, l.window.radius, l.window.radius, 0, 0)
		ctx.clip()
		linear = cairo.LinearGradient(0, 0, 0, self.header_height)
		linear.add_color_stop_rgba(0, *l.header.start_color.get())
		linear.add_color_stop_rgba(1.0,*l.header.end_color.get())
		ctx.set_source(linear)
		ctx.paint()
		ctx.restore()

#		if self.show_public_timeline == False and self.access_key != '': header_str = self.friends_title 
		if self.show_public_timeline == False: header_str = self.friends_title 
		else: header_str = self.public_title


		if l.header.hommage_to_twitter:
			ctx.save()
			self.draw_blurb(ctx, header_str, 10, 5, self.item_font, self.window_width,
					   allignment=pango.ALIGN_LEFT,
					   weight=pango.WEIGHT_BOLD,
					   ellipsize=pango.ELLIPSIZE_NONE, howlong=5)


			ctx.restore()

		ctx.save()
		ctx.set_source_rgba(*l.header.title_color.get())
		self.draw_text(ctx, header_str, 10, 5, self.item_font, self.window_width,
					   allignment=pango.ALIGN_LEFT,
					   weight=pango.WEIGHT_BOLD,
					   ellipsize=pango.ELLIPSIZE_NONE)


		ctx.restore()

		# draw twitter logo
		#ctx.save()
		#ctx.translate(120,6)
		#ctx.scale(.4,.4)
		#self.theme.render(ctx, 'logo')
		#ctx.restore()

		# draw status buffer(refreshed by update_buffer())
		ctx.save()
		if self._buffer:
			ctx.translate(0,self.header_height)
			ctx.set_source_rgba(0,0,0,0)
			ctx.rectangle(0,0,self.window_width,self.window_height)
			ctx.clip()
			ctx.set_operator(cairo.OPERATOR_OVER)
			ctx.set_source_pixmap(self._buffer, 0, -self.statuses_offset)
			ctx.paint()
		ctx.restore()

		# draw footer
		ctx.save()
		ctx.translate(0, self.header_height + self.window_height)
		self.round_rectangle(ctx, 0, 0, self.window_width, self.footer_height, 0, 0, l.window.radius, l.window.radius)
		ctx.clip()
		linear = cairo.LinearGradient(0, 0, 0, self.footer_height)
		linear.add_color_stop_rgba(0.0, *l.footer.start_color.get())
		linear.add_color_stop_rgba(1.0, *l.footer.end_color.get())
		ctx.set_source(linear)
		ctx.paint()
		ctx.restore()

		ctx.restore()

	def draw_blurb (self, ctx, header_str, x, y, item_font, window_width, howlong,
					   allignment=pango.ALIGN_LEFT,
					   weight=pango.WEIGHT_BOLD,
					   ellipsize=pango.ELLIPSIZE_NONE):

#	def draw_text(self, ctx, text, x, y,  font, width, allignment=pango.ALIGN_LEFT,alignment=None,justify = False,weight = 0, ellipsize = pango.ELLIPSIZE_NONE, is_single_p=False):

		howlong = float(howlong)

		if not self.layout.status:
			return

		#		ls = self.layout.status

		o1 = o2 = o3 = 1

		#	o1, o2, o3, o4 = ls.odd_line_color.get()
		adder = float(0)
		for adder in range(int(howlong)):
			coef = (howlong-adder)/(howlong*1.5)
			ctx.set_source_rgba(1,1,1,coef)
			self.draw_text(ctx, header_str, x-adder, y-adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x+adder, y+adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x-adder, y+adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x+adder, y-adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x, y+adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x, y-adder, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x+adder, y, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)
			self.draw_text(ctx, header_str, x-adder, y, self.item_font, self.window_width,
				   allignment=pango.ALIGN_LEFT,
				   weight=pango.WEIGHT_BOLD,
				   ellipsize=pango.ELLIPSIZE_NONE)




	def on_draw_shape (self, ctx):
		self.on_draw(ctx)

	def on_get_timeline (self, timeline, result):
		""" call by TwitterBackend thread"""
		if TwitterResult.ERROR == result:
			self.__notifier.notify(_("Failed to get timeline"))
			return

		print "got timeline"
		self.__timeline = timeline
		self.resize_and_redraw()

	def on_post_message (self, result):
		""" call by TwitterBackend thread"""
		if TwitterResult.ERROR == result:
			self.__notifier.notify(_("Failed to post the message!"))
		else:
			self.__entry.set_text("")

		self.__entry.set_sensitive(True)

	def update_buffer(self):
		if not self.window.window: return
		if not self.layout: return

#		print "update bufffer"

#		self.statuses_offset = 0

		status_num = max(self.num_of_statuses, len(self.__timeline.statuses))
#		self.buffer_height = status_num * self.status_height + (status_num -1) * self.get_border_width()

		self.buffer_height = status_num * 300

		self._buffer = gtk.gdk.Pixmap(self.window.window, 
									int(self.window_width), int(self.buffer_height), -1)

		ctx = self._buffer.cairo_create()
		self.clear_cairo_context(ctx)
		ctx.set_source_rgba(1,1,1,1)

#	print "offset_update_buf: " + str(self.statuses_offset)
#	ctx.set_source_pixmap(self._buffer, 0, -self.statuses_offset)

#		self.draw_status_bg(ctx, status_num)


# siin on asjad

#		status_num = max(self.num_of_statuses, len(self.__timeline.statuses))

#		status_num = len(self.__timeline.statuses)

		status_num = min(self.num_of_statuses, len(self.__timeline.statuses))


		ctx.save()
		index = 0
#	print "statuses to disp: " + str(status_num)
		for index in range(status_num):
#		print "current: " + str(index)

			status = self.__timeline.statuses[index]
			self.draw_user_status(ctx, status, index)
			ctx.translate(0, self.get_status_height(status))
			if index < status_num-1: ctx.translate(0, self.get_border_width())
		# the last one doesn't have border down of it
		
		self.draw_status_outro(ctx, index+1)
		ctx.translate(0, self.window_height)
		ctx.translate(0, self.get_border_width())
		ctx.restore()





	def draw_status_outro (self, ctx, index):
		""" draw user status outro gradient"""

		if not self.window.window:
			return

		if not self.layout.status:
			return

		ls = self.layout.status

		# draw outro
		ctx.save()

	#	pat = cairo.LinearGradient (0.0, 0.0, 0.0, 1.0)
	#	pat.add_color_stop_rgba (1, 0.7, 0, 0, 0.5) # First stop, 50% opacity
	#	pat.add_color_stop_rgba (0, 0.9, 0.7, 0.2, 1) # Last stop, 100% opacity



		o1, o2, o3, o4 = ls.odd_line_color.get()
		e1, e2, e3, e4 = ls.even_line_color.get()

		lg3 = cairo.LinearGradient(0.0, 0.0,  0.0, self.window_height)
		if  index % 2: # index 0 = line 1
			lg3.add_color_stop_rgba(0, o1, o2, o3, o4)		 
		else:
			lg3.add_color_stop_rgba(0, e1, e2, e3, e4)		 
	#	lg3.add_color_stop_rgba(0.5, 1, 1, 0, 1) 
		lg3.add_color_stop_rgba(1, 1, 1, 1, 0) 

	#	linear = cairo.LinearGradient(0, 0, 0, self.window_height)
	#	o1, o2, o3, o4 = ls.odd_line_color.get()
	#	e1, e2, e3, e4 = ls.even_line_color.get()

	#	linear.add_color_stop_rgba(1, 0.7, 0, 0, 0.5)		 
	#	linear.add_color_stop_rgba(0, 0.9, 0.7, 0.2, 1)		 

	#	if  index % 2: # index 0 = line 1
	#		linear.add_color_stop_rgba(0, o1, o2, o3, o4)		 
	#		linear.add_color_stop_rgba(1, e1, e2, e3, e4)		 
	#	else:
	#		linear.add_color_stop_rgba(1, o1, o2, o3, o4)		 
	#		linear.add_color_stop_rgba(0, e1, e2, e3, e4)		 

	#	linear = cairo.LinearGradient(0, 0, self.window_width, self.window_height)		  
	#	ctx.set_source_rgba(*ls.odd_line_color.get())
	#	ctx.set_source_rgba(0.8, 0.1, 0.3, 0.7)
		ctx.set_source(lg3)					 
		self.draw_rectangle(ctx,0,0,self.window_width,self.window_height)
	#	ctx.fill()		 

		ctx.translate(0, self.window_height)
		if ls.enable_border:
			ctx.save()
			ctx.set_source_rgba(*ls.border_color.get())
			self.draw_rectangle(ctx,0,0,self.window_width, self.get_border_width())
			ctx.restore()
			ctx.translate(0, self.get_border_width())

		ctx.restore()



	def draw_user_status (self, ctx, status, index):
		""" draw user status"""


		if not self.window.window:
			return

		if not self.layout.status:
			return

		ls = self.layout.status



#status background

		text_color = ls.text_color.get_str()
		name_color = ls.name_color.get_str()

		ctx.save()
	#	print index % 2
		if self.entry_highlighting and index == self.highlight:

			if  index % 2: # index 0 = line 1
				ctx.set_source_rgba(*ls.even_line_hl_color.get())							  
				text_color = ls.even_line_hl_text_color.get_str()
			else:
				ctx.set_source_rgba(*ls.odd_line_hl_color.get())							  
				text_color = ls.even_line_hl_text_color.get_str()
		else:
			if  index % 2: # index 0 = line 1
				ctx.set_source_rgba(*ls.even_line_color.get())
			else:
				ctx.set_source_rgba(*ls.odd_line_color.get())

		self.draw_rectangle(ctx,0,0,self.window_width,self.get_status_height(status))

		status_num = min(self.num_of_statuses, len(self.__timeline.statuses))

		ctx.translate(0, self.get_status_height(status))
		if ls.enable_border and index < status_num - 1:
			ctx.save()
			ctx.set_source_rgba(*ls.border_color.get())
			self.draw_rectangle(ctx,0,0,self.window_width, self.get_border_width())
			ctx.restore()
			ctx.translate(0, self.get_border_width())


		ctx.restore()



		if status.buffer == None:

			status_text =  self.status_format % (name_color, 
											status.GetUser().GetScreenName(),
											text_color,
											escape_for_pango_markup(status.GetText()))

#			print len(status.GetText())
			

#			buffer = gtk.gdk.Pixmap(self.window.window, 
#									int(self.window_width), int(self.status_height), -1)

			buffer = gtk.gdk.Pixmap(self.window.window, 
									int(self.window_width),
					self.get_status_height(status),
						-1)

			text_ctx = buffer.cairo_create()
			self.clear_cairo_context(text_ctx)
			text_ctx.set_source_rgba(1,1,1,1)


			self.draw_text(text_ctx, status_text, 
						   self.user_icon_size + 4, 2, 
						   self.item_font, 
						   self.window_width-5-self.user_icon_size, 
						   allignment=pango.ALIGN_LEFT, 
						   weight=5,
						   ellipsize=pango.ELLIPSIZE_NONE)
			status.buffer = buffer


		ctx.save()
		#ctx.set_source_rgba(0,0,0,0)
		#ctx.rectangle(0,0,self.window_width, self.status_height)
		#ctx.clip()
		ctx.set_operator(cairo.OPERATOR_OVER)
		ctx.set_source_pixmap(status.buffer, 0, 0)
		ctx.paint()
		ctx.restore()

		self.draw_user_icon(ctx, 2, 2, self.user_icon_size, self.user_icon_size, 4.0, 1, self.__timeline.users[status.GetUser().GetId()])

	def draw_text(self, ctx, text, x, y,  font, width, allignment=pango.ALIGN_LEFT,alignment=None,justify = False,weight = 0, ellipsize = pango.ELLIPSIZE_NONE, is_single_p=False):
		"""Draws text"""

		ctx.save()
		ctx.translate(x, y)
		if self.p_layout == None :
			self.p_layout = ctx.create_layout()
		else:
			ctx.update_layout(self.p_layout)
		if self.p_fdesc == None:self.p_fdesc = pango.FontDescription()
		else: pass
		self.p_fdesc.set_family(font)
		temp_buf = str.split(font)
		real_size=temp_buf[len(temp_buf)-1]
		self.p_fdesc.set_size(int(real_size) * pango.SCALE)
		self.p_fdesc.set_weight(weight)
		self.p_layout.set_font_description(self.p_fdesc)
		self.p_layout.set_width(width * pango.SCALE)
		self.p_layout.set_alignment(allignment)
		if alignment != None:self.p_layout.set_alignment(alignment)
		self.p_layout.set_justify(justify)
		self.p_layout.set_ellipsize(ellipsize)
		self.p_layout.set_markup(text)
		###
		self.p_layout.set_single_paragraph_mode(False)
		self.p_layout.set_wrap(pango.WRAP_WORD_CHAR)
		###

#	x1, y1, x2, y2 = ctx.clip_extents()

#	print str(y2-y1) 	

		ctx.show_layout(self.p_layout)
		ctx.restore()


	# from PidginScreenlet
	# Draw User Icon (Display Picture) 
	def draw_user_icon (self, ctx, x, y, w, h, rounding_radius, transparency, user):
		if user.iconPixbuf:
			ctx.save()
			ctx.translate(x, y)
			r = rounding_radius
			if r: self.round_rectangle(ctx,0,0,w,h,r,r,r,r)
			else: ctx.rectangle(0,0,w,h)
			ctx.clip()
			ctx.set_source_pixbuf(scaleGdkPixbuf(user.iconPixbuf,self.user_icon_size), 0, 0)
			ctx.paint_with_alpha(transparency)
			#ctx.paint()
			ctx.restore()

	# from PidginScreenlet
	# r1: top-left radius, r2: top-right radius, 
	# r3: bottom-left radius, r4: bottom-right radius
	def round_rectangle(self, ctx, x, y, width, height, r1, r2, r3, r4):
		ctx.move_to(x+r1, y)
		ctx.line_to(x+width-r2,y)
		# top right
		if r2 > 0:
				ctx.arc(x+width-r2, y+r2, r2, -PI/2.0, 0)
		ctx.line_to(x+width,y+height-r4)
		# bottom right
		if r4 > 0:
				ctx.arc(x+width-r4, y+height-r4, r4, 0, PI/2.0)
		ctx.line_to(x+r3, y+height)
		# bottom left
		if r3 > 0:
				ctx.arc(x+r3, y+height-r3, r3, PI/2.0, PI)
		ctx.line_to(x,y+r1)
		# top left
		if r1 > 0:
				ctx.arc(x+r1, y+r1, r1, PI, PI*1.5)


	def draw_status_bg(self, ctx, status_num):
		""" draw status background"""
		
		if not self.layout: return

		ls = self.layout.status
		ctx.save()
		for index in range(status_num):
			if  index % 2: # index 0 = line 1
				ctx.set_source_rgba(*ls.even_line_color.get())
			else:
				ctx.set_source_rgba(*ls.odd_line_color.get())
				
			self.draw_rectangle(ctx,0,0,self.window_width,self.get_status_height(self.__timeline.statuses[index]))

			ctx.translate(0, self.get_status_height(self.__timeline.statuses[index]))
			if ls.enable_border and index < status_num - 1:
				ctx.save()
				ctx.set_source_rgba(*ls.border_color.get())
				self.draw_rectangle(ctx,0,0,self.window_width, self.get_border_width())
				ctx.restore()
				ctx.translate(0, self.get_border_width())

		ctx.restore()

		
if __name__ == "__main__":
	# create new session
	
#	import gc
#	gc.set_debug(gc.DEBUG_LEAK)
	
	import screenlets.session
	screenlets.session.create_session(TwitterScreenlet, threading=True)
