"""
A python class to encapsulate CoMet data 
"""

"""
Copyright 2012-2014  Anthony Beville

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

from datetime import datetime
import zipfile
from pprint import pprint 
import xml.etree.ElementTree as ET
from genericmetadata import GenericMetadata
import utils

class CoMet:
	
	writer_synonyms = ['writer', 'plotter', 'scripter']
	penciller_synonyms = [ 'artist', 'penciller', 'penciler', 'breakdowns' ]
	inker_synonyms = [ 'inker', 'artist', 'finishes' ]
	colorist_synonyms = [ 'colorist', 'colourist', 'colorer', 'colourer' ]
	letterer_synonyms = [ 'letterer']
	cover_synonyms = [ 'cover', 'covers', 'coverartist', 'cover artist' ]
	editor_synonyms = [ 'editor']
		
	def metadataFromString( self, string ):

		tree = ET.ElementTree(ET.fromstring( string ))
		return self.convertXMLToMetadata( tree )

	def stringFromMetadata( self, metadata ):

		header = '<?xml version="1.0" encoding="UTF-8"?>\n'
		
		tree = self.convertMetadataToXML( self, metadata )
		return header + ET.tostring(tree.getroot())

	def indent( self, elem, level=0 ):
		# for making the XML output readable
		i = "\n" + level*"  "
		if len(elem):
			if not elem.text or not elem.text.strip():
				elem.text = i + "  "
			if not elem.tail or not elem.tail.strip():
				elem.tail = i
			for elem in elem:
				self.indent( elem, level+1 )
			if not elem.tail or not elem.tail.strip():
				elem.tail = i
		else:
			if level and (not elem.tail or not elem.tail.strip()):
				elem.tail = i
	
	def convertMetadataToXML( self, filename, metadata ):

		#shorthand for the metadata
		md = metadata

		# build a tree structure
		root = ET.Element("comet")
		root.attrib['xmlns:comet'] = "http://www.denvog.com/comet/"
		root.attrib['xmlns:xsi'] = "http://www.w3.org/2001/XMLSchema-instance"
		root.attrib['xsi:schemaLocation'] = "http://www.denvog.com http://www.denvog.com/comet/comet.xsd"
		
		#helper func
		def assign( comet_entry, md_entry):
			if md_entry is not None:
				ET.SubElement(root, comet_entry).text = u"{0}".format(md_entry)
		
		# title is manditory
		if md.title is None:
			md.title = ""
		assign( 'title', md.title )
		assign( 'series', md.series )
		assign( 'issue', md.issue )  #must be int??
		assign( 'volume', md.volume )
		assign( 'description', md.comments )
		assign( 'publisher', md.publisher )
		assign( 'pages', md.pageCount )
		assign( 'format', md.format )
		assign( 'language', md.language )
		assign( 'rating', md.maturityRating )
		assign( 'price', md.price )
		assign( 'isVersionOf', md.isVersionOf )
		assign( 'rights', md.rights )
		assign( 'identifier', md.identifier )
		assign( 'lastMark', md.lastMark )		
		assign( 'genre', md.genre )   # TODO repeatable

		if md.characters is not None:
			char_list = [ c.strip() for c in md.characters.split(',') ]
			for c in char_list:
				assign( 'character', c ) 
			
		if md.manga is not None and md.manga == "YesAndRightToLeft":
			assign( 'readingDirection', "rtl")
		
		date_str = ""
		if md.year is not None:
			date_str = str(md.year).zfill(4) 
			if md.month is not None:
				date_str += "-" + str(md.month).zfill(2)
			assign( 'date', date_str )  

		assign( 'coverImage', md.coverImage )

		# need to specially process the credits, since they are structured differently than CIX	
		credit_writer_list    = list()
		credit_penciller_list = list()
		credit_inker_list     = list()
		credit_colorist_list  = list()
		credit_letterer_list  = list()
		credit_cover_list     = list()
		credit_editor_list    = list()
		
		#  loop thru credits, and build a list for each role that CoMet supports
		for credit in metadata.credits:

			if credit['role'].lower() in set( self.writer_synonyms ):
				ET.SubElement(root, 'writer').text = u"{0}".format(credit['person'])

			if credit['role'].lower() in set( self.penciller_synonyms ):
				ET.SubElement(root, 'penciller').text = u"{0}".format(credit['person'])
				
			if credit['role'].lower() in set( self.inker_synonyms ):
				ET.SubElement(root, 'inker').text = u"{0}".format(credit['person'])
				
			if credit['role'].lower() in set( self.colorist_synonyms ):
				ET.SubElement(root, 'colorist').text = u"{0}".format(credit['person'])

			if credit['role'].lower() in set( self.letterer_synonyms ):
				ET.SubElement(root, 'letterer').text = u"{0}".format(credit['person'])

			if credit['role'].lower() in set( self.cover_synonyms ):
				ET.SubElement(root, 'coverDesigner').text = u"{0}".format(credit['person'])

			if credit['role'].lower() in set( self.editor_synonyms ):
				ET.SubElement(root, 'editor').text = u"{0}".format(credit['person'])
		

		# self pretty-print
		self.indent(root)

		# wrap it in an ElementTree instance, and save as XML
		tree = ET.ElementTree(root)
		return tree
				 

	def convertXMLToMetadata( self, tree ):
			
		root = tree.getroot()

		if root.tag != 'comet':
			raise 1
			return None

		metadata = GenericMetadata()
		md = metadata
	
		# Helper function
		def xlate( tag ):
			node = root.find( tag )
			if node is not None:
				return node.text
			else:
				return None
				
		md.series =           xlate( 'series' )
		md.title =            xlate( 'title' )
		md.issue =            xlate( 'issue' )
		md.volume =           xlate( 'volume' )
		md.comments =         xlate( 'description' )
		md.publisher =        xlate( 'publisher' )
		md.language =         xlate( 'language' )
		md.format =           xlate( 'format' )
		md.pageCount =        xlate( 'pages' )
		md.maturityRating =   xlate( 'rating' )
		md.price =            xlate( 'price' )
		md.isVersionOf =      xlate( 'isVersionOf' )
		md.rights =           xlate( 'rights' )
		md.identifier =       xlate( 'identifier' )
		md.lastMark =         xlate( 'lastMark' )
		md.genre =            xlate( 'genre' ) # TODO - repeatable field

		date = xlate( 'date' )
		if date is not None:
			parts = date.split('-')
			if len( parts) > 0:
				md.year = parts[0]
			if len( parts) > 1:
				md.month = parts[1]
				
		md.coverImage = xlate( 'coverImage' )
		
		readingDirection = xlate( 'readingDirection' )
		if readingDirection is not None and readingDirection == "rtl":
			md.manga = "YesAndRightToLeft"
	
		# loop for character tags		
		char_list =  []
		for n in root:
			if n.tag == 'character':
				char_list.append(n.text.strip())
		md.characters = utils.listToString( char_list )

		# Now extract the credit info
		for n in root:
			if (  n.tag == 'writer' or 
				n.tag == 'penciller' or
				n.tag == 'inker' or
				n.tag == 'colorist' or
				n.tag == 'letterer' or
				n.tag == 'editor' 
			):
				metadata.addCredit( n.text.strip(), n.tag.title() )

			if n.tag == 'coverDesigner':
				metadata.addCredit( n.text.strip(), "Cover" )


		metadata.isEmpty = False
		
		return metadata

	#verify that the string actually contains CoMet data in XML format
	def validateString( self, string ):
		try:
			tree = ET.ElementTree(ET.fromstring( string ))
			root = tree.getroot()
			if root.tag != 'comet':
				raise Exception
		except:
			return False
		
		return True


	def writeToExternalFile( self, filename, metadata ):
		
		tree = self.convertMetadataToXML( self, metadata )
		#ET.dump(tree)		
		tree.write(filename, encoding='utf-8')
	
	def readFromExternalFile( self, filename ):

		tree = ET.parse( filename )
		return self.convertXMLToMetadata( tree )