get_offset = 0x80

header = [[
// THIS FILE IS AUTOGENERATED //
// DO NOT EDIT THIS MANUALLY //

#pragma once
#include "../lib/l_ii_mod.h"

]]

--- comment to find modules
-- %s[1]: name of module
box_header = '//////////////////////////////\n// %s\n'

--- struct of ii commands per module
-- %s[1]: name of module
-- %s[2]: comma-separated table of cmd,name pairs
command_list_fs = 'static const ii_mod_cmds_t ii_mod_%s_cmds[] = {\n%s\n};\n'
-- %i[1]: uint8_t of command
-- %s[2]: string name of command
command_fs = '    {.cmd = %i, .name = "%s"}'

--- struct boxing a complete module
-- %s[1]: name of module
-- %i[2]: default address of module
-- %s[3]: name of module
-- %s[4]: comma-separated list of possible addresses
-- %s[5]: name of module
-- %i[6]: number of elements in cmd list
box_fs = 'static ii_box_t ii_box_%s = {\n'
      .. '    .addr          = %i,\n'
      .. '    .name          = "%s",\n'
      .. '    .addresses     = {%s},\n'
      .. '    .commands      = ii_mod_%s_cmds,\n'
      .. '    .command_count = %i\n'
      .. '};\n'

function insert_commands(cmds_table, commands)
    if(commands) then
        for _,t in pairs(commands) do
            table.insert(cmds_table, string.format(command_fs, t.cmd, t.name))
        end
    end
    return cmds_table
end
function insert_autogetters(cmds_table, commands)
    if(commands) then
        for _,t in pairs(commands) do
            if t.get then
                table.insert(cmds_table, string.format(command_fs, t.cmd + get_offset, t.name))
            end
        end
    end
    return cmds_table
end

function addresses_table(addrs)
    if type(addrs) == 'number' then
        addrs = {addrs}
    end
    return addrs[1], table.concat(addrs,',')
end

function make_module(f)
    local modheader = string.format(box_header, f.module_name)

    local cmds = {}
    cmds = insert_commands({}, f.commands)
    cmds = insert_autogetters(cmds, f.commands)
    cmds = insert_commands(cmds, f.getters)
    local cmdlist = string.format(command_list_fs, f.lua_name, table.concat(cmds, ',\n'))

    local def_addr, addrs = addresses_table(f.i2c_address)
    local box = string.format(box_fs, f.lua_name, def_addr, f.lua_name, addrs, f.lua_name, #cmds)

    return modheader
        .. cmdlist
        .. box
end

function make_all_modules(files)
    -- just one file for now
    local mod_t = {}
    for _,f in ipairs(files) do
        table.insert(mod_t, make_module(f))
    end
    return table.concat(mod_t, '\n')
end

-------------------------------------------------------
--- container for all modules for iterating across all

-- comment to find modules
lookup_header = '//////////////////////////////\n// list of all module structs\n'

-- %s[1]: comma-separated list of &ii_box refs
lookup_fs = 'static ii_box_t* ii_mods[] = {\n%s\n};\n'

-- %i[1]: number of modules
lookup_len_fs = 'static int ii_mod_count = %i;\n'

function module_lookup(files)
    -- just one file for now
    local mod_t = {}
    for _,f in ipairs(files) do
        table.insert(mod_t, string.format('    &ii_box_%s', f.lua_name))
    end
    str = table.concat(mod_t, ',\n')
    return lookup_header
        .. string.format(lookup_fs, str)
        .. string.format(lookup_len_fs, #files)
end

function make_c(files)
    return header
        .. make_all_modules(files)
        .. '\n'
        .. module_lookup(files)
end


-------------------------------------------------------
--- process input directory & generate file
-- if no destination, then prints to console
-- writes to destination file otherwise


local in_file_dir = arg[1]
local out_file = arg[2]

do
    local dir = io.popen('/bin/ls ' .. in_file_dir)
    local files = {}
    for filename in dir:lines() do
        table.insert(files, dofile('lua/ii/' .. filename))
    end

    if arg[2] then
        local c = io.open( out_file, 'w' )
        c:write(make_c(files))
        c:close()
    else -- debug mode: print to console
        print(make_c(files))
    end
end

-- example usage:
-- lua util/ii_mod_gen.lua lua/ii/ build/ii_mod_gen.h
