#!/usr/bin/env python

import gtk
from gtk import gdk
import string
import os.path
import pango
import xml.dom.minidom

##
## Class to manage the themes, Read its xml and then load each item
##
class UI:    
    def __init__(self, win, colors):
        #self.skin = False
        self.width = 0
        self.height	= 0
        self.draw_background = False
        self.theme_path	= None

        self.items = []						#It will hold all the items :D
        self.albumcover_item = False
        self.titlename_item = False
        self.albumname_item = False
        self.artistname_item = False
        self.rating_item = False
        self.playercontrols_item = False
    
        #gtkwin	= None
        self.gtkwin = win
        self.g = colors

    def get_width(self):
        return self.width

    def get_height(self):
        return self.height

    def get_album_x(self):
	return self.Albumcover_Item.x

	## @param self pointer to the class object
	## @param filename Path to the xml file
	##
	## It reads the xml file and creates a item for each xml entry that corresponds to one of the following:
	## - image
	## - albumcover
	## - rating
	## - titlename
	## - artistname
	## - albumname
    def load_xml(self,filename):
		if os.path.exists(filename):
			self.theme_path = os.path.expanduser(os.path.dirname(filename))
			self.g.debug("Theme path: " + self.theme_path)
			dom 	= xml.dom.minidom.parse(filename)
			skinobj 	= dom.getElementsByTagName("skin")[0]
			self.g.info("Theme: " + skinobj.getAttribute("name"))				#Print Theme Name
			self.width 	= int(skinobj.getAttribute("width"))
			self.height = int(skinobj.getAttribute("height"))
			self.draw_background = skinobj.getAttribute("drawBackground")

			for domitem in skinobj.childNodes:
				if domitem.nodeType == 1:
					#print domitem
					type 	= domitem.nodeName
					x 		= int(domitem.getAttribute("x"))
					y 		= int(domitem.getAttribute("y"))
					w 		= domitem.getAttribute("width")
					h 		= domitem.getAttribute("height")
					display = domitem.getAttribute("display")
					if w: w	= int(w)
					if h: h 	= int(h)
					
					item = False
					if type == "image":
						src  = domitem.getAttribute("src")
						item = ImageItem(self.theme_path + "/" + src, x, y, w, h, display)
					elif type == "albumcover":
						item = ImageItem(None, x, y, w, h, display)
						self.albumcover_item = item
						self.g.debug("Loading AlbumCover xml info")
					elif type== "rating":
						src_star  	= domitem.getAttribute("star")
						src_noStar = domitem.getAttribute("nostar") 
						spacing 	= domitem.getAttribute("spacing")
						if spacing: spacing = int(spacing)
						item = RatingItem(self.theme_path + "/" + src_star, self.theme_path + "/" +src_noStar,x,y,w,h,spacing,display)
						self.rating_item = item
					elif type in ("titlename", "artistname", "albumname"):
						font 			=	domitem.getAttribute("font")
						color			=	domitem.getAttribute("color")
						shadowcolor 	=	domitem.getAttribute("shadowcolor")
						align 			=	domitem.getAttribute("align")
						maxchars 		=	domitem.getAttribute("maxchars")
						item = TextItem("", font, color, x, y, display, shadowcolor, maxchars, align, w, h)
						exec "self."+type+"_item = item"
					elif type == "playercontrols":
						xd = float(x)/self.width
						yd = float(y)/self.height
						spacing = domitem.getAttribute("spacing")
						item = PlayerControls(int(spacing), xd, yd, display, self.gtkwin)
						for controlitem in domitem.childNodes:
							if controlitem.nodeType == 1: 
								src = controlitem.getAttribute("src")
								src = self.theme_path + "/" + src
								x  	= controlitem.getAttribute("x")
								y  	= controlitem.getAttribute("y")
								pause = controlitem.getAttribute("pause")
								if pause:
									pause = self.theme_path + "/" + pause
								ctype = controlitem.nodeName
								item.add(ctype,src,x,y,pause)
						self.playercontrols_item = item
					if item: self.items.append(item)
				
# ============================ GENERIC ITEM =========================== #
##
## Each interface item will be part of this GeneriItem class, everyone will have a position and a display mode
##
class GenericItem:
	type 		= ""
	x     		= 0
	y     		= 0
	width		= 0
	height 		= 0
	display 		= True
	regular_updates	= False

	def __init__(self, type, x, y, w, h, display):
		self.type 	= type
		self.x 		= x
		self.y 		= y
		self.width 	= w
		self.height	= h
		if display: self.display = display

	def draw(self, ctx):
		pass
	
