# -*- coding: UTF-8 -*-

__revision__ = '$Id: backup.py 1040 2008-11-15 21:13:49Z mikej06 $'

# Copyright (c) 2005-2008 Vasco Nunes, Piotr Ożarowski
#
# 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 Library 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
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

# You may use and distribute this software under the terms of the
# GNU General Public License, version 2 or later

import config, edit, gutils, sql
import gtk
import os.path
import zipfile

def backup(self):
	"""perform a compressed griffith database/posters/preferences backup"""
	filename = gutils.file_chooser(_("Save Griffith backup"), \
		action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons= \
		(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK), \
		name=self.config.get('name','griffith', section='database') + '_backup.zip')
	if filename and filename[0]:
		overwrite = None
		zipfilename = filename[0].decode('utf-8')
		if os.path.isfile(zipfilename):
			response = gutils.question(self, \
				_("File exists. Do you want to overwrite it?"), \
				1, self.widgets['window'])
			if response == -8:
				overwrite = True
			else:
				overwrite = False

		if overwrite == True or overwrite is None:
			try:
				if zipfile.zlib is not None:
					mzip = zipfile.ZipFile(zipfilename, 'w', zipfile.ZIP_DEFLATED)
				else:
					mzip = zipfile.ZipFile(zipfilename, 'w')
			except:
				gutils.error(self, _("Error creating backup"), self.widgets['window'])
				return False
			mzip.write(os.path.join(self.locations['home'],'griffith.cfg').encode('utf-8'))
			if self.db.metadata.engine.name == 'sqlite':
				fileName = os.path.join(self.locations['home'], self.config.get('name','griffith', section='database') + '.db').encode('utf-8')
				mzip.write(fileName)
			else:
				gutils.error(self, _("Backup function is available only for SQLite engine for now"), self.widgets['window'])
				return False
				from tempfile import mkdtemp
				from shutil import rmtree, move
				from sqlalchemy import BoundMetaData
				import copy
				# if backup_to_sqlite:
				tmp_dir = mkdtemp()
				tmp_config = copy.deepcopy(self.config)
				tmp_config._file = os.path.join(tmp_dir,'griffith.cfg')
				tmp_config.get('type', 'sqlite', section='database') == 'sqlite'
				tmp_config.set('file', section='database') == "griffith.db"
				tmp_config.save()

#				tmp_db = sql.GriffithSQL(tmp_config, self.debug, tmp_dir)
#				for i in self.db.metadata.tables
#				tmp_db.

				tmp_file = os.path.join(tmp_dir, tmp_config.get('file', 'griffith.db', section='database')).encode('utf-8')
				tmp_metadata = BoundMetaData("sqlite:///%s" % tmp_file)
				tmp_metadata.tables = self.db.metadata.tables
				tmp_metadata.create_all()
#				for table in self.db.metadata.tables.keys():
				for table in [t.name for t in self.db.metadata.table_iterator()]: # table_iterator() will return tables in *correct* order
					data = self.db.metadata.tables[table].select().execute().fetchall()
					tmp_metadata.tables[table].insert().execute(data)
#					for item in data:
#						tmp_metadata.tables[table].insert().execute(item)
				tmp_metadata.engine.commit()
				
				mzip.write(tmp_file)
				rmtree(tmp_dir)
			posters_dir = os.path.join(self.locations['posters'])
			for movie in self.db.Movie.select():
				if movie.image is not None:
					filename = str(movie.image)+".jpg"
					filename = os.path.join(posters_dir, filename).encode('utf-8')
					if os.path.isfile(filename):
						try:
							mzip.write(filename)
						except:
							self.debug.show("Can't compress %s" % filename)
			mzip.close()
			gutils.info(self, _("Backup has been created"), self.widgets['window'])

