"""This file provides common backup functions.
A main aim is to wrap windows and unix backup tasks in a single set of python functions
"""
# TODO: create logging

import os
import shutil
import time
import tarfile
import ConfigParser

import logging
logger = logging.getLogger("sysadmin.common.BackupUtils")

def getCurrentDate(separator = ""):
		"""Get current date in format yyyy-mm-dd with '-' replaced by separator parameter"""
		now = time.localtime(time.time())
		today = time.strftime("%Y" + separator + "%m" + separator + "%d", now)
		return today

class DbBackupInfo:
	"""Convenience class to hold information about a backup of a DB"""
	TYPE_PG = 0
	TYPE_MYSQL = 1
	
	def __init__(self, dbType = TYPE_PG, dbName = "__all__", username = "", password = ""):
		"""Can pass it either a set of arguments as shown above or an array (which is then taken to be the arguments in array form).
		Allow for arrays so that can easily parse from config files. Also allow dbType to be given either as enum from this class or as string such as 'pg', 'mysql'"""
		# do in reverse order to set default values first
		self.dbName = dbName
		self.username = username
		self.password = password
		dbTypeTmp = dbType
		
		# hack round the python limitation on function overloading
		# if first argument is an array then use assume that represents all arguments
		if isinstance(dbType, type([])):
			if len(dbType) > 0:
				dbTypeTmp = dbType[0]
			if len(dbType) > 1:
				dbName = dbType[1]
			if len(dbType) > 2:
				username = dbType[2]
			if len(dbType) > 3:
				password = dbType[3]
		
		# finally parse out work out the type of the db from dbTypeTmp
		# is dbType an int if so then an enum otherwise a string
		if isinstance(dbTypeTmp, type(0)):
			self.dbType = dbTypeTmp
		else:
			if dbType == "pg":
				self.dbType = DbBackupInfo.TYPE_PG
			elif dbType == "mysql":
				self.dbType = DbBackupInfo.TYPE_MYSQL
			else:
				raise Exception("Unknown db type: " + str(dbTypeTmp))

class BackupUtils:
	def __init__(self,insertCurrentDate = False, dateSeparator = ""):
		self.insertCurrentDate = insertCurrentDate
		self.dateSeparator = dateSeparator
		self._currentDate = getCurrentDate(dateSeparator)


	def getBackupFileName(self,currentName,backupExtension = ""):
		"""Generate backup file name by possibly adding current date and a backup extension to the current name"""
		(baseName,extension) = os.path.splitext(currentName)
		
		if self.insertCurrentDate:
			baseName += "_" + self._currentDate
		if backupExtension != "" and not(extension.endswith(backupExtension)):
			extension += "." + backupExtension
		
		return (baseName + extension)

	def getOutputFilePath(self, source, dest, backupExtension = ""):
		"""Generate output file path given file/dir to backup and destination.
		@return if(dest isDir) dest + tail(source) + [date] + 
		"""
		fileName = ""
		basePath = ""
		if os.path.isdir(dest):
			basePath = dest
			fileName = os.path.split(os.path.normpath(source))[1]
		else:
			# assume dest is supposed to be a file
			(basePath,fileName) = os.path.split(dest)
			
		result = os.path.join(basePath,self.getBackupFileName(fileName, backupExtension))
		return result

	def addFilesToTarArchive(self, source, dest):
		"""By default recurse into subdirectories. Uses integrated gzip by default. Auto naming of destination file if destination is a directory. Existing destination file will be overwritten"""
		tar = tarfile.open(self.getOutputFilePath(source[0],dest,"tgz"), "w:gz")
		tar.posix = False
		for ff in source:
			tar.add(ff)
		tar.close()
	
	def dbBackup(self, dbBackupInfo, destArchivePath, compress = True):
		"""May be a single or multiple db.
		@param compress If true pipe output through gzip"""
		backupCmd = ""
		logger.debug(str(dbBackupInfo.dbType))
		if dbBackupInfo.dbType == DbBackupInfo.TYPE_PG:
			backupCmd = self._getPgBackupCommand(dbBackupInfo)
		elif dbBackupInfo.dbType == DbBackupInfo.TYPE_MYSQL:
			backupCmd = self._getMysqlBackupCommand(dbBackupInfo)
		else:
			raise Exception("Unknown Database Type")		
		if compress:
			backupCmd += " | gzip "
		
		backupCmd += " > " + destArchivePath
		
		logger.debug("db name: " + dbBackupInfo.dbName + ", type=" + str(dbBackupInfo.dbType))
		logger.debug(backupCmd)
		os.system(backupCmd)
		
	def svnBackup(self):
		# pretty simple. Just hook into standard hot-backup script
		# reqd:
		# 1. location of hot-backup.py
		# 2. repos to backup (or path to repos: /var/svn
		pass
	
	def _getPgBackupCommand(self, dbBackupInfo):
		"""Password can not be submitted via the command line for postgres"""
		# TODO: insert check for password and throw exception if supplied
		
		result = "pg_dump"
		if dbBackupInfo.dbName == "__all__":
			result = "pg_dumpall"
		else:
			result += " " + dbBackupInfo.dbName
		
		if dbBackupInfo.username != "":
			# assume using ident auth and have to work using that
			# result += " --user " + dbBackupInfo.userName
			result = "sudo -u " + dbBackupInfo.username + " " + result
			
		result += " --inserts"
			
		return result
		
	def _getMysqlBackupCommand(self, dbBackupInfo):
		result = "mysqldump"
		
		if dbBackupInfo.username != "":
			result += " --user " + dbBackupInfo.username
			
		if dbBackupInfo.password != "":
			result += " --password=" + dbBackupInfo.password
		
		if dbBackupInfo.dbName == "__all__":
			result += " --all-databases"
		else:
			result += " " + dbBackupInfo.dbName
		
		return result
		pass
	
