import click
import os

def preprocess(path):
    header = "/*\n* Generated by icc\n* https://github.com/voxelstack/icc\n*/\n"
    return "{}\n{}".format(header, "".join(preprocess_source(path)["source"]))

def preprocess_source(path, cache={}, included=[]):
    if path in cache.values():
        return cache[path]
    
    with open(path, "r") as f:
        source = iter(f.readlines())
        preprocessed_source = []
        pragma_once = False
        last_line_empty = False

        line = next(source, None)
        while line is not None:
            trimmed = line.lstrip()

            if trimmed.startswith("#pragma"):
                pragma = trimmed[len("#pragma"):].lstrip()
                if pragma.startswith("once"):
                    pragma_once = True
                elif pragma.startswith("icc"):
                    pragma_icc = pragma[len("icc"):].lstrip()
                    if pragma_icc.startswith("include"):
                            while True:
                                line = next(source, None).lstrip()
                                if line is None or not line.startswith("#include"):
                                    if line.startswith("#pragma icc end"):
                                        break
                                    
                                    click.echo("Invalid icc include block. Expecting #include or #pragma icc end.", err=True)
                                    exit(1)

                                include_file = line[len("#include"):].strip()[1:-1]
                                include_path = os.path.join(os.getcwd(), "include", include_file)
                                include = preprocess_source(include_path, cache, included)
                                if not include["once"] or include_path not in included:
                                    preprocessed_source.append("// BEGIN {}\n".format(include_file))
                                    preprocessed_source.extend(include["source"])
                                    preprocessed_source.append("// END {}\n".format(include_file))
                                    
                                    included.append(include_path)
                    else:
                        click.echo("Unknown pragma {}.".format(line))
                line = next(source, None)
                continue

            current_line_empty = len(trimmed) == 0
            # Since we are ommiting some lines when generating the submission,
            # it's common to have double line breaks which look bad.
            # Skip them.
            if not (last_line_empty and current_line_empty):
                preprocessed_source.append(line)
            last_line_empty = current_line_empty

            line = next(source, None)

    source = {
        "source": preprocessed_source,
        "once": pragma_once,
    }
    cache[path] = source
    
    return source