def restore(self):
	"""restores a griffith compressed backup"""
	filename = gutils.file_chooser(_("Restore Griffith backup"), \
		action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons= \
		(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, \
		gtk.STOCK_OPEN, gtk.RESPONSE_OK))
	if filename[0]:
		try:
			zip = zipfile.ZipFile(filename[0], 'r')
		except:
			gutils.error(self, _("Can't read backup file"), self.widgets['window'])
			return False
		mypath = os.path.join(self.locations['posters'])
		old_config_file = False
		for each in zip.namelist():
			file_to_restore = os.path.split(each)
			if not os.path.isdir(file_to_restore[1]):
				if file_to_restore[1] == '':
					continue
				if file_to_restore[1].endswith('.jpg'):
					myfile = os.path.join(mypath,file_to_restore[1])
				else:
					myfile = os.path.join(self.locations['home'],file_to_restore[1])
				if file_to_restore[1].endswith('.conf'):
					old_config_file = myfile
				outfile = open(myfile, 'wb')
				outfile.write(zip.read(each))
				outfile.flush()
				outfile.close()
		zip.close()

		# restore config file
		self.config = config.Config(file=os.path.join(self.locations['home'],'griffith.cfg'))
		if old_config_file:
			self.debug.show('Old config file detected. Please note that it will not be used.')
			f = open(old_config_file, 'r')
			old_config_raw_data = f.read()
			f.close()
			if old_config_raw_data.find('griffith.gri') >= -1:
				self.config.set('file', 'griffith.gri', section='database')

		filename = os.path.join(self.locations['home'], self.config.get('name', 'griffith', section='database') + '.db')

		self.db.metadata.engine.dispose() # close DB
		from sqlalchemy.orm import clear_mappers
		clear_mappers()

		# check if file needs conversion
		if self.config.get('file', 'griffith.db', section='database').lower().endswith('.gri'):
			self.debug.show('Old database format detected. Converting...')
			from dbupgrade import convert_from_old_db
			from initialize	import location_posters
			if convert_from_old_db(self, filename, os.path.join(self.locations['home'], 'griffith.db')):
				self.config.save()
				location_posters(self.locations, self.config)
			else:
				print 'Cant convert old database, exiting.'
				import sys
				sys.exit(4)

		self.db = sql.GriffithSQL(self.config, self.debug, self.locations['home'])
		from initialize	import dictionaries, people_treeview
		dictionaries(self)
		people_treeview(self)
		# let's refresh the treeview
		self.clear_details()
		self.populate_treeview()
		gutils.info(self, _("Backup restored"), self.widgets['window'])

def merge(self):	# FIXME
	"""
		Merge database from:
		* compressed backup
		* SQLite2 *.gri file
		* SQLite3 *.db file
	"""
	filename = gutils.file_chooser(_("Restore Griffith backup"), \
		action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons= \
		(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, \
		gtk.STOCK_OPEN, gtk.RESPONSE_OK))[0]
	if filename:
		from tempfile import mkdtemp
		from shutil import rmtree, move

		#tmp_config={}
		#tmp_config.get('type', 'sqlite', section='database')

		if filename.lower().endswith('.zip'):
			tmp_dir = mkdtemp()
			try:
				zip = zipfile.ZipFile(filename, 'r')
			except:
				gutils.error(self, _("Can't read backup file"), self.widgets['window'])
				return False
			for each in zip.namelist():
				file_to_restore = os.path.split(each)
				if not os.path.isdir(file_to_restore[1]):
					myfile = os.path.join(tmp_dir, file_to_restore[1])
					outfile = open(myfile, 'wb')
					outfile.write(zip.read(each))
					outfile.flush()
					outfile.close()
			# load stored database filename
			tmp_config = config.Config(file=os.path.join(tmp_dir,'griffith.conf'))
			filename = os.path.join(tmp_dir, tmp_config('name', 'griffith', section='database') + '.db')
			zip.close()

		# check if file needs conversion
		if filename.lower().endswith(".gri"):
			if os.path.isfile(filename) and  open(filename).readline()[:47] == "** This file contains an SQLite 2.1 database **":
				self.debug.show("MERGE: SQLite2 database format detected. Converting...")
				if not self.db.convert_from_sqlite2(filename, os.path.join(tmp_dir, self.config.get('file', 'griffith.db', section='database'))):
					self.debug.show("MERGE: Can't convert database, aborting.")
					return False
		tmp_dir, tmp_file = os.path.split(filename)
		self.config.get('file', tmp_file, section='database') 

		tmp_db = sql.GriffithSQL(tmp_config, self.debug, tmp_dir)

		merged=0
		movies = tmp_db.Movie.count()
		for movie in tmp_db.Movie.select():
			if self.db.Movie.get_by(o_title=movie.o_title) is not None:
				continue
			t_movies = {}
			for column in movie.mapper.c.keys():
				t_movies[column] = eval("movie.%s"%column)

			# replace number with new one
			t_movies["number"] = gutils.find_next_available(self.db)

			# don't restore volume/collection/tag/language/loan data (it's dangerous)
			t_movies.pop('movie_id')
			t_movies.pop('loaned')
			t_movies.pop('volume_id')
			t_movies.pop('collection_id')

			if self.db.add_movie(t_movies):
				print t_movies

			if movie.image is not None:
				dest_file = os.path.join(self.locations['posters'], movie.image+'.jpg')
				if not os.path.isfile(dest_file):
					src_file = os.path.join(tmp_dir, movie.image+'.jpg')
					if os.path.isfile(src_file):
						move(src_file, dest_file)
			merged+=1
		rmtree(tmp_dir)

		from initialize	import dictionaries, people_treeview
		dictionaries(self)
		people_treeview(self)
		# let's refresh the treeview
		self.clear_details()
		self.populate_treeview(self.db.Movie.select())
		#gutils.info(self, _("Databases merged!\n\nProcessed movies: %s\nMerged movies: %s"%(movies, merged)), self.widgets['window'])

