# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
top = '..'

from waflib import Options

def options(opt):
    for subdir in opt.path.ant_glob(['*'], dir=True, src=False):
        tool = subdir.path_from(opt.path)
        opt.add_option('--enable-%s' % tool,
                       help='Build tool %s, enabled by default' % tool,
                       action='store_true', dest='enable_%s' % tool)
        opt.add_option('--disable-%s' % tool,
                       help='Do not build tool %s' % tool,
                       action='store_true', dest='disable_%s' % tool)
        opt.recurse(str(tool), mandatory=False)

def configure(conf):
    all_tools = set() # all available tools
    enabled_tools = set() # --enable-X
    disabled_tools = set() # --disable-X

    Options.options.disable_pib = True

    for subdir in conf.path.ant_glob('*', dir=True, src=False):
        tool = subdir.path_from(conf.path)
        all_tools.add(tool)

        is_enabled = getattr(Options.options, 'enable_%s' % tool)
        is_disabled = getattr(Options.options, 'disable_%s' % tool)

        if is_enabled and is_disabled:
            conf.fatal("--enable-%s and --disable-%s cannot be both specified" % (tool, tool))

        if is_enabled:
            enabled_tools.add(tool)

        if is_disabled:
            disabled_tools.add(tool)

    if len(enabled_tools) == 0:
        conf.env['BUILD_TOOLS'] = list(all_tools - disabled_tools)
    else:
        conf.env['BUILD_TOOLS'] = list(enabled_tools)

    for tool in conf.env['BUILD_TOOLS']:
        conf.recurse(tool, mandatory=False)

def build(bld):
    for tool in bld.env['BUILD_TOOLS']:
        bld.recurse(tool)
