import os, sys, time
from optparse import make_option
from tempfile import mkdtemp, NamedTemporaryFile
import tarfile
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError

from ...components import db, glacier, lib

# Based on: http://code.google.com/p/django-backup/
# Based on: http://www.djangosnippets.org/snippets/823/
# Based on: http://www.yashh.com/blog/2008/sep/05/django-database-backup-view/
class Command(BaseCommand):
	option_list = BaseCommand.option_list + (
		make_option('-o', '--output', default=None, dest='output',
			help='Write backup to file'),
		make_option('-d', '--outdir', default=None, dest='outdir',
			help='Write backup to timestamped file in a directory'),
		make_option('-g', '--glacier', default=None, dest='glacier',
			help='Upload backup to the Amazon Glacier vault with the given ARN'),
		make_option('-O', '--stdout', action='store_true', dest='stdout',
			help='Output backup tarball to standard output'),
		make_option('--extra', '-e', action='append', default=[], dest='extras',
			help='Include extra directories or files in the backup tarball'),
	)
	help = "Back up a Django installation (database and media directory)."

	def handle(self, *args, **options):
		extras = options.get('extras')

		output_file = options.get('output')
		output_dir = options.get('outdir')
		glacier_vault = options.get('glacier')
		output_to_stdout = options.get('stdout')
		output_file_temporary = False

		# glacier backups go to a temporary file
		if glacier_vault is not None or output_to_stdout:
			output_file_temporary = True
			output_file_obj = NamedTemporaryFile(delete=False)
			output_file_obj.close() # we'll open it later
			output_file = output_file_obj.name

		if output_file is None:
			if output_dir is None:
				raise CommandError('You must specify an output file')
			else:
				output_file = os.path.join(output_dir, '{}.tgz'.format(_time()))

		media_root = settings.MEDIA_ROOT

		# Create a temporary directory to perform our backup in
		backup_root = mkdtemp()
		database_root = os.path.join(backup_root, 'databases')
		os.mkdir(database_root)

		# Back up databases
		db.backup_to(settings, database_root)

		# create backup gzipped tarball
		with tarfile.open(output_file, 'w:gz') as tf:
			tf.add(database_root, arcname='backup/databases')
			tf.add(media_root, arcname='backup/media')
			if len(extras) > 0:
				extras_mf = NamedTemporaryFile(delete=False)
				for count, extra in enumerate(extras):
					tf.add(extra, arcname='backup/extras/{}'.format(count))
					extras_mf.write('{},{}\n'.format(count, extra.replace(',','\\,')))
				extras_mf.close()
				tf.add(extras_mf.name, arcname='backup/extras/manifest')
				os.unlink(extras_mf.name)

		# upload to glacier
		if glacier_vault is not None:
			glacier.upload(glacier_vault, output_file, settings)
			glacier.reconcile(glacier_vault, settings)
			glacier.prune(glacier_vault, settings)

		# output to stdout
		if output_to_stdout:
			with open(output_file, 'r') as f:
				sys.stdout.write(f.read())

		# clean up
		lib.rm_rf(backup_root)
		if output_file_temporary:
			os.unlink(output_file)

def _time():
	return time.strftime('%Y%m%d-%H%M%S')
