import getopt
import os
import re
import sys
from meson2python import meson2python
from jinja2 import Environment, FileSystemLoader
from pathlib import Path

environment = Environment(
    loader=FileSystemLoader(Path(__file__).parent.resolve() / 'templates/')
)
generator_template = environment.get_template('generate_python_build.txt')


# Converts the given |file_name| from meson to python, and writes the python code
# to the given |file|.  Code is indented by |output_indent|.  When a subdir command
# is found, the meson.build build in that subdir is converted by recursively invoking
# this function.
def process_meson(file_name: str, output_indent: str = ''):
    python_code = ''
    python_code += (
        output_indent
        + '########################################################################################################################'
    )
    python_code += '\n' + output_indent + f'### Begin conversion from: {file_name}'
    python_code += (
        '\n'
        + output_indent
        + '########################################################################################################################'
    )

    print('Processing: ' + file_name)
    sys.stdout.flush()

    content = meson2python(file_name)
    inside_literal = False

    for line in content.splitlines():
        # Remove line terminator
        line = line.rstrip()

        # Check for multiline literals.
        # We ignore literals that start and end on one line, though that may cause
        # problems for the line processing below.
        matches = re.findall(r"'''", line)

        literal_delimiter_count = len(matches)

        line_prefix = ''
        line_suffix = ''
        if literal_delimiter_count == 1:
            inside_literal = not inside_literal
            literal_line_split = line.split(r"'''")
            if inside_literal:
                line = literal_line_split[0]
                line_suffix = r"'''" + literal_line_split[1]
            else:
                line_prefix = literal_line_split[0] + r"'''"
                line = literal_line_split[1]
        elif literal_delimiter_count == 0 or literal_delimiter_count == 2:
            if inside_literal:
                # Don't match anything while inside literal
                line_prefix = line
                line = ''
        else:
            exit('Unhandled literal in line: ' + line)

        # Recurse into subdirs
        match = re.match("( *)subdir\('([a-zA-Z0-9_\-/]+)'\)", line)
        if match is not None:
            subdir_output_indent = match.group(1) + output_indent
            current_dir = os.path.dirname(file_name)
            next_dir = os.path.join(current_dir, match.group(2))
            next_file = os.path.join(next_dir, 'meson.build')
            # Ensure the build definitions are aware of the changing directory
            python_code += f"\n{subdir_output_indent}set_relative_dir('{next_dir}')"
            python_code += '\n' + process_meson(next_file, subdir_output_indent)
            python_code += f"\n{subdir_output_indent}set_relative_dir('{current_dir}')"
            continue

        python_code += f'\n{output_indent + line_prefix + line + line_suffix}'
    python_code += (
        '\n'
        + output_indent
        + '########################################################################################################################'
    )
    python_code += '\n' + output_indent + f'### End conversion from: {file_name}'
    python_code += (
        '\n'
        + output_indent
        + '########################################################################################################################'
    )
    return python_code


def generate(target: str):
    if not (target == 'android' or target == 'fuchsia'):
        exit('Target must be android or fuchsia')

    output_file_name = 'generate_%s_build.py' % target
    print('Writing to: ' + output_file_name)

    meson_options = process_meson('meson_options.txt')
    meson_build = process_meson('meson.build')
    content = generator_template.render(
        meson_options=meson_options,
        meson_build=meson_build,
    )
    with open(output_file_name, 'w') as file:
        file.write(content)


def usage():
    print('Usage: -t [android|fuchsia]')
    sys.exit()


def main(argv):
    target = 'android'
    try:
        opts, args = getopt.getopt(
            argv,
            'ht:',
            [
                'help',
                'target=',
            ],
        )
        for opt, arg in opts:
            if opt in ('-h', '--help'):
                usage()
            elif opt in ('-t', '--target'):
                target = arg
    except getopt.GetoptError as _:
        usage()

    generate(target)


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