#! /usr/bin/python3

import fileinput
import sys
import re
import os
from enum import Enum

class Section(Enum):
    PREAMBLE = 1
    EXP_TYPE = 2
    EXP_VALUE = 3
    STATIC = 4
    UNKNOWN = 5

class ValueSubsection(Enum):
    FUNCTION = 1
    VARIABLE = 2
    NA = 3

outfile = sys.argv[1]
outfile_local = os.path.basename(outfile)
parts = re.match(r"(?P<module>.*)\.(?P<mode>[^\.]*)\.[hc]$", outfile_local)
module = parts.group('module')
outtype = parts.group('mode')

srcfile = os.path.join(os.path.dirname(outfile), module) + ".src.c"
circImpVar = "__{mod}_{ty}_IMPORTING__".format(mod=module.upper(), ty=outtype.upper())

sys.stdout = open(outfile, 'w')

# data about the current //#-delimited chunk of file
section = Section.PREAMBLE
valueSubsection = ValueSubsection.NA
lines = []

def declOnly():
    if valueSubsection == ValueSubsection.VARIABLE:
        eqpos = lines[0].find('=')
        lines[0] = lines[0][0:eqpos]
        print( 'extern', lines[0], ';' )
    else:
        if lines[0].endswith("{"):
            lines[0] = lines[0][0:len(lines[0])-2].rstrip()
        print( lines[0], ';' )

def fulldump():
    for line in lines:
        print(line)

def flush():
    global lines
    # print("\t// flush", outtype, section)

    if (section == Section.PREAMBLE):
        postpreamble()
    elif (len(lines) == 0):
        return
    elif (outtype == 'tdcl') & (section == Section.EXP_TYPE):
        declOnly()
    elif (outtype == 'defn') & (section == Section.EXP_TYPE):
        fulldump()
    elif (outtype == 'defn') & (section == Section.EXP_VALUE):
        declOnly()
    elif (outtype == 'impl') & (section == Section.EXP_VALUE):
        fulldump()
    elif (outtype == 'impl') & (section == Section.STATIC):
        fulldump()
    else:
        for line in lines:
            pass #print("//", line)

    lines = []

class ImportStyle(Enum):
    NO_EXPORT = 1
    EXPORT_INCOMPLETE = 2
    EXPORT_COMPLETE = 3

def emitInclude(imodule, iftype):
    print('#include "{mod}.{typ}.h"'.format(mod=imodule, typ=iftype))

def import_(cmd):
    if section == Section.PREAMBLE:
        if cmd.startswith("auto"):
            cmd = cmd.replace("auto","").lstrip()
            if cmd.startswith("&"):
                cmd = cmd.replace("&","").lstrip()
                style = ImportStyle.EXPORT_INCOMPLETE
            else:
                style = ImportStyle.EXPORT_COMPLETE
        elif cmd.startswith("static"):
            cmd = cmd.replace("static","").lstrip()
            style = ImportStyle.NO_EXPORT
        else:
            print("#error import not understood:", cmd)            
            style = ImportStyle.NO_EXPORT
        imodule = cmd
        if( style != ImportStyle.EXPORT_COMPLETE) & (outtype == "impl"):
            emitInclude(imodule, "defn")
        if (style == ImportStyle.EXPORT_COMPLETE) & (outtype == "defn"):
            emitInclude(imodule, "defn")
        if (style != ImportStyle.NO_EXPORT) & (outtype == "tdcl"):
            emitInclude(imodule, outtype)
    else:
        print("#error illegal place for: import ", cmd)

def beginunit():
    print("//", outfile_local)
    if (outtype == "tdcl"):
        print("#pragma once")
    elif outtype == "defn":
        print("#ifdef", circImpVar)
        print("#error Illegal circularity detected")
        print("#else")
        print("#define", circImpVar)
    if outtype == "defn":
        emitInclude(module, "tdcl")
    elif outtype == "impl":
        emitInclude(module, "defn")

def postpreamble():
    if outtype == "defn":
        print("#undef", circImpVar)
        print("#pragma once")



def endunit():
    if outtype == "defn":
        print("#endif // ", circImpVar)

try:
    with open(srcfile, "r") as file:
        beginunit()
        for line in file:
            line = line.rstrip()
            if ( line.startswith("#import") ):
                line = line.replace("#import", "").lstrip()
                import_(line)
            elif ( line.startswith("//#") ):
                flush()
                line = line.replace("//#", "").lstrip()
                if line[0] == '@':
                    section = Section.EXP_TYPE
                    valueSubsection = ValueSubsection.NA
                elif line[0] == '$':
                    section = Section.EXP_VALUE
                    valueSubsection = ValueSubsection.NA
                    # print("\t// object decl:{name}, with deps:{decldeps}".format(
                    #     name=name, decldeps=decldeps))
                    line = line[1:]
                    if line[0] == 'f':
                        valueSubsection = ValueSubsection.FUNCTION
                    elif line[0] == 'v':
                        valueSubsection = ValueSubsection.VARIABLE
                    else:
                        print("#error $-subdirective not understood: ", line)
                        valueSubsection = ValueSubsection.NA
                elif line[0] == '-':
                    section = Section.STATIC
                    valueSubsection = ValueSubsection.NA
                else:
                    print("#error directive not understood:", line)
                    section = Section.UNKNOWN
                    valueSubsection = ValueSubsection.NA
                line = line[1:]
            else:
                line = line.split("//")[0].rstrip()
                if (line):
                    lines.append(line)
        flush()
        endunit()
except FileNotFoundError:
    print("Error: The file '" + srcfile + "' was not found.")


