#!/usr/bin/env python3

from taiseilib.common import (
    run_main,
    update_text_file,
    add_common_args,
)

import re


meson_template = '''# @overwrite

# @begin header
# @end header

glsl_files = [
# @begin glsl
# @end glsl
]

subdirs = [
# @begin subdirs
# @end subdirs
]

# @begin validate
# @end validate

foreach sd : subdirs
    subdir(sd)
endforeach
'''

header = '''#
# Text inside @begin/@end blocks is autogenerated by scripts/upkeep/update-glsl-sources.py.
# If this file starts with an @overwrite directive, then its entire contents are managed by the script.
#'''

validation_code = '''if validate_glsl
    foreach fname : glsl_files
        stage = fname.split('.')[-2]

        spirv = custom_target(
            input : fname,
            output : '@BASENAME@.spv',
            command : [
                glslc_command, glslc_args, glslc_depfile_args, get_variable(f'glslc_@stage@_args'),
                '@INPUT@', '-o', '@OUTPUT@'
            ],
            install : false,
            build_by_default : true,
            depfile : f'@fname@.d',
        )

        spirv_targets += spirv

        if transpile_glsl
            essl = custom_target(
                input : spirv,
                output : '@BASENAME@.glsl',
                command : [
                    spvc_command,
                    '--output', '@OUTPUT@', '@INPUT@',
                    spvc_args,
                    get_variable(f'spvc_@stage@_args'),
                ],
                install : false,
                build_by_default : true,
                depfile : f'@fname@.d',
            )

            essl_targets += essl
        endif
    endforeach
endif'''


def make_re(token):
    return re.compile(
        r'(.*?# @begin {0}\s*?\n)(.*?)(# @end {0}\s*?\n.*)'.format(token),
        re.DOTALL | re.MULTILINE
    )


re_glsl = make_re('glsl')
re_subdirs = make_re('subdirs')
re_validate = make_re('validate')
re_header = make_re('header')


def update(args, shaders_root):
    subdir_map = {}

    for dir in sorted(shaders_root.glob('**/'), reverse=True):
        glsl_files = tuple(dir.glob('*.glsl'))

        try:
            subdirs = subdir_map[dir]
        except KeyError:
            subdirs = []

        if glsl_files:
            d = dir

            while d.resolve() != shaders_root.resolve():
                try:
                    subdir_map[d.parent].append(d)
                except KeyError:
                    subdir_map[d.parent] = [d]

                d = d.parent

        if glsl_files or subdirs:
            subdirs = tuple(sd.relative_to(dir) for sd in subdirs)
            glsl_files = tuple(f.relative_to(dir) for f in glsl_files)

            try:
                meson_text = (dir / 'meson.build').read_text()

                if meson_text.strip().startswith('# @overwrite'):
                    meson_text = meson_template
            except FileNotFoundError:
                meson_text = meson_template

            glsl_filelist = '\n'.join(sorted("    '{!s}',".format(f) for f in glsl_files) + [''])
            meson_text = re_glsl.sub(r'\1{}\3'.format(glsl_filelist), meson_text)

            subdirs_list = '\n'.join(sorted("    '{!s}',".format(sd) for sd in subdirs) + [''])
            meson_text = re_subdirs.sub(r'\1{}\3'.format(subdirs_list), meson_text)

            meson_text = re_validate.sub(r'\1{}\n\3'.format(validation_code), meson_text)
            meson_text = re_header.sub(r'\1{}\n\3'.format(header), meson_text)

            update_text_file(dir / 'meson.build', meson_text)


def main(args):
    import argparse
    parser = argparse.ArgumentParser(description='Update build defintions to include all GLSL files.', prog=args[0])
    add_common_args(parser)

    args = parser.parse_args(args[1:])

    for shaders_root in (args.rootdir / 'resources').glob('*/shader'):
        update(args, shaders_root)


if __name__ == '__main__':
    run_main(main)
