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

from __future__ import print_function

import argparse
import sys
import textwrap

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

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')
		self.choices = opt.get('choices')

	@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
		if self.choices is not None:
			kwargs['choices'] = self.choices
		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]
		if 'short' in optd:
			opto = "  %s, %s" % (optd['short'], optd['long'])
		else:
			opto = "  %s" % (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_path = os.path.join(
		(os.path.dirname(
		os.path.realpath(__file__))), "modules"
		)
	module_controller = Modules(
		path=module_path,
		namepath="portage.emaint.modules")
	module_names = module_controller.module_names[:]
	module_names.insert(0, "all")

	parser = argparse.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]))
		desc = module_controller.get_opt_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 long_action in module_controller.get_functions(m):
				tasks.append(module_controller.get_class(m))
	elif long_action 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__
	task_opts['return-messages'] = True
	taskmaster = TaskHandler(callback=print_results, module_output=sys.stdout)
	taskmaster.run_tasks(tasks, func, status, options=task_opts)