# ============================= IMAGE ITEM ============================= #	
##
## Class for the items that are images
##	
class ImageItem(GenericItem):
	src 			= ""
	imgobj 	 	= None
	image_type 	= None

	def __init__(self, src, x, y, w, h, display):
		GenericItem.__init__(self, "image", x, y, w, h, display)
		self.set_image(src)

	def set_image(self, src):
		if (src) and (os.path.exists(src)):
			try:
				self.imgobj = gtk.gdk.pixbuf_new_from_file(src)
			except:
				self.imgobj = None
		else: 
			self.imgobj = None

		cl 	= self.imgobj.__class__.__name__
		mod = self.imgobj.__class__.__module__
		if    cl == 'Handle': 		self.image_type = "rsvg"
		elif  cl == 'ImageSurface': self.image_type = "surface"
		elif  cl == 'Pixbuf': 		self.image_type = "pixbuf"
		else: 
			self.image_type = None
			
		#print mod+", "+cl

	def draw(self, ctx):
		# Draw accordingly
		#print "Drawing Image :"+self.src + " - " + str(self.image_type)
		if self.imgobj != None:
				ctx.save()
				pw = float(self.imgobj.get_width())
				ph = float(self.imgobj.get_height())
				ctx.translate(self.x, self.y)
				#if self.width and self.height:
				#	ctx.scale(self.width/pw, self.height/ph)
				#ctx.set_source_pixbuf(self.imgobj, 0, 0)
				pixscaled = self.imgobj
				if self.width and self.height:
					pixscaled = self.imgobj.scale_simple(self.width,self.height,1)
				ctx.set_source_pixbuf(pixscaled, 0, 0)
				ctx.paint()
				ctx.restore()	

# ============================= RATING ITEM ============================== #	
##
## Class for the rating items
##	
class RatingItem(GenericItem):
	src_star 		= ""
	src_noStar 		= ""
	starobj 		= None
	noStarobj 		= None
	spacing 		= 1
	image_type 		= None
	stars 			= 0
	
	def __init__(self, src_star, src_noStar, x, y, w, h, spacing, display):
		GenericItem.__init__(self, "rating", x, y, w, h, display)
		self.set_image(src_star, src_noStar)
		self.spacing = spacing

	def set_image(self, src_star, src_noStar):
		if src_star:
			self.starobj = gtk.gdk.pixbuf_new_from_file(src_star)
		if src_noStar:
			self.noStarobj = gtk.gdk.pixbuf_new_from_file(src_noStar)

		cl 	= self.starobj.__class__.__name__
		mod 	= self.starobj.__class__.__module__
		if    cl == 'Handle': self.image_type = "rsvg"
		elif cl == 'ImageSurface': self.image_type = "surface"
		elif cl == 'Pixbuf': self.image_type = "pixbuf"
		else: self.image_type = None
		#print mod+", "+cl

	def set_rating(self,stars):
		self.stars = stars

	def draw(self, ctx):
		# Draw the rating (stars and the no stars)
		#print "Drawing Rating :"+self.src_star + " - " + str(self.image_type)
		if self.starobj != None and self.noStarobj != None:
			if self.image_type == "pixbuf":
				ctx.save()
				pw 	= float(self.starobj.get_width())
				ph 	= float(self.starobj.get_height())
				p2w 	= float(self.noStarobj.get_width())
				p2h 	= float(self.noStarobj.get_height())
				pixbuf = [None,None,None,None,None]
				
				#if self.width and self.height:
					#ctx.scale(self.width/pw, self.height/ph)
				#ctx.set_source_pixbuf(self.imgobj, 0, 0)

				for i in range(0,self.stars):			#Draw Stars
					ctx.save()
       					pixbuf[i] = self.noStarobj
					if self.width and self.height:
						pixbuf[i] = self.starobj.scale_simple(self.width,self.height,1)
					ctx.translate(self.x + i*(self.width+self.spacing), self.y)
					ctx.set_source_pixbuf(pixbuf[i], 0, 0)
					ctx.paint()
					ctx.restore()

				for i in range(self.stars,5):			#Draw No Stars
					ctx.save()
       					pixbuf[i] = self.noStarobj
					if self.width and self.height:
						pixbuf[i] = self.noStarobj.scale_simple(self.width,self.height,1)
					ctx.translate(self.x + i*(self.width+self.spacing), self.y)
					ctx.set_source_pixbuf(pixbuf[i], 0, 0)
					ctx.paint()
					ctx.restore()
				ctx.restore()	


