SplineGenerator = {}

SplineGenerator.defaultFence = {
    placeOnTerrain = false,
    fenceGenerationParentId = 0,
    onlyScaleLastPanel = false,
    panels = {{
        id = 0,
        size = 2,
        weight = 1
    }},
    poles = {{
        id = 0,
        weight = 1
    }},
    specialObjects = {{
        id = 0,
        size = 4,
        offset = 0.5
    }}
}


function SplineGenerator.loadFenceFromSpline(spline)
    local maxAmountOfItems = 10
    local fence = {
        placeOnTerrain = getUserAttribute(spline,"fenceGenerationPlaceOnTerrain") or false,
        fenceGenerationParentId = getUserAttribute(spline,"fenceGenerationParentId") or 0,
        onlyScaleLastPanel = getUserAttribute(spline,"fenceGenerationOnlyScaleLastPanel") or false
    }
    fence.panels = {}
    fence.poles = {}
    fence.specialObjects = {}

    for i=1,maxAmountOfItems do
        local id = getUserAttribute(spline,"fenceGenerationPanelObjectId" .. i)
        local size = getUserAttribute(spline,"fenceGenerationPanelObjectSize" .. i)
        local weight = getUserAttribute(spline,"fenceGenerationPanelObjectWeight" .. i)
        
        if id ~= nil then
            print("Found panel " .. id .. " with size " .. size)
            table.insert(fence.panels, {
                id = id,
                size = size,
                weight = weight
            })
        end
    end

    for i=1,maxAmountOfItems do
        local id = getUserAttribute(spline,"fenceGenerationPoleObjectId" .. i)
        local weight = getUserAttribute(spline,"fenceGenerationPoleObjectWeight" .. i)

        if id ~= nil then
            print("Found pole " .. id)
            table.insert(fence.poles, {
                id = id,
                weight = weight
            })
        end
    end

    for i=1,maxAmountOfItems do
        local id = getUserAttribute(spline,"fenceGenerationSpecialObjectId" .. i)
        local size = getUserAttribute(spline,"fenceGenerationSpecialObjectSize" .. i)
        local offset = getUserAttribute(spline,"fenceGenerationSpecialObjectOffset" .. i)
        if id ~= nil then
            print("Found special object " .. id .. " with size " .. size)
            table.insert(fence.specialObjects, {
                id = id,
                size = size,
                offset = offset
            })
        end
    end
    return fence
end

function SplineGenerator.saveFenceToSpline(spline, fence)
    setUserAttribute(spline,"fenceGenerationPlaceOnTerrain",0,fence.placeOnTerrain or false)
    setUserAttribute(spline,"fenceGenerationParentId",5, fence.fenceGenerationParentId or 0)
    setUserAttribute(spline,"fenceGenerationOnlyScaleLastPanel",0,fence.onlyScaleLastPanel or false)

    for i=1,#fence.panels do
        if fence.panels[i] ~= nil then
            setUserAttribute(spline,"fenceGenerationPanelObjectId" .. i, 5, fence.panels[i].id or 0)
            setUserAttribute(spline,"fenceGenerationPanelObjectSize" .. i, 1, fence.panels[i].size or 2)
            setUserAttribute(spline,"fenceGenerationPanelObjectWeight" .. i, 1, fence.panels[i].weight or 1)
        end
    end

    for i=1,#fence.poles do
        if fence.poles[i] ~= nil then
            setUserAttribute(spline,"fenceGenerationPoleObjectId" .. i, 5, fence.poles[i].id or 0)
            setUserAttribute(spline,"fenceGenerationPoleObjectWeight" .. i, 5, fence.poles[i].weight or 1)
        end
    end

    for i=1,#fence.specialObjects do
        if fence.specialObjects[i] ~= nil then
            setUserAttribute(spline,"fenceGenerationSpecialObjectId" .. i, 5, fence.specialObjects[i].id or 0)
            setUserAttribute(spline,"fenceGenerationSpecialObjectSize" .. i, 1, fence.specialObjects[i].size or 4)
            setUserAttribute(spline,"fenceGenerationSpecialObjectOffset" .. i, 2, fence.specialObjects[i].offset or 0.5)
        end
    end
