inp = """
CIMGUI_API ImVec2* igImVec2_ImVec2_Nil(const char* x);
CIMGUI_API void ImVec2_destroy(ImVec2* self);
CIMGUI_API ImVec2* ImVec2_ImVec2_Float(float _x,float _y);
CIMGUI_API ImVec4* ImVec4_ImVec4_Nil(void);
CIMGUI_API void ImVec4_destroy(ImVec4* self);
CIMGUI_API ImVec4* ImVec4_ImVec4_Float(float _x,float _y,float _z,float _w);
CIMGUI_API ImGuiContext* igCreateContext(ImFontAtlas* shared_font_atlas);
CIMGUI_API void igDestroyContext(ImGuiContext* ctx);
CIMGUI_API ImGuiContext* igGetCurrentContext(void);
CIMGUI_API void igSetCurrentContext(ImGuiContext* ctx);
CIMGUI_API ImGuiIO* igGetIO(void);
CIMGUI_API ImGuiStyle* igGetStyle(void);
CIMGUI_API void igNewFrame(void);
CIMGUI_API void igEndFrame(void);
CIMGUI_API void igRender(void);
CIMGUI_API ImDrawData* igGetDrawData(void);
CIMGUI_API void igShowDemoWindow(bool* p_open);
"""


singletonList = [
    'getStyle',
    'getIO',
    'getCurrentContext',
    'getMainViewport',
]

bitcastList = [
    "Vec2",
    "Vec4",
    "Cond",
    "WindowFlags",
    "DockNodeFlags",
    "ConstCharPtrVector",
    "CharVector",
    "WcharVector",
    "InputTextFlags",
    "TreeNodeFlags",
    "PopupFlags",
    "SelectableFlags",
    "ComboFlags",
    "TabBarFlags",
    "TabItemFlags",
    "TableColumnFlags",
    "TableFlags",
    "TableRowFlags",
    "TableBgTarget",
    "FocusedFlags",
    "HoveredFlags",
    "DragDropFlags",
    "DockNodeFlags",
    "ModFlags",
    "ConfigFlags",
    "BackendFlags",
    "ColorEditFlags",
    "SliderFlags",
    "Cond",
    "Style",
    "KeyData",
    "FontAtlas",
    "FontAtlasCustomRect",
    "FontConfig",
    "Io",
    "Viewport",
    "PlatformMonitorVector",
    "ViewportPtrVector",
    "PlatformIO",
    "PlatformMonitor",
    "ViewportFlags",
    "DrawFlags",
    "DrawListFlags",
    "FontAtlasFlags",
    "PlatformImeData",
    "StbUndoRecord",
    "StbUndoState",
    "StbTexteditState",
    "StbTexteditRow",
    "Vec1",
    "Rect",
    "BitVector",
    "Vec2ih",
    "DrawListSharedData",
    "DrawListPtrVector",
    "DrawList",
    "DrawDataBuilder",
    "ItemFlags",
    "ItemStatusFlags",
    "SeparatorFlags",
    "TextFlags",
    "TooltipFlags",
    "NextWindowDataFlags",
    "NextItemDataFlags",
    "ActivateFlags",
    "ScrollFlags",
    "NavHighlightFlags",
    "NavDirSourceFlags",
    "NavMoveFlags",
    "OldColumnFlags",
    "DebugLogFlags",
    "DataTypeTempStorage",
    "DataTypeInfo",
    "ColorMod",
    "StyleMod",
    "ComboPreviewData",
    "GroupData",
    "MenuColumns",
    "InputTextState",
    "PopupData",
    "NextWindowData",
    "NextItemData",
    "LastItemData",
    "StackSizes",
    "WindowStackData",
    "PtrOrIndex",
    "BitArrayForNamedKeys",
    "InputEventMousePos",
    "InputEventMouseWheel",
    "InputEventMouseButton",
    "InputEventMouseViewport",
    "InputEventKey",
    "InputEventText",
    "InputEventAppFocused",
    "InputEvent",
    "ListClipperRange",
    "ListClipperData",
    "ListClipperRangeVector",
    "NavItemData",
    "OldColumnData",
    "OldColumnDataVector",
    "WindowPtrVector",
    "WindowDockStyle",
    "DockRequestVector",
    "DockNodeSettingsVector",
    "DockContext",
    "ViewportP",
    "WindowSettings",
    "SettingsHandler",
    "MetricsConfig",
    "StackLevelInfoVector",
    "StackTool",
    "ContextHook",
    "InputEventVector",
    "WindowStackDataVector",
    "ColorModVector",
    "StyleModVector",
    "IDVector",
    "ItemFlagsVector",
    "GroupDataVector",
    "PopupDataVector",
    "ViewportPPtrVector",
    "ListClipperDataVector",
    "TableTempDataVector",
    "TableVector",
    "TabBarVector",
    "PtrOrIndexVector",
    "ShrinkWidthItemVector",
    "ShrinkWidthItem",
    "SettingsHandlerVector",
    "ContextHookVector",
    "u8Vector",
    "TablePool",
    "TabBarPool",
    "TabItemVector",
    "WindowSettingsChunkStream",
    "TableSettingsChunkStream",
    "TabItem",
    "TabBar",
    "TableTempData",
    "TableSettings",
    "FontBuilderIO",
    "TableCellData",
    "TableInstanceData",
    "TableColumnSpan",
    "TableColumnIdxSpan",
    "TableCellDataSpan",
    "TableInstanceDataVector",
    "TableColumnSortSpecsVector",
    "TextBuffer",
    "Context",
    "DrawChannelVector",
    "DrawChannel",
    "DrawCmdVector",
    "DrawIdxVector",
    "f32Vector",
    "FontPtrVector",
    "Payload",
    "ListClipper",
    "Storage",
    "StoragePairVector",
    "WindowClass",
    "InputTextCallbackData",
    "SizeCallbackData",
    "DrawData",
    "FontGlyphVector",
    "Font",
    "DrawCmd",
    "DrawVert",
    "DrawCmdHeader",
    "DrawListSplitter",
]