# ============================= TEXT ITEM ============================== #	
##
## Class for the items that are text
##		
class TextItem(GenericItem):
	font 			= "Sans 10"
	text 			= ""
	align			= ""
	color 		= (0,0,0,1)
	shadowcolor 	= False
	maxchars 		= False
	layout = 0
	

 	def __init__(self, text, font, color, x, y, display="", 
					shadowcolor="", maxchars="", align="left", 
					w=0, h=0):       
		GenericItem.__init__(self, "text", x, y, w, h, display)
		if font: self.font = font
		if color: self.color = self.get_rgba(color)
		if shadowcolor: self.shadowcolor = self.get_rgba(shadowcolor)
		if maxchars: self.maxchars = int(maxchars)
		self.align = align
		self.set_text(text)
	
	def get_rgba(self, color):
		return (
            int(color[1:3], 16)/255.0,
            int(color[3:5], 16)/255.0,
            int(color[5:7], 16)/255.0,
            int(color[7:9], 16)/255.0
        )

	def set_text(self, text):
		#print "resetting text"
		if self.maxchars and len(text) > self.maxchars:
			text = text[0:self.maxchars] + "..."
		self.text = text
		
	def draw(self, ctx):
        	# Do some Pango Magic here
        	# Draw Shadow Text
		text = self.text
		ctx.save()
		if self.shadowcolor: 
			self.draw_text(ctx, text, self.shadowcolor, self.x-1, self.y-1)
        	# Draw Text
		self.draw_text(ctx, text, self.color, self.x, self.y)
		ctx.restore()

	def draw_text(self, ctx, text, c, x, y):
		ctx.save()
		p_layout = ctx.create_layout()
		p_fdesc = pango.FontDescription(self.font)
		p_layout.set_font_description(p_fdesc)
		p_layout.set_text(text)
		self.set_clip_region(ctx, p_layout, x, y)
		if text: 
			(x,y) = self.get_xy_from_alignment(p_layout, x, y)
		ctx.move_to(x,y)
		ctx.set_source_rgba(c[0],c[1],c[2],c[3])
		ctx.show_layout(p_layout)
		ctx.restore()

	def get_extents(self, p_layout):
		(extents, lextents) = p_layout.get_pixel_extents()
		return extents

	def get_xy_from_alignment(self, p_layout, x, y):
		if not self.width: return (x, y)
		extents = self.get_extents(p_layout)
		fw = extents[2]+extents[0]
		fh = extents[3]+extents[1]

		if self.align == "left":
			pass
		
		elif self.align == "center":
			if self.layout==0:
				x = x + self.width/2.0 - fw/2.0
			elif self.layout==1:
				y = y - self.width/2.0 + fw/2.0
			elif self.layout==2:
				x = x - self.width/2.0 + fw/2.0
			elif self.layout==3:
				y = y + self.width/2.0 - fw/2.0
		
		elif self.align == "right":
			if self.layout==0:
				x = x + self.width - fw
			elif self.layout==1:
				y = y - self.width + fw
			elif self.layout==2:
				x = x - self.width + fw
			elif self.layout==3:
				y = y + self.width - fw
		return (x, y)
		
	def set_clip_region(self, ctx, p_layout, x, y):
		extents = self.get_extents(p_layout)
		fw = extents[2]+extents[0]
		fh = extents[3]+extents[1]
		if self.width:
			if self.layout == 0:
				ctx.rectangle(x, y, self.width, fh)
			if self.layout == 1:
				ctx.rectangle(x, y-self.width, fh, self.width)
			if self.layout == 2:
				ctx.rectangle(x-self.width, y-fh, self.width, fh)
			if self.layout == 3:
				ctx.rectangle(x-fh, y, fh, self.width)
			#ctx.stroke()
			ctx.clip()

# ============================= PlayerControls ITEM ============================== #	
##
## Class for the player controls
##			
class PlayerControls(GenericItem):
	type = "playercontrols"

	fixed				= False
	box 				= False
	window 				= False
	theme 				= False
	player 				= False

	prev_button 		= False
	play_pause_button 	= False
	next_button 		= False
	
	display = True

	image_play = None
	src_play = ''
	src_pause = ''
	state = None
        
	def __init__(self, spacing, display,x ,y , gtkwin , w=0, h=0,):
		GenericItem.__init__(self, "text", x, y, w, h, display)
		self.box 	= gtk.HBox(spacing=spacing)
		self.fixed 	= gtk.Fixed()
		self.fixed.add(self.box)
		self.window = gtkwin
		self.window.add(self.fixed)
		
		if display: self.display = display       
		
	def add(self, image_type, src, x, y, pause=''):
		image = gtk.Image()
		image.set_from_file(src)
		
		ebox = gtk.EventBox()
		ebox.set_visible_window(False)
		ebox.add(image)
		
		if image_type == "prev":
			self.prev_button = ebox
			self.fixed.put(self.prev_button, int(x),int(y))
		elif image_type == "play":
			self.play_pause_button = ebox
			self.fixed.put(self.play_pause_button, int(x),int(y))
			self.src_play = src
			self.src_pause = pause
			self.image_play = image
		elif image_type == "next":
			self.next_button = ebox
			self.fixed.put(self.next_button, int(x),int(y))

	def change_state(self, state):
		if self.src_pause and state != self.state:
			if state == 'playing':
				self.image_play.set_from_file(self.src_pause)
				self.state = state
			elif state == 'paused':
				self.image_play.set_from_file(self.src_play)
				self.state = state
