#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
opsi-backup

opsi-backup is part of the desktop management solution opsi
(open pc server integration) http://www.opsi.org

Copyright (C) 2010-2016 uib GmbH

http://www.uib.de/

All rights reserved.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.

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 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
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

@copyright:	uib GmbH <info@uib.de>
@author: Christian Kampka <c.kampka@uib.de>
@license: GNU General Public License version 2
"""

import locale
import os
import sys

from OPSI.Logger import Logger, LOG_WARNING, LOG_INFO
from OPSI.Util.Task.Backup import OpsiBackup
from OPSI.Util.Collections import DefaultList
from OPSI.Util import argparse

__version__ = "4.0.6.11"

logger = Logger()

USAGE = '''
Usage: %s [common-options] <command> [command-options]

Creates and restores opsi backups.
Version %s.

Common options:
   -h, --help                          Show this help message and exit
   -l, --log-level    <log-level>      Set log level to <log-level> (default: 5)
                                          0=nothing, 1=essential, 2=critical, 3=error, 4=warning
                                          5=notice, 6=info, 7=debug, 8=debug2, 9=confidential
   -v, --verbose                       Log to standard error
   --log-file         <log-file>       Log to <log-file>

Commands:
   verify     <backup-archive>         Verify integrity of <backup-archive>.

   restore    <backup-archive>         Restore data from <backup-archive>.
      --mode        {raw|data}         Select a mode that should be used for restoration (default: raw).
      --backends    <backend>          Select a backend to restore or 'all' for all backends.
                                          Can be given multiple times.
      --configuration                  Restore opsi configuration.
      -f, --force                      Ignore sanity checks and try to apply anyways. Use with caution!

   create     [destination]            Create a new backup.
                                          If [destination] is omitted, a backup archive will be created
                                          in the current directory. If [destination] is an existing
                                          directory, the backup archive will be created in that directory.
                                          If [destination] does not exist or is a file, [destination]
                                          will be used as backup archive destination file.
      --mode        {raw|data}         Select a mode that should be used for creation (default: raw).
      --flush-logs                        Causes mysql to flush table logs to disk before the backup (recommended).
      --backends    <backend>          Select a backend to create a backup for. Use 'auto' for automatic detection
                                          of used backends or 'all' for all backends.
                                          Can be given multiple times.
      --no-configuration               Do not backup opsi configuration.
      -c, --compression {gz|bz2|none}  Sets the compression format for the archive (default: bz2).

''' % (os.path.basename(sys.argv[0]), __version__)


class HelpFormatter(argparse.HelpFormatter):
	def format_help(self):
		return USAGE


def main():
	logger.setLogFormat('[%l] [%D] %M')
	logger.setConsoleLevel(LOG_WARNING)

	parser = argparse.ArgumentParser(prog="opsi-backup", add_help=False, usage=USAGE, formatter_class=HelpFormatter)
	parser.add_argument("-h", "--help", action="help")
	parser.add_argument("-v", "--verbose", action="store_true", default=False)
	parser.add_argument("-l", "--log-level", action="store", default=5, type=int)
	parser.add_argument("--log-file", metavar='FILE', default="/var/log/opsi/opsi-backup.log")

	subs = parser.add_subparsers(title="commands", dest="command")

	parser_verify = subs.add_parser("verify")
	parser_verify.add_argument("file", nargs="+")

	parser_restore = subs.add_parser("restore")
	parser_restore.add_argument("file", nargs=1)
	parser_restore.add_argument("--mode", nargs=1, choices=['raw', 'data'], default="raw")
	parser_restore.add_argument("--backends", action="append")
	parser_restore.add_argument("--configuration", action="store_true", default=False)
	parser_restore.add_argument("-f", "--force", action="store_true", default=False)

	parser_create = subs.add_parser("create")
	parser_create.add_argument("destination", nargs="?")
	parser_create.add_argument("--mode", nargs=1, choices=['raw', 'data'], default="raw")
	parser_create.add_argument("--flush-logs", action="store_true", default=False)
	parser_create.add_argument("--backends", action="append", default=DefaultList(["auto"]))
	parser_create.add_argument("--no-configuration", action="store_true", default=False)
	parser_create.add_argument("-c", "--compression", nargs="?", default="bz2", choices=['gz', 'bz2', 'none'])

	try:
		args = parser.parse_args()
	except Exception:
		print(USAGE)
		return 1

	if args.verbose:
		logger.setConsoleColor(True)
		logger.setConsoleLevel(args.log_level)

	if args.log_file:
		logger.setLogFile(args.log_file)
		logger.setFileLevel(args.log_level)

	backup = OpsiBackup(stdout=sys.stdout)
	result = 0
	if args.command == 'restore':
		if not args.backends:
			logger.warning("No backend given!")

		result = backup._restore(
			file=args.file, mode=args.mode, backends=args.backends,
			configuration=args.configuration, force=args.force
		)
	elif args.command == 'verify':
		result = backup._verify(file=args.file)
		if result == 0:
			print("Verified")
		else:
			print("Verification failed")
	elif args.command == 'create':
		result = backup._create(
			destination=args.destination, mode=args.mode,
			backends=args.backends, no_configuration=args.no_configuration,
			compression=args.compression, flush_logs=args.flush_logs
		)

	try:
		result = int(result)
	except (TypeError, ValueError):
		pass

	return result


if __name__ == "__main__":
	try:
		ret = main()
	except Exception as exception:
		logger.logException(exception, LOG_INFO)
		print >> sys.stderr, (u"\nERROR: %s\n" % exception).encode(locale.getpreferredencoding(), 'replace')
		ret = 1

	sys.exit(ret)
