# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import, print_function, unicode_literals

import argparse
import os
import re
import sys
from buildconfig import topobjdir
from mozbuild.backend.configenvironment import ConfigEnvironment
from mozbuild.util import FileAvoidWrite
import mozpack.path as mozpath


def process_define_file(output, input):
    '''Creates the given config header. A config header is generated by
    taking the corresponding source file and replacing some #define/#undef
    occurences:
        "#undef NAME" is turned into "#define NAME VALUE"
        "#define NAME" is unchanged
        "#define NAME ORIGINAL_VALUE" is turned into "#define NAME VALUE"
        "#undef UNKNOWN_NAME" is turned into "/* #undef UNKNOWN_NAME */"
        Whitespaces are preserved.

    As a special rule, "#undef ALLDEFINES" is turned into "#define NAME
    VALUE" for all the defined variables.
    '''

    path = os.path.abspath(input)

    config = ConfigEnvironment.from_config_status(
        mozpath.join(topobjdir, 'config.status'))

    if mozpath.basedir(path,
                       [mozpath.join(config.topsrcdir, 'js/src')]) and \
            not config.substs.get('JS_STANDALONE'):
        config = ConfigEnvironment.from_config_status(
            mozpath.join(topobjdir, 'js', 'src', 'config.status'))

    with open(path, 'rU') as input:
        r = re.compile('^\s*#\s*(?P<cmd>[a-z]+)(?:\s+(?P<name>\S+)(?:\s+(?P<value>\S+))?)?', re.U)
        for l in input:
            m = r.match(l)
            if m:
                cmd = m.group('cmd')
                name = m.group('name')
                value = m.group('value')
                if name:
                    if name == 'ALLDEFINES':
                        if cmd == 'define':
                            raise Exception(
                                '`#define ALLDEFINES` is not allowed in a '
                                'CONFIGURE_DEFINE_FILE')
                        defines = '\n'.join(sorted(
                            '#define %s %s' % (name, val)
                            for name, val in config.defines.iteritems()
                            if name not in config.non_global_defines))
                        l = l[:m.start('cmd') - 1] \
                            + defines + l[m.end('name'):]
                    elif name in config.defines:
                        if cmd == 'define' and value:
                            l = l[:m.start('value')] \
                                + str(config.defines[name]) \
                                + l[m.end('value'):]
                        elif cmd == 'undef':
                            l = l[:m.start('cmd')] \
                                + 'define' \
                                + l[m.end('cmd'):m.end('name')] \
                                + ' ' \
                                + str(config.defines[name]) \
                                + l[m.end('name'):]
                    elif cmd == 'undef':
                       l = '/* ' + l[:m.end('name')] + ' */' + l[m.end('name'):]

            output.write(l)

    return {path, config.source}


def main(argv):
    parser = argparse.ArgumentParser(
        description='Process define files.')

    parser.add_argument('input', help='Input define file.')

    args = parser.parse_args(argv)

    return process_define_file(sys.stdout, args.input)


if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))
