#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
###################################
# MongoDB Backup & Restore
# Author: netkiller@msn.com
# Home:	http://www.netkiller.cn
###################################
import os,sys
import logging, logging.handlers
from configparser import ConfigParser,RawConfigParser, NoSectionError
from optparse import OptionParser, OptionGroup
module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0,module)
from netkiller.mongo import *

class MongoTools():

	def __init__(self): 
		# super().__init__()
		self.logging = getLogger(__name__)

		self.parser = OptionParser("usage: %prog [options] <item item1 item2 ... item(n)>")
		self.parser.add_option('-c', '--config', dest='config', help='config file', default='/usr/local/etc/mongo.ini', metavar='/usr/local/etc/mongo.ini')
		self.parser.add_option('-e', '--edit', dest='edit', action='store_true', help="open the config file")
		self.parser.add_option('-l', '--list', dest='list', action='store_true', help="list items")
		self.parser.add_option('-H', '--history', dest='history', action='store_true', help="backup history")
		self.parser.add_option('','--retain', dest='retain', help='The number of days retained', default=30, metavar='30')
		
		group = OptionGroup(self.parser, "Output options")
		group.add_option('-o','--out', dest='out', help="output directory, or '-' for stdout (default: 'dump')", default=None, metavar='<directory>')
		group.add_option('-a','--archive', dest='archive', help='dump as an archive to the specified path. If flag is specified without a value, archive is written to stdout', default=None, metavar='<file>')
		group.add_option('-g', '--gzip', dest='gzip', action='store_true', help="compress archive or collection output with Gzip")
		# group.add_option('-u','--gunzip', dest='gunzip', help='decompress files', default=None, metavar='backup.sql.gz')
		# group.add_option('-s','--show', dest='zcat', help='print sql', default=None, metavar='backup.sql.gz')
		self.parser.add_option_group(group)

		group = OptionGroup(self.parser, "GnuPG encrypt or decrypt files")
		
		group.add_option('-r','--recipient', dest='recipient', help='encrypt for USER-ID', default=None, metavar='netkiller@msn.com')
		group.add_option('', '--encrypt', dest='encrypt', action='store_true', help="encrypt file")
		group.add_option('','--decrypt', dest='decrypt', help='decrypt file', default=None, metavar='backup.sql.gpg')
		# group.add_option('-S','--stdout', dest='stdout', help='print file', default=None, metavar='backup.sql.gpg')
		self.parser.add_option_group(group)
		
		self.parser.add_option('','--logfile', dest='logfile', help='logs file.', default='/dev/null', metavar='/var/log/dump.log')
		self.parser.add_option('', '--debug', action='store_true', dest="debug", help="debug mode")

		(self.options, self.args) = self.parser.parse_args()
		
		# self.config = ConfigParser()
		self.config = RawConfigParser()
		self.config.optionxform = lambda option: option
		self.config.read(self.options.config)

		try:
			if self.options.debug :
				logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
			else:
				if 'logfile' in self.config.defaults():
					self.logfile = self.config.defaults()['logfile']
				else:
					self.logfile = self.options.logfile
				logging.basicConfig(level=logging.NOTSET, format='%(asctime)s %(levelname)-8s %(message)s',	datefmt='%Y-%m-%d %H:%M:%S', filename=self.logfile, filemode='a')
		except Exception as err:
			print("Error: %s" %(err))
			sys.exit(2)	

		if self.options.out :
		 	self.out = self.options.out
		else:
			if 'directory' in self.config.defaults():
				self.out = self.config.defaults()['directory']
			else:
				self.out = '.'
				# print('No backup directory!')

		self.logging.debug('[DEFAULT] %s', self.config.defaults())

		if self.options.debug :
			self.logging.debug('Options %s', self.options)
			self.logging.debug('Args %s', self.args)

		if self.options.list :
			self.list()
		if self.options.history :
			if self.args :
				self.history(self.args)
			else:
				self.history()
		if self.options.edit :	
			os.system('vim '+ self.options.config)
			exit()
		
		if self.args :

			if self.options.decrypt and self.options.recipient:
				item = self.args[0]
				output = self.out +'/'+item+'/'+ self.options.decrypt.replace('.gpg', '')
				decrypt = self.out +'/'+item+'/'+ self.options.decrypt
				command = 'gpg --recipient {recipient} --output {output} --decrypt {decrypt} '.format(recipient=self.options.recipient, output=output, decrypt=decrypt)
				self.logging.debug(command)
				os.system(command)
				exit()

			self.logging.info("==================== Backup starting ====================")
			for item in self.args :
				self.dump(item)
				self.logging.info('%s [Done]', item)
			self.logging.info("==================== Backup delete ====================")
			self.retain(self.options.retain)
		else:
			self.usage()

	def usage(self):
		print("Netkiller MongoDB backup & restore")
		self.parser.print_help()
		print("\nHomepage: http://www.netkiller.cn\tAuthor: Neo <netkiller@msn.com>")
		exit()

	def list(self):
		self.logging.info(self.config.sections())
		for item in self.config.sections() :
			if self.config.has_option(item, 'description'):
				print('%s : %s' % (item, self.config.get(item, 'description')))
			else:
				print(item)
		exit()
	def conf(self, item):
		try:
			# print(self.config[item])
			conf = dict(self.config.items(item))
		except NoSectionError as error :
			print(error)
			exit()
		return 
	def retain(self, days):
		dump = MongoDump()
		dump.out(self.out)
		dump.copies(self.options.retain).delete()
	def dump(self, item):
		try:
			conf = dict(self.config.items(item))
		except NoSectionError as err :
			print('%s in %s' % (err, self.options.config))
			exit()
		self.logging.info('[%s] : %s' % (item, conf))
		try:
			dump = MongoDump()

			dump.username(conf['username'])
			dump.password(conf['password'])
			dump.db(conf['db'])	

			if 'host' in conf.keys():
				dump.hostname(conf['host'])

			if 'port' in conf.keys():
				dump.port(conf['port'])

			if 'authenticationDatabase' in conf.keys():
				dump.authenticationDatabase(conf['authenticationDatabase'])

			dump.config(item)

			if self.options.gzip :
				dump.gzip()

			if self.options.encrypt :
				if self.options.archive :
					output = self.options.archive
				else:
					output = self.out+'/'+item +'/'+ time.strftime('%Y-%m-%d.%H:%M:%S',time.localtime(time.time())) + '/' +dump.db
				if self.options.recipient :
					dump.GnuPG(self.options.recipient, output)
				else:
					dump.GnuPG(conf['recipient'], output)
			else:
				if self.options.archive :
					dump.archive(self.options.archive)
				else:
					timepoint = time.strftime('%Y-%m-%d.%H:%M:%S',time.localtime(time.time()))
					output = self.out+'/'+item + '/' + timepoint
					dump.out(output)
			dump.execute()
		except KeyError as error:
			print('The configuration item was not found: [%s] %s.' % (item, error))
	def history(self, items = None):
		if items == None:
			items = self.config.sections()
		for item in items :
			path = self.out+'/'+item
			if os.path.isdir(path):
				files = os.scandir(path)
				print('%s :' % item)
				for file in files:
					print('\t%s' % file.name)

		exit()
if __name__ == '__main__':
	try:
		mongo = MongoTools()
	except KeyboardInterrupt:
		print ("Crtl+C Pressed. Shutting down.")