#!/usr/bin/env python3
#
# Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#
# Little script to build a header file including every other header file in the SDK!
# (also checks we don't have "conflicting" header-filenames)
# Edit the IGNORE_DIRS variable to filter out which directories get looked in.
#
# Usage:
#
# tools/build_all_headers.py <root of source tree> <output file>


import os
import sys

IGNORE_DIRS = set(['host', 'boards'])
IGNORE_DIRS.add('common/boot_picoboot')
IGNORE_DIRS.add('common/boot_uf2')
IGNORE_DIRS.add('common/pico_usb_reset_interface')
IGNORE_DIRS.add('rp2_common/cmsis')
IGNORE_DIRS.add('rp2_common/pico_async_context')
IGNORE_DIRS.add('rp2_common/pico_btstack')
#IGNORE_DIRS.add('rp2_common/pico_cyw43_arch')
IGNORE_DIRS.add('rp2_common/pico_cyw43_driver')
IGNORE_DIRS.add('rp2_common/pico_lwip')
IGNORE_DIRS.add('rp2_common/pico_stdio_semihosting')
IGNORE_DIRS.add('rp2_common/pico_stdio_usb')
IGNORE_DIRS.add('rp2_common/pico_clib_interface')
IGNORE_DIRS.add('rp2_common/pico_mbedtls')

SORT_HEADERS_BY_DIRECTORY = True # if False, sort by filename

if len(sys.argv) != 3:
    print("Usage: {} top_dir output_header".format(os.path.basename(sys.argv[0])))
    sys.exit(1)

top_dir = os.path.join(sys.argv[1], 'src')
output_header = sys.argv[2]

if not os.path.isdir(top_dir):
    print("{} doesn't exist!".format(top_dir))
    sys.exit(1)

include_dirs = set()
for root, dirs, files in os.walk(top_dir):
    prune_dirs = []
    for d in dirs:
        if os.path.relpath(os.path.join(root, d), top_dir) in IGNORE_DIRS:
            prune_dirs.append(d)
    for d in prune_dirs:
        dirs.remove(d)

    if 'include' in dirs:
        include_dirs.add(os.path.join(root, 'include'))
        dirs.remove('include')

include_files_by_chip = {
    'none': list(),
    'rp2040': list(),
    'rp2350': list(),
}
all_include_files = set()
include_locations = dict()
for d in sorted(include_dirs):
    for root, dirs, files in os.walk(d):
        for f in sorted(files):
            if f.endswith('.h'):
                include_file = os.path.relpath(os.path.join(root, f), d)
                include_path = os.path.relpath(d, top_dir)
                if 'rp2040/' in include_path:
                    include_files_by_chip['rp2040'].append(include_file)
                elif 'rp2350/' in include_path:
                    include_files_by_chip['rp2350'].append(include_file)
                else:
                    if include_file in include_files_by_chip['none']:
                        raise Exception("Duplicate include file '{}' (found in both {} and {})".format(include_file, include_locations[include_file], include_path))
                    include_files_by_chip['none'].append(include_file)
                include_locations[include_file] = include_path
                all_include_files.add(include_file)

# figure out which includes are applicable to both chips
include_files_by_chip['both'] = []
for f in include_files_by_chip['rp2040']:
    if f in include_files_by_chip['rp2350']:
        include_files_by_chip['both'].append(f)
        include_locations[f] = include_locations[f].replace('rp2350/', 'rp2xxx/')
for f in include_files_by_chip['both']:
    include_files_by_chip['rp2040'].remove(f)
    include_files_by_chip['rp2350'].remove(f)

if SORT_HEADERS_BY_DIRECTORY:
    with open(output_header, 'w') as fh:
        fh.write('''/*
 * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

// This file is autogenerated, do not edit by hand

''')
        last_location = ''
        for f in include_files_by_chip['none']:
            if include_locations[f] != last_location:
                fh.write('\n// {}\n'.format(include_locations[f]))
            fh.write('#include "{}"\n'.format(f))
            last_location = include_locations[f]
        for f in include_files_by_chip['both']:
            if include_locations[f] != last_location:
                fh.write('\n// {}\n'.format(include_locations[f]))
            fh.write('#include "{}"\n'.format(f))
            last_location = include_locations[f]
        if include_files_by_chip['rp2040']:
            fh.write('\n#if PICO_RP2040\n')
            for f in include_files_by_chip['rp2040']:
                if include_locations[f] != last_location:
                    fh.write('\n// {}\n'.format(include_locations[f]))
                fh.write('#include "{}"\n'.format(f))
                last_location = include_locations[f]
            fh.write('\n#endif\n')
        if include_files_by_chip['rp2350']:
            fh.write('\n#if PICO_RP2350\n')
            for f in include_files_by_chip['rp2350']:
                if include_locations[f] != last_location:
                    fh.write('\n// {}\n'.format(include_locations[f]))
                fh.write('#include "{}"\n'.format(f))
                last_location = include_locations[f]
            fh.write('\n#endif\n')
        fh.write('\n')
else:
    with open(output_header, 'w') as fh:
        fh.write('''/*
 * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

// This file is autogenerated, do not edit by hand

''')
        last_define = None
        for f in sorted(all_include_files, key=lambda x: os.path.split(x)):
            if f in include_files_by_chip['rp2040']:
                define = 'PICO_RP2040'
            elif f in include_files_by_chip['rp2350']:
                define = 'PICO_RP2350'
            else:
                define = None
            if define != last_define:
                if last_define is not None:
                    fh.write('#endif\n')
                if define is not None:
                    fh.write('#if {}\n'.format(define))
            fh.write('#include "{}"\n'.format(f))
            last_define = define
        if last_define is not None:
            fh.write('#endif\n')
        fh.write('\n')

