#!/usr/bin/env python
# encoding: utf-8
# Scott Newton, 2005 (scottn)
# Thomas Nagy, 2006 (ita)

"Custom command-line options"

import os, sys, imp, types, tempfile, optparse
import Logs, Utils
from Constants import *

cmds = 'distclean configure build install clean uninstall check dist distcheck'.split()

# TODO remove in waf 1.6 the following two
commands = {}
is_install = False

options = {}
arg_line = []
launch_dir = ''
tooldir = ''
lockfile = os.environ.get('WAFLOCK', '.lock-wscript')
try: cache_global = os.path.abspath(os.environ['WAFCACHE'])
except KeyError: cache_global = ''
platform = Utils.unversioned_sys_platform()
conf_file = 'conf-runs-%s-%d.pickle' % (platform, ABI)

remote_repo = ['http://waf.googlecode.com/svn/']
"""remote directory for the plugins"""


# Such a command-line should work:  JOBS=4 PREFIX=/opt/ DESTDIR=/tmp/ahoj/ waf configure
default_prefix = os.environ.get('PREFIX')
if not default_prefix:
	if platform == 'win32':
		d = tempfile.gettempdir()
		default_prefix = d[0].upper() + d[1:]
		# win32 preserves the case, but gettempdir does not
	else: default_prefix = '/usr/local/'

default_jobs = os.environ.get('JOBS', -1)
if default_jobs < 1:
	try:
		if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
			default_jobs = os.sysconf('SC_NPROCESSORS_ONLN')
		else:
			default_jobs = int(Utils.cmd_output(['sysctl', '-n', 'hw.ncpu']))
	except:
		if os.name == 'java': # platform.system() == 'Java'
			from java.lang import Runtime
			default_jobs = Runtime.getRuntime().availableProcessors()
		else:
			# environment var defined on win32
			default_jobs = int(os.environ.get('NUMBER_OF_PROCESSORS', 1))

default_destdir = os.environ.get('DESTDIR', '')

def get_usage(self):
	cmds_str = []
	module = Utils.g_module
	if module:
		# create the help messages for commands
		tbl = module.__dict__
		keys = list(tbl.keys())
		keys.sort()

		if 'build' in tbl:
			if not module.build.__doc__:
				module.build.__doc__ = 'builds the project'
		if 'configure' in tbl:
			if not module.configure.__doc__:
				module.configure.__doc__ = 'configures the project'

		ban = ['set_options', 'init', 'shutdown']

		optlst = [x for x in keys if not x in ban
			and type(tbl[x]) is type(parse_args_impl)
			and tbl[x].__doc__
			and not x.startswith('_')]

		just = max([len(x) for x in optlst])

		for x in optlst:
			cmds_str.append('  %s: %s' % (x.ljust(just), tbl[x].__doc__))
		ret = '\n'.join(cmds_str)
	else:
		ret = ' '.join(cmds)
	return '''waf [command] [options]

Main commands (example: ./waf build -j4)
%s
''' % ret


setattr(optparse.OptionParser, 'get_usage', get_usage)

def create_parser(module=None):
	Logs.debug('options: create_parser is called')
	parser = optparse.OptionParser(conflict_handler="resolve", version = 'waf %s (%s)' % (WAFVERSION, WAFREVISION))

	parser.formatter.width = Utils.get_term_cols()
	p = parser.add_option

	p('-j', '--jobs',
		type    = 'int',
		default = default_jobs,
		help    = 'amount of parallel jobs (%r)' % default_jobs,
		dest    = 'jobs')

	p('-k', '--keep',
		action  = 'store_true',
		default = False,
		help    = 'keep running happily on independent task groups',
		dest    = 'keep')

	p('-v', '--verbose',
		action  = 'count',
		default = 0,
		help    = 'verbosity level -v -vv or -vvv [default: 0]',
		dest    = 'verbose')

	p('--nocache',
		action  = 'store_true',
		default = False,
		help    = 'ignore the WAFCACHE (if set)',
		dest    = 'nocache')

	p('--zones',
		action  = 'store',
		default = '',
		help    = 'debugging zones (task_gen, deps, tasks, etc)',
		dest    = 'zones')

	p('-p', '--progress',
		action  = 'count',
		default = 0,
		help    = '-p: progress bar; -pp: ide output',
		dest    = 'progress_bar')

	p('--targets',
		action  = 'store',
		default = '',
		help    = 'build given task generators, e.g. "target1,target2"',
		dest    = 'compile_targets')

	gr = optparse.OptionGroup(parser, 'configuration options')
	parser.add_option_group(gr)
	gr.add_option('-b', '--blddir',
		action  = 'store',
		default = '',
		help    = 'out dir for the project (configuration)',
		dest    = 'blddir')
	gr.add_option('-s', '--srcdir',
		action  = 'store',
		default = '',
		help    = 'top dir for the project (configuration)',
		dest    = 'srcdir')
	gr.add_option('--prefix',
		help    = 'installation prefix (configuration) [default: %r]' % default_prefix,
		default = default_prefix,
		dest    = 'prefix')

	gr.add_option('--download',
		action  = 'store_true',
		default = False,
		help    = 'try to download the tools if missing',
		dest    = 'download')

	gr = optparse.OptionGroup(parser, 'installation options')
	parser.add_option_group(gr)
	gr.add_option('--destdir',
		help    = 'installation root [default: %r]' % default_destdir,
		default = default_destdir,
		dest    = 'destdir')
	gr.add_option('-f', '--force',
		action  = 'store_true',
		default = False,
		help    = 'force file installation',
		dest    = 'force')

	return parser

