#!/usr/bin/env python3
import fileinput
import os
import re
import sys

btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/../../')

defines_to_add = []
defines_to_remove = []

# dictionary with existing lines as keys, and new text as value
lines_to_replace = {}

def get_line_ending(full_path):
    with open(full_path, "r", newline='') as fin:
        line = fin.readline()
        if line.endswith('\r\n'):
            return '\r\n'
        if line.endswith('\r'):
            return '\r'
        return '\n'


def configuration_from_block(block, line_ending):
    global defines_to_add, defines_to_remove
    configuration = ""
    
    if len(block) == 0:
        return ""

    for item in defines_to_remove:
        if item in block:
            block.remove(item)

    defines_processed = []
    for item in temp_defines_to_add:
        if item in block:
            defines_processed.append(item)
            continue

        if len(block) > 0:
            prefix = block[0].split("_")[0]
            if item.startswith(prefix):
                block.append(item)
                defines_processed.append(item)

    for item in defines_processed:
        temp_defines_to_add.remove(item)

    block.sort()
    for item in block:
        configuration += ("#define %s%s" % (item, line_ending))

    configuration += ("%s" % (line_ending))
    return configuration

def read_and_update_configuration(full_path, line_ending):
    global lines_to_replace, temp_defines_to_add

    configuration = ""
    block = []
    temp_defines_to_add = defines_to_add.copy()

    with open(full_path, "rt") as fin:
        for unstripped_line in fin:
            line = unstripped_line.strip()

            if not line:
                if len(block) == 0:
                    # we have newline to deal with
                    configuration += line_ending
                else:
                    configuration += configuration_from_block(block, line_ending)
                block = []
            else:
                if line in lines_to_replace.keys():
                    configuration += ("%s%s" % (lines_to_replace[line], line_ending))
                    continue

                parts = re.match("#define\\s*(.*)", line)
                if parts:
                    block.append(parts[1])
                else:
                    # if commented code follows directly block, process block, and start a new one
                    configuration += configuration_from_block(block, line_ending)
                    block = []
                    configuration += ("%s%s" % (line, line_ending))
    
    if len(temp_defines_to_add) > 0:
        print("Cannot add defines: \n- " + "\n- ".join(temp_defines_to_add))
        print("ABORT")
        sys.exit(10)

    # if end of file could not be detected, process last block
    configuration += configuration_from_block(block, line_ending)
    return configuration

def write_configuration(full_path, config_file):
    with open(full_path, "wb") as fout:
        bytes = configuration.encode('utf-8')
        fout.write(bytes)


for root, dirs, files in os.walk(btstack_root, topdown=True):
    for f in files:
        if f.endswith("btstack_config.h"):
            config_file = root + "/" + f
            line_ending = get_line_ending(config_file)
            configuration = read_and_update_configuration(config_file, line_ending)
            write_configuration(config_file, configuration)