end

function SplineGenerator.connectPoints(template, startX, startY, startZ, endX, endY, endZ)
    local splinePoints = {endX, endY, endZ,startX, endY, startZ}
    local newSpline = createSplineFromEditPoints(getRootNode(),splinePoints,true,false)
    local rX, rY, rZ = getSplineOrientation(newSpline,0,0,-1,0)
    delete(newSpline)

    local newFence = clone(template,false)
    link(getRootNode(),newFence)
    setWorldRotation(newFence, rX, rY, rZ)
    setWorldTranslation(newFence, startX,startY,startZ)
    return newFence
end

function SplineGenerator.buildFence(spline, fence)
    local spawnedObject = {}
    local fenceLength = fence.panels[1].size
    -- Max amount of panels/poles places
    local amount = 200
    local panelTemplate = fence.panels[1].id
    local poleTemplate = fence.poles[1].id
    local offsetMultiplier = 2

    local mSplineLength = getSplineLength(spline)
    print("Spline length: " .. mSplineLength)
    local fenceLengthTime = 1 / (mSplineLength / fenceLength)
    print("Fence length: " .. fenceLengthTime)
    local splinePos = 0.0


    -- Spawn all Objects
    for i=0,amount do
        if splinePos <= 1.0 and ((splinePos + fenceLengthTime) <= 1.0) then
            local x, y, z = getSplinePosition(spline,splinePos)
            local endX, endY, endZ = getSplinePosition(spline,(splinePos + fenceLengthTime))

            if (panelTemplate ~= nil and panelTemplate ~= 0) then
                local panel = SplineGenerator.connectPoints(panelTemplate, x, y, z, endX, endY, endZ)
                if (offsetMultiplier ~= nil and offsetMultiplier ~= 0) then
                    local heightDifference = (endY - y) * offsetMultiplier
                    local shaderParameterName = "yOffset"
                    local xOffset, yOffset, zOffset, wOffset = 0, 0, 0, 0
                    xOffset = math.atan(heightDifference/fenceLength)
                    setShaderParameterRecursive(panel, shaderParameterName, xOffset, yOffset, zOffset, wOffset, false)
                end
                table.insert(spawnedObject, panel)
            end
            if (poleTemplate ~= nil and poleTemplate ~= 0) then
                local pole = SplineGenerator.connectPoints(poleTemplate, x, y, z, endX, endY, endZ)
                table.insert(spawnedObject, pole)

                if (splinePos + fenceLengthTime) >= 1 then
                    local endPole = SplineGenerator.connectPoints(pole, endX, endY, endZ, x,y,z)
                    table.insert(spawnedObject, endPole)
                    i = amount + 1
                end
            end

            splinePos = splinePos + fenceLengthTime
        end
    end

    -- Move Objects to parent Group
    local parentGroup = createTransformGroup("fence")
    link(getRootNode(),parentGroup)
    setWorldTranslation(parentGroup, getSplinePosition(spline,0))

    for i=1,#spawnedObject do
        local x, y, z = getWorldTranslation(spawnedObject[i])
        link(parentGroup, spawnedObject[i])
        setWorldTranslation(spawnedObject[i], x, y, z)
    end
end

-- SideNote, this script loads and saves all fenceGeneration settings.
-- But doesn't use most of them yet. ex. SpecialObjects aren't implemented just yet.

local node = getSelection(0)
-- 1. Save default settings to selected Spline
SplineGenerator.saveFenceToSpline(node, SplineGenerator.defaultFence)

-- 1. Manually Select the spline, go to user attributes and update these settings
-- fenceGenerationPanelObjectId1
-- fenceGenerationPanelObjectSize1
-- fenceGenerationPoleObjectId1

-- 2. Load settings from selected spline and generate fence
-- local fence = SplineGenerator.loadFenceFromSpline(node)
-- SplineGenerator.buildFence(node, fence)