def parse_args_impl(parser, _args=None):
	global options, commands, arg_line
	(options, args) = parser.parse_args(args=_args)

	arg_line = args
	#arg_line = args[:] # copy

	# By default, 'waf' is equivalent to 'waf build'
	commands = {}
	for var in cmds: commands[var] = 0
	if not args:
		commands['build'] = 1
		args.append('build')

	# Parse the command arguments
	for arg in args:
		commands[arg] = True

	# the check thing depends on the build
	if 'check' in args:
		idx = args.index('check')
		try:
			bidx = args.index('build')
			if bidx > idx:
				raise ValueError('build before check')
		except ValueError, e:
			args.insert(idx, 'build')

	if args[0] != 'init':
		args.insert(0, 'init')

	# TODO -k => -j0
	if options.keep: options.jobs = 1
	if options.jobs < 1: options.jobs = 1

	if 'install' in sys.argv or 'uninstall' in sys.argv:
		# absolute path only if set
		options.destdir = options.destdir and os.path.abspath(os.path.expanduser(options.destdir))

	Logs.verbose = options.verbose
	Logs.init_log()

	if options.zones:
		Logs.zones = options.zones.split(',')
		if not Logs.verbose: Logs.verbose = 1
	elif Logs.verbose > 0:
		Logs.zones = ['runner']
	if Logs.verbose > 2:
		Logs.zones = ['*']

# TODO waf 1.6
# 1. rename the class to OptionsContext
# 2. instead of a class attribute, use a module (static 'parser')
# 3. parse_args_impl was made in times when we did not know about binding new methods to classes

class Handler(Utils.Context):
	"""loads wscript modules in folders for adding options
	This class should be named 'OptionsContext'
	A method named 'recurse' is bound when used by the module Scripting"""

	parser = None
	# make it possible to access the reference, like Build.bld

	def __init__(self, module=None):
		self.parser = create_parser(module)
		self.cwd = os.getcwd()
		Handler.parser = self

	def add_option(self, *k, **kw):
		self.parser.add_option(*k, **kw)

	def add_option_group(self, *k, **kw):
		return self.parser.add_option_group(*k, **kw)

	def get_option_group(self, opt_str):
		return self.parser.get_option_group(opt_str)

	def sub_options(self, *k, **kw):
		if not k: raise Utils.WscriptError('folder expected')
		self.recurse(k[0], name='set_options')

	def tool_options(self, *k, **kw):
		Utils.python_24_guard()

		if not k[0]:
			raise Utils.WscriptError('invalid tool_options call %r %r' % (k, kw))
		tools = Utils.to_list(k[0])

		# TODO waf 1.6 remove the global variable tooldir
		path = Utils.to_list(kw.get('tdir', kw.get('tooldir', tooldir)))

		for tool in tools:
			tool = tool.replace('++', 'xx')
			if tool == 'java': tool = 'javaw'
			if tool.lower() == 'unittest': tool = 'unittestw'
			module = Utils.load_tool(tool, path)
			try:
				fun = module.set_options
			except AttributeError:
				pass
			else:
				fun(kw.get('option_group', self))

	def parse_args(self, args=None):
		parse_args_impl(self.parser, args)

