# Copyright 2005-2014 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

from __future__ import print_function


import sys
import textwrap

import portage
from portage import os
from portage.emaint.module import Modules
from portage.emaint.progress import ProgressBar
from portage.emaint.defaults import DEFAULT_OPTIONS
from portage.util._argparse import ArgumentParser

class OptionItem(object):
	"""class to hold module ArgumentParser options data
	"""

	def __init__(self, opt):
		"""
		@type opt: dictionary
		@param opt: options parser options
		"""
		self.short = opt.get('short')
		self.long = opt.get('long')
		# '-' are not allowed in python identifiers
		# so store the sanitized target variable name
		self.target = self.long[2:].replace('-','_')
		self.help = opt.get('help')
		self.status = opt.get('status')
		self.func = opt.get('func')
		self.action = opt.get('action')
		self.type = opt.get('type')
		self.dest = opt.get('dest')

	@property
	def pargs(self):
		pargs = []
		if self.short is not None:
			pargs.append(self.short)
		if self.long is not None:
			pargs.append(self.long)
		return pargs

	@property
	def kwargs(self):
		# Support for keyword arguments varies depending on the action,
		# so only pass in the keywords that are needed, in order
		# to avoid a TypeError.
		kwargs = {}
		if self.help is not None:
			kwargs['help'] = self.help
		if self.action is not None:
			kwargs['action'] = self.action
		if self.type is not None:
			kwargs['type'] = self.type
		if self.dest is not None:
			kwargs['dest'] = self.dest
		return kwargs

def usage(module_controller):
		_usage = "usage: emaint [options] COMMAND"

		desc = "The emaint program provides an interface to system health " + \
			"checks and maintenance. See the emaint(1) man page " + \
			"for additional information about the following commands:"

		_usage += "\n\n"
		for line in textwrap.wrap(desc, 65):
			_usage += "%s\n" % line
		_usage += "\nCommands:\n"
		_usage += "  %s" % "all".ljust(15) + \
			"Perform all supported commands\n"
		textwrap.subsequent_indent = ' '.ljust(17)
		for mod in module_controller.module_names:
			desc = textwrap.wrap(module_controller.get_description(mod), 65)
			_usage += "  %s%s\n" % (mod.ljust(15), desc[0])
			for d in desc[1:]:
				_usage += "  %s%s\n" % (' '.ljust(15), d)
		return _usage


def module_opts(module_controller, module):
	_usage = " %s module options:\n" % module
	opts = module_controller.get_func_descriptions(module)
	if opts == {}:
		opts = DEFAULT_OPTIONS
	for opt in sorted(opts):
		optd = opts[opt]
		opto = "  %s, %s" % (optd['short'], optd['long'])
		_usage += '%s %s\n' % (opto.ljust(15), optd['help'])
	_usage += '\n'
	return _usage


class TaskHandler(object):
	"""Handles the running of the tasks it is given"""

	def __init__(self, show_progress_bar=True, verbose=True, callback=None, module_output=None):
		self.show_progress_bar = show_progress_bar
		self.verbose = verbose
		self.callback = callback
		self.module_output = module_output
		self.isatty = os.environ.get('TERM') != 'dumb' and sys.stdout.isatty()
		self.progress_bar = ProgressBar(self.isatty, title="Emaint", max_desc_length=27)

	def run_tasks(self, tasks, func, status=None, verbose=True, options=None):
		"""Runs the module tasks"""
		if tasks is None or func is None:
			return
		for task in tasks:
			inst = task()
			show_progress = self.show_progress_bar and self.isatty
			# check if the function is capable of progressbar 
			# and possibly override it off
			if show_progress and hasattr(inst, 'can_progressbar'):
				show_progress = inst.can_progressbar(func)
			if show_progress:
				self.progress_bar.reset()
				self.progress_bar.set_label(func + " " + inst.name())
				onProgress = self.progress_bar.start()
			else:
				onProgress = None
			kwargs = {
				'onProgress': onProgress,
				'module_output': self.module_output,
				# pass in a copy of the options so a module can not pollute or change
				# them for other tasks if there is more to do.
				'options': options.copy()
				}
			result = getattr(inst, func)(**kwargs)
			if show_progress:
				# make sure the final progress is displayed
				self.progress_bar.display()
				print()
				self.progress_bar.stop()
			if self.callback:
				self.callback(result)


def print_results(results):
	if results:
		print()
		print("\n".join(results))
		print("\n")


def emaint_main(myargv):

	# Similar to emerge, emaint needs a default umask so that created
	# files (such as the world file) have sane permissions.
	os.umask(0o22)

	module_controller = Modules(namepath="portage.emaint.modules")
	module_names = module_controller.module_names[:]
	module_names.insert(0, "all")


	parser = ArgumentParser(usage=usage(module_controller))
	# add default options
	parser_options = []
	for opt in DEFAULT_OPTIONS:
		parser_options.append(OptionItem(DEFAULT_OPTIONS[opt]))
	for mod in module_names[1:]:
		desc = module_controller.get_func_descriptions(mod)
		if desc:
			for opt in desc:
				parser_options.append(OptionItem(desc[opt]))
	for opt in parser_options:
		parser.add_argument(*opt.pargs, **opt.kwargs)

	options, args = parser.parse_known_args(args=myargv)

	if options.version:
		print(portage.VERSION)
		return os.EX_OK

	if len(args) != 1:
		parser.error("Incorrect number of arguments")
	if args[0] not in module_names:
		parser.error("%s target is not a known target" % args[0])

	check_opt = None
	func = status = long_action = None
	for opt in parser_options:
		if opt.long == '--check':
			# Default action
			check_opt = opt
		if opt.status and getattr(options, opt.target, False):
			if long_action is not None:
				parser.error("--%s and %s are exclusive options" %
					(long_action, opt.long))
			status = opt.status
			func = opt.func
			long_action = opt.long.lstrip('-')

	if long_action is None:
		#print("DEBUG: long_action is None: setting to 'check'")
		long_action = 'check'
		func = check_opt.func
		status = check_opt.status

	if args[0] == "all":
		tasks = []
		for m in module_names[1:]:
			#print("DEBUG: module: %s, functions: " % (m, str(module_controller.get_functions(m))))
			if func in module_controller.get_functions(m):
				tasks.append(module_controller.get_class(m))
	elif func in module_controller.get_functions(args[0]):
		tasks = [module_controller.get_class(args[0] )]
	else:
		portage.util.writemsg(
			"\nERROR: module '%s' does not have option '--%s'\n\n" %
			(args[0], long_action), noiselevel=-1)
		portage.util.writemsg(module_opts(module_controller, args[0]),
			noiselevel=-1)
		sys.exit(1)

	# need to pass the parser options dict to the modules
	# so they are available if needed.
	task_opts = options.__dict__
	taskmaster = TaskHandler(callback=print_results, module_output=sys.stdout)
	taskmaster.run_tasks(tasks, func, status, options=task_opts)
