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

# Copyright 2006-2007 (C) Raster Software Vigo (Sergio Costas)
# Copyright 2006-2007 (C) Peter Gill - win32 parts

# This file is part of DeVeDe
#
# DeVeDe 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 3 of the License, or
# (at your option) any later version.
#
# DeVeDe 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, see <http://www.gnu.org/licenses/>.


import cairo
import time
import sys
import os
import devede_executor
import devede_other

class xml_files(devede_executor.executor):
	
	""" This class creates the XML files and the menues """
	
	def create_files(self,filename,filefolder,structure,do_menu,menu_PAL,menu_widescreen,menu_path,menu_bg,font_name,path,bgcolor,fontcolor,activecolor,align,extcr=None):
		
		devede_executor.executor.__init__(self,filename,filefolder,None)
		
		if self.create_xml(structure,do_menu,menu_PAL,menu_widescreen):
			return _("Failed to write to the destination directory.\nCheck that you have privileges and free space there.")
	
		if do_menu:
			if self.create_menu_stream(structure,menu_PAL,menu_widescreen,menu_path,activecolor,align):
				return _("Failed to write to the destination directory.\nCheck that you have privileges and free space there.")
			if None==self.create_menu_bg(structure, menu_bg, menu_PAL, font_name, bgcolor, fontcolor, activecolor, align,extcr,0):
				return _("Can't find the menu background.\nCheck the menu options.")
			if None==self.create_menu_bg(structure, menu_bg, menu_PAL, font_name, bgcolor, fontcolor, activecolor, align,extcr,1):
				return _("Failed to write to the destination directory.\nCheck that you have privileges and free space there.")
			if None==self.create_menu_bg(structure, menu_bg, menu_PAL, font_name, bgcolor, fontcolor, activecolor, align,extcr,2):
				return _("Failed to write to the destination directory.\nCheck that you have privileges and free space there.")
			if None==self.create_menu_bg(structure, menu_bg, menu_PAL, font_name, bgcolor, fontcolor, activecolor, align,extcr,3):
				return _("Failed to write to the destination directory.\nCheck that you have privileges and free space there.")
			#if self.reduce_colors():
			#	return _("Can't reduce menu colors.\nCheck that you have ImageMagic's Convert installed")
			if self.create_menu_mpg(menu_PAL,path):
				return _("Menu generation failed.")
			if self.menu_mplex_buttons():
				return _("Can't add the buttons to the menus.\nIt seems a bug of SPUMUX.")
			
		return None
		
		
	def create_xml(self,structure,do_menu,menu_PAL,menu_widescreen):

		""" Creates the XML file for DVDAuthor """

		# calculate the position for each title
		
		title_list=[]
		counter=1
		for element in structure:
			title_list.append(counter)
			counter+=((len(element))-1)

		try:
			fichero=open(self.filefolder+self.filename+".xml","w")
			fichero.write('<dvdauthor dest="'+self.filefolder+self.filename+'">\n')
			fichero.write('\t<vmgm>\n')
			
			# MENU
			
			fichero.write("\t\t<menus>\n")
			if do_menu==False:
				for element in structure:
					for element2 in element[1:]:
						if element2["fps"]==25:
							menu_PAL=True
						else:
							menu_PAL=False
						break

				
			fichero.write('\t\t\t<video format="')
			if menu_PAL:
				fichero.write("pal")
			else:
				fichero.write("ntsc")
			fichero.write('" aspect="')
			if menu_widescreen:
				fichero.write("16:9")
			else:
				fichero.write("4:3")
			fichero.write('"> </video>\n')
				
			fichero.write('\t\t\t<pgc>\n')
			fichero.write('\t\t\t\t<pre>\n')
			fichero.write('\t\t\t\t\tif (g0 eq 847) {\n')
			fichero.write('\t\t\t\t\t\tif (g1 eq 6725) {\n')
			counter=1
			for element in structure:
				for element2 in element[1:]:
					fichero.write('\t\t\t\t\t\t\tif (g2 eq '+str(counter)+')\n')
					fichero.write('\t\t\t\t\t\t\t\tjump titleset '+str(counter)+' menu;\n')
					counter+=1
			fichero.write('\t\t\t\t\t\t}\n')
			fichero.write('\t\t\t\t\t}\n')
			
			# if there's no menu, jump to the first title
			fichero.write('\t\t\t\t\tg0=847;\n')
			fichero.write('\t\t\t\t\tg1=6725;\n')
			
			if do_menu==False:
				fichero.write('\t\t\t\t\tjump titleset 1 menu;\n')
			fichero.write('\t\t\t\t</pre>\n')
			if do_menu:
				fichero.write('\t\t\t\t<vob file="'+self.filefolder+self.filename+'_menu2.mpg"></vob>\n')
				counter=0
				
				# One button for each title
				for element in structure:
					fichero.write('\t\t\t\t\t<button name="boton'+str(counter)+'">jump titleset '+str(title_list[counter])+' menu;</button>\n')
					counter+=1
			fichero.write('\t\t\t\t</pgc>\n')
			fichero.write('\t\t\t</menus>\n')
			fichero.write("\t</vmgm>\n")

			total_t=len(structure)
			titleset=1
			titles=0
			for element in structure:
				files=0
				num_chapters=len(element)-1
				action=element[0]["jumpto"]
				for element2 in element[1:]:
					fichero.write("\t<titleset>\n")
					fichero.write("\t\t<menus>\n")
					fichero.write("\t\t\t<pgc>\n")
					fichero.write("\t\t\t\t<pre>\n")
					fichero.write('\t\t\t\t\tif (g0 eq 847) {\n')
					fichero.write('\t\t\t\t\t\tif (g1 eq 6725) {\n')
					fichero.write('\t\t\t\t\t\t\tg0=0;\n')
					fichero.write('\t\t\t\t\t\t\tg1=0;\n')
					fichero.write('\t\t\t\t\t\t\tjump title 1;\n')
					fichero.write('\t\t\t\t\t\t}\n')
					fichero.write('\t\t\t\t\t}\n')
					fichero.write('\t\t\t\t\tjump vmgm menu entry title;\n')
					fichero.write('\t\t\t\t</pre>\n')
					fichero.write("\t\t\t</pgc>\n")
					fichero.write("\t\t</menus>\n")
					fichero.write("\t\t<titles>\n")
					for element3 in element2["sub_list"]:
						fichero.write('\t\t\t<subpicture lang="'+str(element3["sub_language"][:2].lower())+'" />\n')
					fichero.write("\t\t\t<pgc>\n")
					currentfile=self.create_filename(self.filefolder+self.filename,titles+1,files+1,False)
					fichero.write('\t\t\t\t<vob file="'+currentfile+'" ')
					fichero.write('chapters="0')
					if (element2["olength"]>5):
						if (element2["lchapters"]!=0): # add chapters
							toadd=int(element2["lchapters"])
							seconds=toadd*60
							while seconds<(element2["olength"]-4):
								thetime=devede_other.return_time(seconds,False)
								fichero.write(","+thetime)
								seconds+=(toadd*60)
						fichero.write(','+devede_other.return_time((element2["olength"]-2),False))
					fichero.write('" />\n')
					fichero.write('\t\t\t\t<post>\n')
					files+=1
					if (files==num_chapters) and (action=="menu"): # last chapter
						if do_menu:
							fichero.write('\t\t\t\t\tg0=0;\n')
							fichero.write('\t\t\t\t\tg1=0;\n')
							fichero.write('\t\t\t\t\tcall vmgm menu entry title;\n')
					else:
						fichero.write('\t\t\t\t\tg0=847;\n')
						fichero.write('\t\t\t\t\tg1=6725;\n')
						fichero.write('\t\t\t\t\tg2=')
						if (files==num_chapters): # last chapter; do ACTION
							if action=="prev":
								if titles==0:
									prev_t=total_t-1
								else:
									prev_t=titles-1
								fichero.write(str(title_list[prev_t]))
							elif action=="loop":
								fichero.write(str(title_list[titles]))
							elif action=="next":
								if titles==total_t-1:
									next_t=0
								else:
									next_t=titles+1
								fichero.write(str(title_list[next_t]))
							elif action=="last":
								fichero.write(str(title_list[total_t-1]))
							else:
								fichero.write('1') # first
						else:
							fichero.write(str(title_list[titles]+files))
						fichero.write(';\n')
						fichero.write('\t\t\t\t\tcall vmgm menu entry title;\n')
					fichero.write('\t\t\t\t</post>\n')
					fichero.write("\t\t\t</pgc>\n")
					fichero.write("\t\t</titles>\n")
					fichero.write("\t</titleset>\n")
				titles+=1
			fichero.write("</dvdauthor>")
			fichero.close()
			return False
		except IOError:
			return True

		
	def create_menu_stream(self,structure,menu_PAL,menu_widescreen,menu_path,activecolor,align):

		""" Creates the menu XML file """

		cantidad=len(structure)
		if align!=0:
			offset=(12-cantidad)/align
		else:
			offset=0
			
		if menu_PAL:
			formato="pal"
		else:
			formato="ntsc"

		if menu_widescreen:
			menu_wide="_wide"
		else:
			menu_wide=""

		try:
			fichero=open(self.filefolder+self.filename+"_menu.xml","w")
			fichero.write('<subpictures>\n<stream>\n<spu force="yes" start="00:00:00.00"')# transparent="000000"')
			fichero.write(' image="'+self.filefolder+self.filename+'_menu_bg_inactive_out.png"')
			fichero.write(' highlight="'+self.filefolder+self.filename+'_menu_bg_active_out.png"')
			fichero.write(' select="'+self.filefolder+self.filename+'_menu_bg_select_out.png" >\n')
			if menu_PAL:
				coord_y=[(54,91),(92,129),(130,167),(168,205),(206,243),(244,281),(282,321),(322,359),(360,397),(398,437),(438,475),(476,513)]
			else:
				coord_y=[(44,75),(76,107),(108,139),(140,171),(172,203),(204,235),(236,267),(268,299),(300,331),(332,363),(364,395),(396,427)]
			for contador in range(cantidad):
				fichero.write('<button name="boton'+str(contador))
				fichero.write('" x0="0" y0="'+str(coord_y[contador+offset][0])+'" x1="719" y1="'+str(coord_y[contador+offset][1])+'"')
				fichero.write(' up="boton')
				if contador==0:
					fichero.write(str(cantidad-1))
				else:
					fichero.write(str(contador-1))
				fichero.write('" down="boton')
			
				if contador==(cantidad-1):
					fichero.write("0")
				else:
					fichero.write(str(contador+1))
				fichero.write('" > </button>\n')
			fichero.write("</spu>\n</stream>\n</subpictures>\n")
			fichero.close()
			
			return False
		except IOError:
			return True
		
		
	def menu_set_text(self,cr,y,texto,widescreen,bgcolor,fontcolor,myfontname="Sans",myfontstyle=cairo.FONT_WEIGHT_BOLD,myfontslant=cairo.FONT_SLANT_NORMAL,myfontsize=12):

		if widescreen:
			x=0
		else:
			x=0.125

		radius=0.0375
		border=0.0048
		linea=0.0024
		fontsize2=myfontsize*0.00315

		cr.set_line_width(linea)
		cr.select_font_face(myfontname,myfontslant,myfontstyle)

		# I created the button image for this size, so I must respect it :(
		#xb,yb,width,height,cx,cy=cr.text_extents("Título 1")
		height=0.0391604010025
	
		cr.set_font_size(fontsize2)
		xb,y2,width,h2,cx,cy2=cr.text_extents(texto)

		#if ((bgcolor[0]<512) and (bgcolor[1]<512) and (bgcolor[2]<512)):
		#	bgcolor[0]=512
		#	bgcolor[1]=512
		#	bgcolor[2]=512
			
		#if ((fontcolor[0]<512) and (fontcolor[1]<512) and (fontcolor[2]<512)):
		#	fontcolor[0]=512
		#	fontcolor[1]=512
		#	fontcolor[2]=512
			
		cor=float(bgcolor[0])/65535.0
		cog=float(bgcolor[1])/65535.0
		cob=float(bgcolor[2])/65535.0
		coa=float(bgcolor[3])/65535.0
		cr.set_source_rgba(cor,cog,cob,coa)
		cr.move_to(x,y-border)
		cr.line_to(1-x,y-border)
		cr.curve_to(1-x+radius,y-border,1-x+radius,y+height+border,1-x,y+height+border)
		cr.line_to(x,y+height+border)
		cr.curve_to(x-radius,y+height+border,x-radius,y-border,x,y-border)
		cr.fill()
		
		cor=float(fontcolor[0])/65535.0
		cog=float(fontcolor[1])/65535.0
		cob=float(fontcolor[2])/65535.0
		coa=float(fontcolor[3])/65535.0
		cr.set_source_rgba(cor,cog,cob,coa)
		cr.move_to(.5-width/2-xb,y-y2+(height-h2)/2)
		cr.show_text(texto)


	def create_menu_bg(self,structure,menu_bg,menu_PAL,fontname,bgcolor,fontcolor,activecolor,align,extcr=None,paint_bg=0):

		""" Paints the menu in a Cairo surface.	PAINT_BG can be:
			0: paints everything for the base picture
			1: paints the HIGHLIGHT picture
			2: paints the ACTIVE picture
			3: paints the SELECT picture		
		"""

		wide=False
		
		if paint_bg==0:
			try:
				sf_base=cairo.ImageSurface.create_from_png(menu_bg)
			except:
				return None

		if menu_PAL:
			y=576.0
		else:
			y=480.0

		sf=cairo.ImageSurface(cairo.FORMAT_ARGB32,720,int(y))

		cr=cairo.Context(sf)

		if paint_bg!=0:
			# turn off font antialias (reduces color use in the image, same thing as using convert.exe)
			fo = cairo.FontOptions()
			fo.set_antialias(cairo.ANTIALIAS_NONE)
			
			cr.set_font_options(fo)
			# turn off antialias
			cr.set_antialias(cairo.ANTIALIAS_NONE)
		
		cr.identity_matrix()
		
		if paint_bg==0:
			wbase=float(sf_base.get_width())
			hbase=float(sf_base.get_height())
			cr.scale(720.0/wbase,y/hbase)
			cr.set_source_surface(sf_base)
			cr.paint()
			cr.identity_matrix()
		#else:
		#	cr.set_source_rgb(0.0, 0.0, 0.0)
		

		if wide:
			cr.scale(0.75*sf.get_width(),1.33*sf.get_height()) # picture gets from 0 to 1 in X and from 0 to 0.75 in Y
			cr.translate(0.166666666,0)		
		else:
			cr.scale(sf.get_width(),1.33*sf.get_height()) # picture gets from 0 to 1 in X and from 0 to 0.75 in Y

		pos_y=0.075
		
		if align!=0:
			pos_y+=0.05*float((12-len(structure))/align)
		
		font_elements=[]
		font_temp=fontname
		while True:
			pos=font_temp.find(" ")
			if pos==-1:
				font_elements.append(font_temp) # add the last element
				break
			font_elements.append(font_temp[:pos])
			longitud=len(font_temp)
			if pos+1==longitud: # a missed blank space at the end
				break
			font_temp=font_temp[pos+1:]
	
		if (len(font_elements))<2:
			fontname="Sans"
			fontstyle=cairo.FONT_WEIGHT_NORMAL
			fontslant=cairo.FONT_SLANT_NORMAL
			fontsize=12
		else:
			fontname=""
			fontstyle=cairo.FONT_WEIGHT_NORMAL
			fontslant=cairo.FONT_SLANT_NORMAL
			for counter in range(len(font_elements)-1):
				if font_elements[counter]=="Bold":
					fontstyle=cairo.FONT_WEIGHT_BOLD
				elif font_elements[counter]=="Italic":
					fontslant=cairo.FONT_SLANT_ITALIC
				else:
					fontname+=" "+font_elements[counter]
			if fontname!="":
				fontname=fontname[1:]
			else:
				fontname="Sans"
	
		try:
			fontsize=float(font_elements[-1])
		except:
			fontsize=12
		
		if paint_bg<2:
			for entrada in structure:
				if paint_bg==0:
					self.menu_set_text(cr,pos_y,entrada[0]["nombre"],wide,bgcolor,fontcolor,fontname,fontstyle,fontslant,fontsize)
				elif paint_bg==1:
					self.menu_set_text(cr,pos_y,entrada[0]["nombre"],wide,[0,0,0,0],activecolor,fontname,fontstyle,fontslant,fontsize)
				elif paint_bg==2:
					self.menu_set_text(cr,pos_y,entrada[0]["nombre"],wide,[0,0,0,0],fontcolor,fontname,fontstyle,fontslant,fontsize)
				else:
					self.menu_set_text(cr,pos_y,entrada[0]["nombre"],wide,[0,0,0,0],fontcolor,fontname,fontstyle,fontslant,fontsize)
				pos_y+=0.05

		if extcr==None:
			if paint_bg==0:
				sf.write_to_png(self.filefolder+self.filename+"_menu_bg.png")
			elif paint_bg==1:
				sf.write_to_png(self.filefolder+self.filename+"_menu_bg_active_out.png")
			elif paint_bg==2:
				sf.write_to_png(self.filefolder+self.filename+"_menu_bg_inactive_out.png")
			else:
				sf.write_to_png(self.filefolder+self.filename+"_menu_bg_select_out.png")
		return sf
	
	
	def reduce_colors(self):
		self.reduce_colors2("inactive")
		self.reduce_colors2("active")
		self.reduce_colors2("select")
	
	def reduce_colors2(self,filename):
	
		print "Reducing menu colors"
	
		command_var=[]
		if sys.platform=='win32':
			command_var=["convert.exe"]
		else:
			command_var=["convert"]
	
		currentfile=self.filefolder+self.filename+"_menu_bg_"+filename+".png"
		
		origDir=os.getcwd()
		if sys.platform=="win32":
			temp=os.path.split(self.filefolder+self.filename+"_menu_bg_"+filename+".png")
			picDir=temp[0]
			picName=temp[1]
			command_var.append(picName)
			os.chdir(picDir)
		else:
			command_var.append(self.filefolder+self.filename+"_menu_bg_"+filename+".png")
			
		command_var.append("-colors")
		command_var.append("2")
		command_var.append("-depth")
		command_var.append("24")
		
		origDir=os.getcwd()
		if sys.platform=="win32":
			temp=os.path.split(self.filefolder+self.filename+"_menu_bg_"+filename+"_out.png")
			picDir=temp[0]
			picName=temp[1]
			command_var.append(picName)
			os.chdir(picDir)
		else:
			command_var.append(self.filefolder+self.filename+"_menu_bg_"+filename+"_out.png")
		
		print "Lanzo "+str(command_var)

		self.launch_program(command_var)
		
		while(0==self.refresh()):
			time.sleep(.5)
		if 0!=self.wait_end():
			return True
	
		if sys.platform=="win32":
			os.chdir(origDir)
		return False
	
	
	def create_menu_mpg(self,menu_PAL,path):
	
		print "Creating menus"
	
		menu_widescreen=False
		
		command_var=[]
		if sys.platform=='win32':
			command_var=["mencoder.exe"]
		else:
			command_var=["mencoder"]
	
		currentfile=self.filefolder+self.filename+"_menu.mpg"
	
		command_var.append("-srate")
		command_var.append("48000")
		command_var.append("-af")
		command_var.append("lavcresample=48000")
		command_var.append("-oac")
		command_var.append("lavc")
		command_var.append("-ovc")
		command_var.append("lavc")
		command_var.append("-of")
		command_var.append("mpeg")
		command_var.append("-mpegopts")
		command_var.append("format=dvd:tsaf")
		command_var.append("-ofps")
		audio=path+"silence.wav"
		if menu_PAL:
			command_var.append("25")
		else:
			command_var.append("30000/1001")

		if menu_widescreen:
			wide="16/9"
		else:
			wide="4/3"
		command_var.append("-vf")
		if menu_PAL:
			command_var.append("scale=720:576,harddup")
		else:
			command_var.append("scale=720:480,harddup")
		command_var.append("-lavcopts")
		command_var.append("vcodec=mpeg2video:sc_threshold=1000000000:cgop:trell:mbd=2:vstrict=0:vrc_maxrate=7501:vrc_buf_size=1835:vbitrate=5001:keyint=12:acodec=mp2:abitrate=224:aspect="+wide)
		command_var.append("-o")
		command_var.append(currentfile)
		command_var.append("-audiofile")
		command_var.append(audio)
		command_var.append("-mf")
		command_var.append("type=png:fps=1")
		origDir=os.getcwd()
		if sys.platform=="win32":
			temp=os.path.split(self.filefolder+self.filename+"_menu_bg.png")
			picDir=temp[0]
			picName=temp[1]
			command_var.append("mf://"+picName)
			os.chdir(picDir)
		else:
			command_var.append("mf://"+self.filefolder+self.filename+"_menu_bg.png")
		print "Lanzo "+str(command_var)

		self.launch_program(command_var)
		
		while(0==self.refresh()):
			time.sleep(.5)
		if 0!=self.wait_end():
			return True
	
		if sys.platform=="win32":
			os.chdir(origDir)
		return False

	
	def menu_mplex_buttons(self):
	
		if sys.platform=='win32':
			comando=["spumux.exe"]
			# The -i -o is with a custom patched version of
			# dvdauthor.  Best and easiest way of making it work
			comando.append(self.filefolder+self.filename+"_menu.xml")
			comando.append("-i")
			comando.append(self.filefolder+self.filename+"_menu.mpg")
			comando.append("-o")
			comando.append(self.filefolder+self.filename+"_menu2.mpg")
			self.launch_program(comando)
		else:
			comando="spumux"
			
			comando+=' "' +self.filefolder+self.filename+'_menu.xml"'

			print "Launch: "+comando
			self.launch_shell(comando,stdinout=[self.filefolder+self.filename+"_menu.mpg",self.filefolder+self.filename+"_menu2.mpg"])

		while(0==self.refresh()):
			time.sleep(.5)

		if 0!=self.wait_end():
			return True
	
		return False


	def end_process(self,eraser,erase_temporary_files):
		
		if erase_temporary_files:
			eraser.delete_menu_temp()
