-- Script to automatically import object positions from kmp.txt files generated from MkWii
-- TODO: Quickly hacked together, don't include in final map
-- Author: stefan750

local M = {}

local columnWidths = {5, 7, 12, 12, 12, 7, 7, 7, 7, 8}

-- split with fixed column widths and strip whitespace
local function splitFixed(str)
    local t = {}
    local offset = 1
    for i, w in ipairs(columnWidths) do
        t[i] = str:sub(offset, offset + w - 1):match("^%s*(.-)%s*$")
        offset = offset + w
    end

    return t
end

-- split with whitespace
local function split(str)
    local t = {}
    for i, f in string.gmatch(str, "^%s+") do
        t[i] = f
    end

    return t
end

-- filePath: kmp.txt file to import from
-- id: MkWii object id to import
-- name: name prefix for finding existing map objects
-- shape: shape model that should be spawned
-- posMul: position scale from MkWii units to Beam units
-- scaleMul: object scale multiplier
-- posOffset: offset position in world space
--
-- example: kmpImport.spawnObjects("course.kmp.txt", "0x145", "PalmTree", "/levels/coconutmall/art/shapes/palmtree/PalmTree.dae", 0.005, 0.5, vec3(0,0,100))
local function spawnObjects(filePath, id, name, shape, posMul, scaleMul, posOffset)
    local file, err = io.open(filePath, "r")
    if not file then return err end

    local i = 0
    local obj
    for line in file:lines() do
        -- skip empty lines and comments
        if #line > 0 and not line:match("^%s*#") then
            local fields = splitFixed(line)
            
            -- match first object data line (name and position)
            if fields[1]:match("^o") and fields[2] == id then
                i = 1

                --dump(fields)

                local shapeName = shape

                -- special handling for coconut mall car colors
                if id == "aaaa" and not shape:match("%.dae") then
                    local rand = math.random(0,2)
                    shapeName = shape .. (rand > 0 and rand or "") .. ".dae"
                end

                -- special handling for dark and regular red mushrooms
                if id == "0x1f6" or id == "0x1f5" and not shape:match("%.dae") then
                    shapeName = shape ..  (fields[6] ~= "0" and "_d" or "") .. "_r.dae"
                end

                -- special handling for dark and regular green mushrooms
                if id == "0x1fa" and not shape:match("%.dae") then
                    shapeName = shape ..  (fields[6] ~= "0" and "_d" or "") .. "_g.dae"
                end

                -- get object from scenetree or create a new one
                local objName = name.."_"..fields[1]
                obj = scenetree[objName]
                
                if not obj then
                    obj = createObject("TSStatic")
                    obj:setField("shapeName", 0, shapeName)
                    obj:registerObject(objName)

                    if editor and editor.onAddSceneTreeObjects then
                        editor.onAddSceneTreeObjects({obj:getId()})
                    end
                end
                
                -- update object data
                obj:setField("shapeName", 0, shapeName)
                obj:setField("collisionType", 0, "Collision Mesh")
                obj.canSave = true

                local pos = vec3(tonumber(fields[3]), -tonumber(fields[5]), tonumber(fields[4]))*posMul + posOffset
                local rot = quat()
                obj:setPosRot(pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, rot.w)
                
                goto continue
            end

            -- match second object data line (rotation)
            if i == 1 and fields[1] == ">" then
                i = 2

                local pos = obj:getPosition()
                local rot = quatFromEuler(tonumber(fields[3]) * (math.pi / 180), tonumber(fields[5]) * (math.pi / 180), -tonumber(fields[4]) * (math.pi / 180))
                obj:setPosRot(pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, rot.w)
                goto continue
            end

            -- match third object data line (scale)
            if i == 2 and fields[1] == ">" then
                i = 0

                obj:setScale(vec3(tonumber(fields[3]), tonumber(fields[5]), tonumber(fields[4]))*scaleMul)
                goto continue
            end
        end
        ::continue::
    end

    file:close()
end

M.spawnObjects = spawnObjects

return M