ptrcastList = [
    "WindowClass"
]

enumcastList = [
    "StyleVar",
    "DataType",
    "DataTypePrivate",
    "NavLayer",
    "DataAuthority",
    "DockNodeState",
    "WindowDockStyleCol",
    "ContextHookType",
    "Dir",
    "NavInput",
    "LayoutType",
    "LogType",
    "Axis",
    "PlotType",
    "PopupPositionPolicy",
    "MouseButton",
    "MouseCursor",
    "SortDirection",
    "Key",
    "StyleColor",
    "KeyPrivate",
    "InputSource",
    "NavReadMode",
    "InputEventType",
]

with open('functions.txt') as f:
    inp = f.read()
    pass

def splitTypeAndLabel(line):
    if ' ' in line:
        spaceIndex = line.rindex(' ')
        left = line[:spaceIndex]
        right = line[spaceIndex + 1:]
        return left, right
    else:
        return line, ''

def convertInner(typeName):
    if 'size_t' == typeName:
        return 'usize'
    if 'double' == typeName:
        return 'f64'
    if 'float' == typeName:
        return 'f32'
    if 'char' == typeName:
        return 'u8'
    if 'int' == typeName:
        return 'c_int'
    if 'short' == typeName:
        return 'c_short'
    if 'unsigned char' == typeName:
        return 'u8'
    if 'unsigned int' == typeName:
        return 'c_uint'
    if 'unsigned short' == typeName:
        return 'c_ushort'
    if 'unsigned long' == typeName:
        return 'c_ulong'
    if 'long' == typeName:
        return 'c_long'
    if 'longlong' == typeName:
        return 'c_longlong'
    if 'ImGui' == typeName[0:5]:
        return typeName[5:]
    if 'Im' == typeName[0:2]:
        return typeName[2:]
    return typeName

def parseFuncName(line):
    line = line.strip(' \n;')
    line = line.replace(')', '')
    s = line.split('(')
    funcName = s[1].strip('* ')
    return funcName

def parseFunction(line):
    line = line.strip(' \n;')
    line = line.replace(')', '')
    s = line.split('(')
    returnType = convertTypeName(s[0].strip(' '))
    funcName = convertVarName(s[1].strip('* '))
    funcName = funcName.replace('__', '_')
    argsRaw = s[2].split(',')
    args = []
    for a in argsRaw:
        if len(a) >= 1:
            args.append(a)

    argList = []
    for a in args:
        a = a.strip(' ')
        tname, vname = splitTypeAndLabel(a)
        argList.append([convertTypeName(tname), convertVarName(vname)])

    return (returnType, funcName, argList)

def convertFuncName(funcName):
    returnType, funcName, argList = parseFunction(line)
    ostr = funcName + ': *const fn ('
    first = True
    for arg in argList:
        if first:
            first = False
        else:
            ostr += ', '
        ostr += arg[0]
    ostr += ') ' + returnType + ','
    return ostr

def convertVarName(name):
    ostr = ""
    first = True
    for c in name:
        if c.isupper():
            if first:
                first = False
            else:
                ostr += '_'
        ostr += c.lower()
    return ostr

