#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

# ***************************************************************************
#    copyright            : (C) 2007 by Robby Stephenson
#    email                : robby@periapsis.org
#    based on             : fr.allocine.py by Mathias Monnerville
# ***************************************************************************
#
# ***************************************************************************
# *                                                                         *
# *   This program is free software; you can redistribute it and/or modify  *
# *   it under the terms of version 2 of the GNU General Public License as  *
# *   published by the Free Software Foundation;                            *
# *                                                                         *
# ***************************************************************************

import os, sys
import base64
import xml.dom.minidom
try:
	import sqlite3
except:
	print(sys.stderr, "The Python sqlite3 module is required to import Griffith databases.")
	exit(1)

DB_PATH =      os.environ['HOME'] + '/.griffith/griffith.db'
POSTERS_PATH = os.environ['HOME'] + '/.griffith/posters/'

XML_HEADER = """<?xml version="1.0" encoding="UTF-8"?>"""
DOCTYPE = """<!DOCTYPE tellico PUBLIC "-//Robby Stephenson/DTD Tellico V9.0//EN" "http://periapsis.org/tellico/dtd/v9/tellico.dtd">"""

class BasicTellicoDOM:
	def __init__(self):
		self.__doc = xml.dom.minidom.Document()
		self.__root = self.__doc.createElement('tellico')
		self.__root.setAttribute('xmlns', 'http://periapsis.org/tellico/')
		self.__root.setAttribute('syntaxVersion', '9')

		self.__collection = self.__doc.createElement('collection')
		self.__collection.setAttribute('title', 'Griffith Import')
		self.__collection.setAttribute('type', '3')

		self.__fields = self.__doc.createElement('fields')
		# Add all default (standard) fields
		self.__dfltField = self.__doc.createElement('field')
		self.__dfltField.setAttribute('name', '_default')

		# change the rating to have a maximum of 10
		self.__ratingField = self.__doc.createElement('field')
		self.__ratingField.setAttribute('name', 'rating')
		self.__ratingField.setAttribute('title', 'Personal Rating')
		self.__ratingField.setAttribute('flags', '2')
		self.__ratingField.setAttribute('category', 'Personal')
		self.__ratingField.setAttribute('format', '4')
		self.__ratingField.setAttribute('type', '14')
		self.__ratingField.setAttribute('i18n', 'yes')
		propNode = self.__doc.createElement('prop')
		propNode.setAttribute('name', 'maximum')
		propNode.appendChild(self.__doc.createTextNode('10'))
		self.__ratingField.appendChild(propNode);
		propNode = self.__doc.createElement('prop')
		propNode.setAttribute('name', 'minimum')
		propNode.appendChild(self.__doc.createTextNode('1'))
		self.__ratingField.appendChild(propNode);

		# Add a custom 'Original Title' field
		self.__titleField = self.__doc.createElement('field')
		self.__titleField.setAttribute('name', 'orig-title')
		self.__titleField.setAttribute('title', 'Original Title')
		self.__titleField.setAttribute('flags', '8')
		self.__titleField.setAttribute('category', 'General')
		self.__titleField.setAttribute('format', '1')
		self.__titleField.setAttribute('type', '1')
		self.__titleField.setAttribute('i18n', 'yes')

		self.__keywordField = self.__doc.createElement('field')
		self.__keywordField.setAttribute('name', 'keyword')
		self.__keywordField.setAttribute('title', 'Keywords')
		self.__keywordField.setAttribute('flags', '7')
		self.__keywordField.setAttribute('category', 'Personal')
		self.__keywordField.setAttribute('format', '4')
		self.__keywordField.setAttribute('type', '1')
		self.__keywordField.setAttribute('i18n', 'yes')

		self.__urlField = self.__doc.createElement('field')
		self.__urlField.setAttribute('name', 'url')
		self.__urlField.setAttribute('title', 'URL')
		self.__urlField.setAttribute('flags', '0')
		self.__urlField.setAttribute('category', 'General')
		self.__urlField.setAttribute('format', '4')
		self.__urlField.setAttribute('type', '7')
		self.__urlField.setAttribute('i18n', 'yes')

		self.__fields.appendChild(self.__dfltField)
		self.__fields.appendChild(self.__ratingField)
		self.__fields.appendChild(self.__titleField)
		self.__fields.appendChild(self.__keywordField)
		self.__fields.appendChild(self.__urlField)
		self.__collection.appendChild(self.__fields)

		self.__images = self.__doc.createElement('images')

		self.__root.appendChild(self.__collection)
		self.__doc.appendChild(self.__root)
		self.__fieldsMap = dict(country='nationality',
							 classification='certification',
							 runtime='running-time',
							 o_title='orig-title',
							 notes='comments',
							 image='cover',
							 tag='keyword',
							 site='url')


	def addMedia(self, media):
		if len(media) == 0: return
		# add default Tellico values
		orig_media = 'DVD;VHS;VCD;DivX;Blu-ray;HD DVD'.split(';')
		orig_media.extend(media)
		# make sure unique
		set = {}
		media = [set.setdefault(e,e) for e in orig_media if e not in set]

		mediaField = self.__doc.createElement('field')
		mediaField.setAttribute('name', 'medium')
		mediaField.setAttribute('title', 'Medium')
		mediaField.setAttribute('flags', '2')
		mediaField.setAttribute('category', 'General')
		mediaField.setAttribute('format', '4')
		mediaField.setAttribute('type', '3')
		mediaField.setAttribute('i18n', 'yes')
		mediaField.setAttribute('allowed', ';'.join(media))
		self.__fields.appendChild(mediaField)

	def addEntry(self, movieData):
		"""
		Add a movie entry
		"""
		entryNode = self.__doc.createElement('entry')
		entryNode.setAttribute('id', movieData['id'])

		for key, values in movieData.items():
			if key == 'id':
				continue

			if key in self.__fieldsMap:
				field = self.__fieldsMap[key]
			else:
				field = key

			parentNode = self.__doc.createElement(field + 's')

			for value in values:
				if len(value) == 0: continue
				node = self.__doc.createElement(field)
				if field == 'certification': value += " (USA)"
				elif field == 'region': value = "Region " + value
				elif field == 'cover':
					imageNode = self.__doc.createElement('image')
					imageNode.setAttribute('format', 'JPEG')
					imageNode.setAttribute('id', value[0])
					imageNode.appendChild(self.__doc.createTextNode(value[1]))
					self.__images.appendChild(imageNode)
					value = value[0] # value was (id, md5)

				if field == 'cast':
					for v in value:
						columnNode = self.__doc.createElement('column')
						columnNode.appendChild(self.__doc.createTextNode(v.strip()))
						node.appendChild(columnNode)

				else:
					node.appendChild(self.__doc.createTextNode(value.strip()))

				if node.hasChildNodes(): parentNode.appendChild(node)

			if parentNode.hasChildNodes(): entryNode.appendChild(parentNode)

		self.__collection.appendChild(entryNode)

	def printXML(self):
		"""
		Outputs XML content to stdout
		"""
		self.__collection.appendChild(self.__images)
		print(XML_HEADER); print(DOCTYPE)
		print(self.__root.toxml())


