#!/usr/bin/env python

# WallpaperClockScreenlet by Natan Yellin
# Based on the original screenlet by Helder Fraga

# (C) 2008 Natan Yellin and Helder Fraga 

#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.


import decimal
import math
import os
import random
import time
from commands import getoutput
from datetime import datetime
from sys import path
from xdg import BaseDirectory

try:
	import Image
except:
	import sys
	screenlets.show_error(None, _("Please install the python image module"))
	sys.exit()

import gtk
import gobject

import screenlets
import screenlets.menu
from screenlets.options import StringOption, BoolOption, ImageOption

# use gettext for translation
import gettext

_ = screenlets.utils.get_translator(__file__)

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

@tdoc
class WallpaperClockScreenlet (screenlets.Screenlet):
	"""A Screenlet that displays wallpaper clocks. You can download \
	wallpaper clocks from http://www.vladstudio.com/wallpaperclock/ \
	and install them by dropping them on the screenlet."""
	
	# --------------------------------------------------------------------------
	# meta-info, options
	# --------------------------------------------------------------------------
	
	__name__		= 'WallpaperClockScreenlet'
	__version__		= '2.6'
	__author__		= 'Natan Yellin (Based on Helder Fraga\'s original screenlet.)'
	__desc__		= __doc__
	
	GNOME_WALLPAPER_OPTIONS = ['centered', 'scaled', 'stretched', 'wallpaper', 'zoom']	
	THUMB_WIDTH = 50
	THUMB_HEIGHT = 37
	
	def __init__ (self, **keyword_args):
		screenlets.Screenlet.__init__(self, width=72, height=92,
			uses_theme=True, drag_drop=True, **keyword_args)
		
		self.wpath = os.environ['HOME'] + '/.WallpaperClockScreenlet'
		
		self.time = datetime.now()
		self.timeout = None
		self.started = False
		
		self.dec = decimal.Decimal
		self.image = None
		self.image1 = None	
		self.current_file_index = 0
		
		self.month = ''
		self.day = ''
		self.hour = ''
		self.minute = ''
		self.weekday = ''
		self.home = getoutput("echo $HOME")
			
		# set theme
		self.theme_name = "default"
		
		if not os.path.isdir(self.wpath):
			os.mkdir(self.wpath)
		if not os.path.isdir(self.wpath + '/wallpapers'):
			os.mkdir(self.wpath + '/wallpapers')
		
		self.wall_sel = os.listdir(self.wpath + '/wallpapers')
		self.wall_sel.extend(os.listdir(self.get_screenlet_dir() + '/wallpapers'))
		self.wall_sel.sort()
		
		# load the thumbnails (and insert None whenever no thumbnail can be found)
		self.thumbs = []
		for clock in self.wall_sel:
			self.thumbs.append(None)
			for path in (self.wpath, self.get_screenlet_dir()):
				if os.path.exists(path + '/wallpapers/' + clock + '/preview100x75.jpg'):
					self.thumbs[len(self.thumbs)-1] = path + '/wallpapers/' + clock + '/preview100x75.jpg'
					break
		
		# Add clock related options
		self.add_options_group(_('Clock'), _('Clock related settings'))		
		self.add_option(StringOption(_('Clock'), 'hour_format', '24', _('Hour-Format'),
			_('The hour-format (12/24)'), choices=['12', '24'], callback=self.update))
		
		# Wallpaper related settings
		self.add_options_group(_('Wallpaper'), _('Wallpaper settings'))
		self.add_option(BoolOption(_('Wallpaper'), 'random_wallpaper', False, 
			_('Use random'), _('Randomize theme on startup'), callback=self.set_random_wallpaper))
		self.add_option(StringOption(_('Wallpaper'), 'wall', 'alittlemotivation.wcz',
			_('Current Wallpaper Clock'), '', choices=self.wall_sel, callback=self.update))		
		self.add_option(StringOption(_('Wallpaper'), 'gnome_wallpaper_option',
			'wallpaper', 'Drawing style of the wallpaper. \
			(Also useful for multi-screen setups.)', '', choices=self.GNOME_WALLPAPER_OPTIONS,
			callback=self.set_wallpaper_options))
		self.add_option(BoolOption(_('Wallpaper'), 'xfce_workarround', False, 
			_('XFCE Workarround'), _('If you have a refresh problem in xfce desktop'),
			callback=self.update))
		
		self.create_menu()
		
		if self.random_wallpaper:
			self.set_random_wallpaper()
		
		for month in xrange(1,12):
			for day in xrange(1, 31):
				self.get_zodiac(day, month)
		
		self.started = True
		self.update()
		
		# Synchronizes so the timeout occurs roughly at minute-changes
		# This call calculates the number of seconds left in the current minute and 
		lSecUntilSynch = (60 - time.gmtime()[5])
		
		# Leave 2 seconds room for the time it takes the wallpaper to update (just a rough estimate...)
		#if lSecUntilSynch > 3:
		#	lSecUntilSynch = lSecUntilSynch - 2
		
		self.__timeout = gobject.timeout_add(lSecUntilSynch * 1000, self.sync_with_minute_change)
	
	def create_menu (self):
		"""Populates the screenlets' right-click menu."""
		root_item = gtk.MenuItem(_("Change Wallpaper"))
		root_item.show()
		self.menu.append(root_item)
		
		# create the submenu w/ options for changing the wallpaper
		sub_menu = gtk.Menu()
		root_item.set_submenu(sub_menu)
		
		# add a menu item for choosing a random wallpaper
		screenlets.menu.add_menuitem(sub_menu, _("Pick a random wallpaper"),
			self.menuitem_callback, "random")
		
		# add a submenu containing all of the available wallpapers
		self.clocks_menu = screenlets.menu.add_submenuitem(sub_menu,
			"Wallpaper Clocks", self.wall_sel, self.thumbs, (self.THUMB_WIDTH,
			self.THUMB_HEIGHT), self.menuitem_callback, "change")
		
		self.add_menuitem("install", _("Install Wallpaper Clock"))
		self.add_menuitem("visit", _("Download more Clocks"))
		self.add_menuitem("wallinfo", _("View Wallpaper info"))
		self.add_default_menuitems()
	
	def show_install_dialog (self):
		"""Create and show the install-dialog."""
		# create filter
		flt = gtk.FileFilter()
		flt.add_pattern('*.wcz')

		# create dialog
		dlg = gtk.FileChooserDialog(buttons=(gtk.STOCK_CANCEL, 
			gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
		dlg.set_current_folder(os.environ['HOME'])
		dlg.set_title((_('Install a Wallpaper Clock')))
		dlg.set_filter(flt)
		
		# run
		resp		= dlg.run()
		filename	= dlg.get_filename()
		dlg.destroy()
		if resp == gtk.RESPONSE_OK:
			# try installing
			self.window.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
			self.install (filename)
			self.window.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
	
	def install (self, filename):
		"""Install a screenlet from a given archive-file. Extracts the
		contents of the archive to the user's screenlet dir."""
		print 'Installing %s' % filename

		basename	= os.path.basename(filename)
		extension	= str(filename)[-3:]

		unzip_command = 'unzip -o %s -d %s'
		
		if extension.lower() == 'wcz':
			if not os.path.isdir(self.wpath + '/wallpapers/' + basename):
				os.mkdir(self.wpath + '/wallpapers/' + basename)
			os.system(unzip_command % (chr(34) + filename + chr(34),
				self.wpath + '/wallpapers/' + basename))
			self.update_wallpaper_list(basename)
			self.wall = basename
			screenlets.show_message(self,_("Wallpaper clock has been succesfully installed."))
			return True
		else:
			screenlets.show_message(self,"The archive doesn't seem to contain a valid wallpaper clock archive. \
				You may try to extract it manually")
			return False
	
	def on_draw (self, ctx):
		ctx.scale(self.scale*0.7, self.scale*0.7)
		if self.theme:
			# TODO: If something is dragged over, lighten up the whole thing
			self.theme.render(ctx, 'WallpaperClock-bg')
	
	def on_drop (self, x, y, sel_data, timestamp):
		"""Handler for drops. Installs the dropped file."""
		filename = ''
	
		txt = sel_data.get_text()
		if txt is not None:
			if txt[-1] == '\n':
				txt = txt[:-1]
			txt.replace('\n', '\\n')
		
			if txt.startswith('file://'):
				filename = txt[7:]
			else:
				screenlets.show_error(self, _('Invalid string: %s.') % txt)
		else:
			uris = sel_data.get_uris()
			if uris is not None and len(uris)>0:
				filename = uris[0][7:]
		
		if filename != '':
			self.install (filename)	
	
	def position(self, now=None): 
		dec = decimal.Decimal
		if now is None: 
			now = datetime.now()

		diff = now - datetime(2001, 1, 1)
		days = dec(diff.days) + (dec(diff.seconds) / dec(86400))
		lunations = dec("0.20439731") + (days * dec("0.03386319269"))

		return lunations % dec(1)
	
	def sync_with_minute_change(self):
		# Add the default 60-sec time
		self.__timeout = gobject.timeout_add(60000, self.update)
		# And, update current wallpaper
		self.update()		

		# We don't want this timeout to get called again.
		# We only need it when initiating (and synchronizing with clock)
		return False
		
	def update_wallpaper_list (self, filename):
		"""Inserts filename into the list of available wallpapers
		and adds filename and it's thumbnail to the right-click menu."""
		# find the file's lexographical position in the list 
		i = 0
		while i < len(self.wall_sel) and cmp(self.wall_sel[i], filename) == -1:
			i += 1
		
		# insert it into the list at the right location
		self.wall_sel.insert(i, filename)
		
		# create the menuitem
		item = screenlets.menu.ImageMenuItem(label=filename)
		
		# load the thumbnail if it exists
		if os.path.exists(self.wpath + '/wallpapers/' + filename + '/preview100x75.jpg'):
			self.thumbs.insert(i, self.wpath + '/wallpapers/' + filename + '/preview100x75.jpg')
			pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.thumbs[i], self.THUMB_WIDTH,
				self.THUMB_HEIGHT)
			item.set_image_from_pixbuf(pixbuf)
		# if the thumbnail doesn't exist, let gtk load a broken-image thumbnail
		else:
			self.thumbs.insert(i, None)
			item.set_image_from_file('')
		
		# show the menuitem and attach it to the menu
		item.show()
		self.clocks_menu.insert(item, i)

	def phase(self, pos): 
		dec = decimal.Decimal
		index = (pos * dec(8)) + dec("0.5")
		index = math.floor(index)
		return [_("New Moon"),
			_("Waxing Crescent"),
			_("First Quarter"),
			_("Waxing Gibbous"),
			_("Full Moon"),
			_("Waning Gibbous"),
			_("Last Quarter"),
			_("Waning Crescent")][int(index) & 7]

	def get_zodiac(self, day, month):
		"""Finds the zodiac and returns it."""
		# all zodiacs in order of the months
		zodiac = [_('Capricorn'), _('Aquarius'),
			_('Pisces'), _('Aries'), _('Taurus'),
			_('Gemini'), _('Cancer'), _('Leo'),
			_('Virgo'), _('Libra'), _('Scorpio'),
			_('Sagittarius')]
		
		# the midpoints each month where one zodiac
		# ends and the next begins, in month order
		midpoint = [19, 18, 20, 19, 20,
			20, 22, 22, 22, 22, 21, 21]
				
		# deal with december where we need to wrap
		# around to the first zodiac
		if month == 12 and day > midpoint[month-1]:
			return zodiac[0]
		
		# if it's the first half of the month,
		# return the appropriate zodiac
		elif day <= midpoint[month-1]:
			return zodiac[month-1]
		
		# if it's the second half of the month,
		# return the next zodiac in the list
		else:
			return zodiac[month]
		
	def set_random_wallpaper(self):
		"""Sets the wallpaper to a random wallpaper clock."""
		self.wall = self.wall_sel[random.randint(0, len(self.wall_sel) - 1)]
	
	def set_wallpaper_options(self):
		"""Sets the GNOME/KDE wallpaper options."""
		os.system("gconftool-2 -t string -s /desktop/gnome/background/picture_options "
			+ self.gnome_wallpaper_option)
		
		if self.gnome_wallpaper_option == 'stretched': 
			kde_wall = 6
		else:
			kde_wall = 7
		try:
			os.system("/usr/bin/dcop kdesktop KBackgroundIface setWallpaper " + self.wpath + "/wallpaper.png " + kde_wall)
		except:
			pass
		
	def get_day (self):
		"""Only needed for the service."""
		return self.time.strftime("%d")
		
	def get_month (self):
		"""Only needed for the service."""
		return self.time.strftime("%m")
		
	def get_hour24 (self):
		"""Only needed for the service."""
		return self.time.strftime("%H")
		
	def get_hour (self):
		"""Only needed for the service."""
		if self.hour_format == '24' :
			return self.time.strftime("%H")
		elif self.hour_format == '12' :
			return self.time.strftime("%I")
			
	def get_minute (self):
		"""Only needed for the service."""
		return self.time.strftime("%M")
		
	def get_weekday (self):
		"""Only needed for the service."""
		return self.time.strftime("%w")
		
	def get_year (self):
		"""Only needed for the service."""
		return self.time.strftime("%y")

	def set_image(self):
		#print "Point 1: " +str(time.localtime())
		#print "Point 1: " +str(datetime.now())
		if self.wall != '':
			# load the background image and determine the path
			try:
				self.image = Image.open(self.wpath+'/wallpapers/' +self.wall+'/bg.jpg')
				path = self.wpath + '/wallpapers/' + self.wall
			except:
				self.image = Image.open(self.get_screenlet_dir() + '/wallpapers/' + self.wall + '/bg.jpg')
				path = self.get_screenlet_dir() + '/wallpapers/' + self.wall
			
			# load the am/pm image and paste it onto the background
			if self.hour_format == '12' and os.path.isfile(path + '/am.png'):
				try:
					if int(self.get_hour24())> 12:
						self.image1 = Image.open(path + '/pm.png')
						self.image.paste(self.image1, (0,0), self.image1)
					else:
						self.image1 = Image.open(path + '/am.png')
						self.image.paste(self.image1, (0,0), self.image1)
						#self.hour = str(int(self.hour)/2)
				except:
					pass
			
			# load the other images and paste them onto the background
			for img in ("minute", "hour", "day", "month", "weekday", "moonphase", "zodiac"):
				try:
					self.image1 = Image.open(path + '/' + img + getattr(self, img) + '.png')
					self.image.paste(self.image1, (0,0), self.image1)
				except:
					pass
			
			# save the file to the location we just selected. this is a slow operation
			self.image.save(self.wpath + "/wallpaper.png")
			
			if self.xfce_workarround:
				os.system ("killall -USR1 xfdesktop &")
			
			os.system("gconftool-2 -t string -s /desktop/gnome/background/picture_filename %s/wallpaper.png"
				% self.wpath)
			#os.system("gconftool-2 -t bool -s /desktop/gnome/background/draw_background False")
			#os.system("gconftool-2 -t bool -s /desktop/gnome/background/draw_background True")

			try:
				os.system("xfconf-query -c xfce4-desktop -p /backdrop/screen0/monitor0/image-path -s "+ self.imagepath + 'wallpaper.png')
				os.system("xfconf-query -c xfce4-desktop -p /backdrop/screen0/monitor0/image-show -s true")
				os.system("xfconf-query -c xfce4-desktop -p /backdrop/screen0/monitor0/image-style -s 0")
			except:
				pass
			
			if self.gnome_wallpaper_option == 'stretched': 
				kde_wall = 6
			else:
				kde_wall = 7
			try:
				os.system("/usr/bin/dcop kdesktop KBackgroundIface setWallpaper " + self.wpath
					+ "/wallpaper.png" + kde_wall)
			except:
				pass
			
	def update(self):
		if not self.started:
			return
		dec = decimal.Decimal
		
		self.time = datetime.now()
		
		self.minute = self.get_minute()
		self.hour = self.get_hour()
		self.day = self.get_day()
		self.month = self.get_month()
		self.year = self.get_year()
		
		self.hour24 = self.get_hour24()
		self.weekday = self.get_weekday()
		
		pos = self.position()
		self.moon = int(((float(pos))*100)/3.333333) +1
		self.moon = str(self.moon)
		phasename = self.phase(pos)

		self.zodiac = self.get_zodiac(int(self.day),int(self.month))
		
		if os.path.isfile (self.wpath+'/wallpapers/' +self.wall+'/hour25.png') or \
			os.path.isfile(self.get_screenlet_dir()+'/wallpapers/'+self.wall+'/hour25.png'):
				if int(self.hour24) <= 12:
					self.hour = str(((int(self.hour24)*60)/12)+(int(self.minute)/12))
				else:
					self.hour = str((((int(self.hour24)*60)/12)-60)+(int(self.minute)/12))

		if self.month[0] == '0': 
			self.month = self.month[1]
		
		if self.day[0] == '0': 
			self.day = self.day[1]

		if self.hour[0] == '0':
			if len(str(self.hour)) == 2:
				self.hour = self.hour[1]
			if len(str(self.hour)) == 1:
				self.hour = self.hour[0]
		if int(self.hour)>60:
			self.hour = str(int(self.hour)-60)
		
		if self.minute[0] == '0':
			self.minute = self.minute[1]

		if self.weekday == '0': 
			self.weekday = '7'
		
		#print time.localtime()
		self.set_image ()		
		#print time.localtime()
		
		#print "updated:\t%s\t%s\t%s\t%s\t%s\t%s\t%s" % (self.month, self.day,
		#	self.hour, self.minute, self.weekday, self.moon, self.zodiac)
	
		return True
	
	def show_wallpaper_info (self):
		if os.path.isfile (self.wpath + '/wallpapers/' + self.wall +'/clock.ini'):
			f = open(self.wpath + '/wallpapers/' + self.wall + '/clock.ini')
			text = f.read()
			
			# create a list of properties that we'll read from the file
			props = {"name": "",
				"author": "",
				"width": "",
				"height": "",
				"email": "",
				"description": "",
				"homepageurl": "",
				"downloadurl": ""}
			
			# split the file into lines
			lines = text.split("\n")
			
			# loop over each of the lines and each of the properties
			for line in lines:
				for prop in props:
					# check if this lines corresponds to one of the properties
					if line.find(prop) != -1:
						# make sure the property's value isn't blank
						if len(line) > len(prop + "=\n"):
							props[prop] = line[line.find("=")+1:].lstrip()
			
			out = "<b>%s</b> (%sx%s)\n<b>By %s</b>\n%s" % (props["name"], props["width"],
				props["height"], props["author"], props["description"])
			screenlets.show_message(None, out)
	
	def on_menuitem_select (self, id ):
		"""handle MenuItem-events in right-click menu"""
		if id[:6] == "change":
			# change the clock (self.update() will automatically be called)
			self.wall = id[6:]
		elif id == "install":
			self.show_install_dialog()
		elif id == "random":
			self.set_random_wallpaper()
		elif id == "visit":
			screenlets.utils.xdg_open('http://www.vladstudio.com/wallpaperclock/')
		elif id == "wallinfo":
			self.show_wallpaper_info()

	def on_draw_shape (self, ctx):
		ctx.scale(self.scale, self.scale)
		if self.theme:
			self.theme.render(ctx, 'WallpaperClock-bg')


	
# If the program is run directly or passed as an argument to the python
# interpreter then launch as new application
if __name__ == "__main__":
	# create session object here, the rest is done automagically
	import screenlets.session
	screenlets.session.create_session(WallpaperClockScreenlet)