def convertTypeName(entry):
    if 'void*' == entry:
        return '?*anyopaque'
    if 'void' == entry:
        return 'void'
    if 'size_t' == entry:
        return 'c_usize'

    # print('---')
    # print(entry)
    entry = entry.strip(' ')
    isVector = False
    if entry[:8] == 'ImVector':
        isVector = True

    typeName = entry
    const = False
    pointer = False
    if '*' in typeName:
        pointer = True;
        typeName = typeName.strip('*')

    # print('\'' + typeName[:5] + '\'')
    if typeName[:5] == 'const':
        const = True
        typeName = typeName[5:]
        typeName = typeName.strip(' ')
    # print(typeName)


    if '_' in typeName:
        x = typeName.split('_')
        typeName = x[-1]
    rv = convertInner(typeName)

    if const and pointer:
        rv = 'const ' + rv

    if pointer:
        rv = '[*c]' + rv

    if isVector:
        rv += 'Vector'

    # print(rv)
    return rv


def startswith(line, segment):
    if line[0:len(segment)] == segment:
        return True
    return False

def parseRawArgsList(line):
    argList = []
    windowStart = 0
    braceCount = 0
    for i in range(0, len(line)):
        if line[i] == '(':
            braceCount += 1
            continue
        if line[i] == ')':
            braceCount -= 1
            continue
        if braceCount == 0 and (line[i] == ',' or i == len(line) - 1):
            argList.append((line[windowStart: i + 1]).strip(','))
            windowStart = i
    return argList

def lowerFirst(s):
    if len(s) > 1:
        s = s[0].lower() + s[1:]
    elif len(s) == 1:
        s = s[0].lower()
    return s

funcList = []
for l in inp.split('\n'):
    line = l.strip(' \n;')
    line = line.replace(' *', '* ')

    if len(line) == 0:
        continue

    function = {}
    if startswith(line, 'CIMGUI_API'):
        line = line[len('CIMGUI_API'):].strip(' ')
        s = line[line.index('('):]
        argListRaw = parseRawArgsList(s.strip(' ()'))
        argList = []
        for arg in argListRaw:
            if '(*' in arg:
                paramName =  parseFuncName(arg)
                typeName = arg
                argList.append((typeName, paramName))
            elif ' ' in arg:
                argList.append(( arg[:arg.rindex(' ')].strip(' '), arg[arg.rindex(' '):].strip(' ')))
            else:
                argList.append((arg.strip(' '), None))
        #print(line, '> ', argList)
        function['rawName'] = line[:line.index('(')]
        function['args'] = argList
        rawName = function['rawName']
        function['label'] = rawName[rawName.rindex(' '):].strip(' ')
        function['returnType'] = rawName[:rawName.rindex(' ')].strip(' ')
        # reject any functions that have a variadic
        shouldAdd = True
        for arg in function['args']:
            if '...' in arg[0]:
                shouldAdd = False
        if shouldAdd:
            funcList.append(function)

def wrapCast(arg):
    convertedType = convertTypeName(arg[0])
    return convertedType

for f in funcList:
    if startswith(f['label'], 'ig'):
        ostr = "pub fn "
        label = f['label'][2:]
        ostr += lowerFirst(label)
        ostr += "("
        first = True
        for arg in f['args']:
            if arg[0] == 'void':
                continue
            if first:
                first = False
            else:
                ostr += ', '
            ostr += convertVarName(arg[1]) + ': '
            ostr += convertTypeName(arg[0])

        ostr += ") "
        returnType = convertTypeName(f['returnType'])
        isSingleton = False
        for s in singletonList:
            if s == lowerFirst(label):
                returnType = returnType.replace(r'[*c]', r'?*')
                isSingleton = True
                break
        ostr += returnType
        ostr += " { //" + f['label'] +"\n    "
        if returnType != 'void':
            ostr += 'return '
        if isSingleton:
            ostr += '@ptrCast('
        ostr += "c." + f['label'] + '('
        first = True
        for arg in f['args']:
            if first:
                first = False
            else:
                ostr += ', '

            if arg[0] == 'void':
                continue
            argStr = convertVarName(arg[1])
            def applyCasts(a, t):
                for cast in bitcastList:
                    if t == cast:
                        return '@bitCast(' + a + ')'
                for cast in ptrcastList:
                    if cast in t:
                        return '@ptrCast(' + a + ')'
                for cast in enumcastList:
                    if t == cast:
                        return '@intFromEnum(' + a + ')'
                return a
            argStr = applyCasts(argStr, convertTypeName(arg[0]))
            ostr += argStr
            # print(wrapCast(arg))
        if isSingleton:
            ostr += ')'
        ostr += ');\n'
        # ostr += convertTypeName(arg[0])
        ostr += "}"
        print(ostr)
    else:
        continue