class GriffithParser:
	def __init__(self):
		self.__dbPath = DB_PATH
		self.__domTree = BasicTellicoDOM()

	def run(self):
		"""
		Runs the parser: fetch movie ids, then fills and prints the DOM tree
		to stdout (in tellico format) so that tellico can use it.
		"""
		self.__conn = sqlite3.connect(self.__dbPath)
		self.__loadDatabase()
		# Print results to stdout
		self.__domTree.printXML()

	def __addMediaValues(self):
		c = self.__conn.cursor()
		c.execute("SELECT name FROM media")

		media = list([row[0].encode('utf-8') for row in c.fetchall()])
		self.__domTree.addMedia(media)


	def __fetchMovieIds(self):
		"""
		Retrieve all movie ids
		"""
		c = self.__conn.cursor()
		c.execute("SELECT movie_id FROM movies")
		data = c.fetchall()
		dataList = [row[0] for row in data]
		return dataList

	def __fetchMovieInfo(self, id):
		"""
		Fetches movie information
		"""
		#cast is a reserved word
		columns = ('title','director','rating','year','region',
					'country','genre','classification','plot',
					'runtime','o_title','studio','notes','image',
					'[cast]','loaned','color','site')

		c = self.__conn.cursor()
		c.execute("SELECT %s FROM movies WHERE movie_id=%s" % (','.join(columns),id))
		row = c.fetchone()

		data = {}
		data['id'] = str(id)

		for i in range(len(columns)):
			if row[i] == None : continue

			try:
				value = row[i].encode('utf-8')
			except:
				value = str(row[i])

			col = columns[i].replace('[','').replace(']','')

			if col == 'genre' or col == 'studio':
				values = value.split('/')
			elif col == 'plot' or col == 'notes':
				value = value.replace('\n', '\n<br/>')
				values = (value,)
			elif col == 'cast':
				values = []
				lines = value.split('\n')
				for line in lines:
					cast = line.split('as')
					values.append(cast)
			elif col == 'image':
				imgfile = POSTERS_PATH + value + '.jpg'
				img = file(imgfile,'rb').read()
				values = ((value + '.jpg', base64.encodestring(img)),)
			elif col == 'loaned':
				if value == '0': value = ''
				values = (value,)
			elif col == 'color':
				if value == '1': value = 'Color'
				elif value == '2': value = 'Black & White'
				values = (value,)
			else:
				values = (value,)
			col = col.replace('"','')
			data[col] = values

		# get medium
		c.execute("SELECT name FROM media WHERE medium_id IN (SELECT medium_id FROM movies WHERE movie_id=%s)" % id)

		media = list([row[0].encode('utf-8') for row in c.fetchall()])
		if len(media) > 0: data['medium'] = media

		# get all tags
		c.execute("SELECT name FROM tags WHERE tag_id IN (SELECT tag_id FROM movie_tag WHERE movie_id=%s)" % id)

		tags = list([row[0].encode('utf-8') for row in c.fetchall()])
		if len(tags) > 0: data['tag'] = tags

		# get all languages
		c.execute("SELECT name FROM languages WHERE lang_id IN (SELECT lang_id FROM movie_lang WHERE movie_id=%s)" % id)

		langs = list([row[0].encode('utf-8') for row in c.fetchall()])
		if len(langs) > 0: data['language'] = langs

		return data


	def __loadDatabase(self):
		# Get all ids
		self.__addMediaValues();
		ids = self.__fetchMovieIds()

		# Now retrieve data
		if ids:
			for entry in ids:
				data = self.__fetchMovieInfo(entry)
				self.__domTree.addEntry(data)
		else:
			return None



def main():
	parser = GriffithParser()
	parser.run()

if __name__ == '__main__':
	main()
