



--[[
    Open interface
]]
addCommandHandler("turret", 
function ()

    local turretInterface = getTurretUserInterface()

    local visibilityState = guiGetVisible(turretInterface.mainWindow)
    if visibilityState then
        closeTurretPanel ()
    else
        local canMakeRequest, remainingTime = checkPassiveTimer("open-turret-panel", true, 2000) 
        if canMakeRequest then
            callServer("openTurretPanel", onOpenTurretPanel)
        else
            outputChatBox("You have to wait " .. math.ceil(remainingTime / 1000) .. " seconds before you can execute this command again.")
        end
    end
end)

function closeTurretPanel ()
    local turretInterface = getTurretUserInterface()
    showCursor(false)
    
    
    guiSetVisible(turretInterface.mainWindow, false)
    callServer("unselectTurretPanelItem")
end



function onOpenTurretPanel (status, message)

    if message then
        outputStatusMessage(status, message)
    end

    if status then
        local turretInterface = getTurretUserInterface()
        guiSetVisible(turretInterface.mainWindow, true)
        showCursor(true)
        
        

        callServer("requestTurretList", updateTurretList)
        guiGridListClear ( turretInterface.turretList )
    end
end

--[[
    Form field names
]]

local inputFieldValidationFunctions = {
    number = function (self, value) 
        local value = tostring(value):gsub("[^0-9,\.\-]", ""):gsub(",", ".")
        local startIndex = value:find(".", 0, true)
        if startIndex then
            value = value:gsub("[^0-9\-]", "")
            value = value:sub(1, startIndex-1) .. "." .. value:sub(startIndex)
        end
        return value
    end
}

local inputFields = {
    {inputName = "turretNameInput", id = "name"}, 
    {inputName = "turretDescriptionInput", id = "description"}, 
    {
        inputName = "turretPositionInputX", id = "positionX", 
        validation = inputFieldValidationFunctions.number
    }, 
    {
        inputName = "turretPositionInputY", 
        id = "positionY",
        validation = inputFieldValidationFunctions.number
    }, 
    {
        inputName = "turretPositionInputZ", 
        id = "positionZ",
        validation = inputFieldValidationFunctions.number
    }, 
    {
        inputName = "turretRotationInput", 
        id = "rotation",
        validation = inputFieldValidationFunctions.number
    }
}

local inputFieldBy_ID = {}
for i=1, #inputFields do
    local inputField = inputFields[i]
    inputFieldBy_ID[inputField.id] = inputField
end


local function addTurret (button, state)
    if button == "left" and state == "up" then
        local button = this
        guiSetEnabled(button, false)
        
        local turretInterface = getTurretUserInterface()
        guiSetEnabled(turretInterface.turretList, false)

        showLoadingStatus ("addTurret", true)
        callServer("addTurret", onTurretAdd, button)
        
    end
end

function onTurretAdd (button, status, message, turretsData) -- server feedback
    showLoadingStatus ("addTurret", false)
    local turretInterface = getTurretUserInterface()
    guiSetEnabled(turretInterface.turretList, true)

    if message then
        outputStatusMessage(status, message)
    end
    
    if status then
        updateTurretList (true, nil, turretsData)
    else
        guiSetEnabled(button, true)
    end
end


function updateTurretList (status, message, turretsData)

    if message then
        outputStatusMessage(status, message)
    end

    if status then

        local turretInterface = getTurretUserInterface()

        local selectedTurret_ID
        local selectedRow, selectedColumn = guiGridListGetSelectedItem(turretInterface.turretList)
        if selectedRow > -1 and selectedColumn > -1 then 
            local turret_ID = guiGridListGetItemData(turretInterface.turretList, selectedRow, 1)
            if turret_ID then 
                selectedTurret_ID = turret_ID
            end
        end
        
        guiSetEnabled(turretInterface.addTurretButton, true)

        guiGridListClear ( turretInterface.turretList )
        if turretsData and type(turretsData) == "table" then
            for i=1, #turretsData do
                local turretData = turretsData[i]
                local id = turretData.key
                local name = turretData.value

                local rowIndex = guiGridListAddRow(turretInterface.turretList, name)
                guiGridListSetItemData(turretInterface.turretList, rowIndex, 1, id)
                if selectedTurret_ID and selectedTurret_ID == id then
                    guiGridListSetSelectedItem ( turretInterface.turretList, rowIndex, 1 )
                end
            end
        end
    end
end
addToWhitelist(updateTurretList)

function updateTurretListItemName (turret_ID, name)

    local turretInterface = getTurretUserInterface()
    local rows = guiGridListGetRowCount ( turretInterface.turretList )
    for rowIndex=0, rows-1 do
        if guiGridListGetItemData(turretInterface.turretList, rowIndex, 1) == turret_ID then
            guiGridListSetItemText (turretInterface.turretList, rowIndex, 1, name, false, false )
            break
        end
    end
end
addToWhitelist(updateTurretListItemName)



local function turretItemClick ()
    local turretInterface = getTurretUserInterface()

    guiSetEnabled(turretInterface.scrollpane[1], false)
    local selectedRow, selectedColumn = guiGridListGetSelectedItem(turretInterface.turretList)
    if selectedRow > -1 and selectedColumn > -1 then 
        local turret_ID = guiGridListGetItemData(turretInterface.turretList, selectedRow, 1)
        if turret_ID then 
            showLoadingStatus ("requestTurretData", true)
            
            clearInputFields()    
            guiGridListClear ( turretInterface.turretOwnerList )

            callServer("requestTurretData", turret_ID, 
            function ( status, message, turretData)
                showLoadingStatus ("requestTurretData", false)
                --[[
                    Checking if the data matches the selected grid item
                ]]
                local selectedRow, selectedColumn = guiGridListGetSelectedItem(turretInterface.turretList)
                if selectedRow > -1 and selectedColumn > -1 then
                    if guiGridListGetItemData(turretInterface.turretList, selectedRow, 1) == turret_ID then
                        if message then
                            outputStatusMessage(status, message)
                        end
                    
                        if status then
                            
                            setInputCaptureStatus(false)

                            setElementData(turretInterface.scrollpane[1], "turret_ID", turret_ID, false)
                            for i=1, #inputFields do
                                local inputField = inputFields[i]
                                setElementData(turretInterface[inputField.inputName], "inputField_ID", inputField.id, false)
                                
                                
                                local value = tostring(turretData[inputField.id] or "")

                                guiSetText (turretInterface[inputField.inputName], value)
                            end
                            setInputCaptureStatus(true)
                            
                            updateTurretOwnerGridList (turretData.owners)

                            guiSetEnabled(turretInterface.scrollpane[1], true)
                        else
                            guiGridListSetSelectedItem (turretInterface.turretList, 0, 0)
                        end
                    end
                end
            end)
        else
            callServer("unselectTurretPanelItem")
        end
    else
        callServer("unselectTurretPanelItem")
    end
end

function setInputCaptureStatus(status)
    --[[
        This following code is used to prevent the onClientGUIChanged from triggering when guiSetText is used.
        1. It removes the eventHandlers
        2. guiSetText is used.
        3. It adds the eventHandlers again.
    ]]
    local turretInterface = getTurretUserInterface()
    if status then
        for i=1, #inputFields do
            local inputField = inputFields[i]
            addEventHandler("onClientGUIChanged", turretInterface[inputField.inputName], onTurretInputChange)
        end
    else
        for i=1, #inputFields do
            local inputField = inputFields[i]
            removeEventHandler("onClientGUIChanged", turretInterface[inputField.inputName], onTurretInputChange)
        end
    end
end

function clearInputFields ()
    --[[
        Empty all input fields.
    ]]
    setInputCaptureStatus(false)
    local turretInterface = getTurretUserInterface()
    for i=1, #inputFields do
        local inputField = inputFields[i]
        guiSetText(turretInterface[inputField.inputName], "")
    end
    setInputCaptureStatus(true)
end


function onTurretInputChange ()
    local turretInterface = getTurretUserInterface()
    local value = guiGetText(source)
    local inputField_ID = getElementData(source, "inputField_ID", false)
    local turret_ID = getElementData(source, "turret_ID", true) -- inherit

    if turret_ID and inputField_ID then
        local inputField = inputFieldBy_ID[inputField_ID]
        if inputField and inputField.validation then
            value = inputField:validation(value)
            setInputCaptureStatus(false)
            guiSetText(source, value)
            setInputCaptureStatus(true)
        end
        showLoadingStatus ("requestUpdateTurret", true)
        callServer("requestUpdateTurret", turret_ID, inputField_ID, value, onUpdateTurret)
    else
        outputStatusMessage(false, "Could find turret identifier or inputField identifier")
    end
end

function onUpdateTurret (status, message, turret_ID, name) -- server feedback
    showLoadingStatus ("requestUpdateTurret", false)
    if message then
        outputStatusMessage(status, message)
    end
    if status then
        local turretInterface = getTurretUserInterface()
        local rows = guiGridListGetRowCount ( turretInterface.turretList )
        
        for rowIndex=0, rows-1 do
            if guiGridListGetItemData(turretInterface.turretList, rowIndex, 1) == turret_ID then
                guiGridListSetItemText (turretInterface.turretList, rowIndex, 1, name, false, false )
                break
            end
        end
    end
end


function deleteTurret ()
    
    local turret_ID = getElementData(source, "turret_ID", true) -- inherit
    if turret_ID then
        local turretInterface = getTurretUserInterface()
        
        guiSetEnabled(turretInterface.scrollpane[1], false)
        guiSetEnabled(turretInterface.turretList, false)
        
        showLoadingStatus ("deleteTurret", true)
        callServer("deleteTurret", turret_ID, onDeleteTurret, this)

    else
        outputStatusMessage(false, "Could find turret identifier.")
    end
end

function onDeleteTurret (button, status, message) -- server feedback
    
    showLoadingStatus ("deleteTurret", false)
    local turretInterface = getTurretUserInterface()
    guiSetEnabled(turretInterface.turretList, true)
    
    if not status then
        guiSetEnabled(turretInterface.scrollpane[1], true)
    else
        clearInputFields()    
        guiGridListClear ( turretInterface.turretOwnerList )
        callServer("requestTurretList", updateTurretList)
    end

    if message then
        outputStatusMessage(status, message)
    end
end


function setCurrentOrientation ()
    --[[

        This function is called when the player clicks on the orientation button.
        It will adjust the input values and move the player out of the way.

    ]]

    local playerX, playerY, playerZ = getElementPosition(localPlayer)
    local _,_,rotZ = getElementRotation(localPlayer)

    local turretInterface = getTurretUserInterface()
    
    guiSetText(turretInterface.turretPositionInputX, playerX)
    guiSetText(turretInterface.turretPositionInputY, playerY)
    guiSetText(turretInterface.turretPositionInputZ, playerZ)
    guiSetText(turretInterface.turretRotationInput, rotZ)

    setElementPosition(localPlayer, playerX + 4, playerY + 4, playerZ + 2)
end

--[[

    Turret owners

]]


function addTurretOwner ()
    local turret_ID = getElementData(source, "turret_ID", true) -- inherit
    if turret_ID then
        local turretInterface = getTurretUserInterface()
        
        local accountName = guiGetText(turretInterface.turretOwnerInput)
        if accountName ~= "" then
            guiSetEnabled(source, false)
            showLoadingStatus ("addTurretOwner", true)
            callServer("addTurretOwner", turret_ID, accountName,  onAddTurretOwner, source, turretInterface.turretOwnerInput)
        else
            outputStatusMessage(false, "Please fill in an accountName.")
        end
    end
end

function ownerItemClick ()
    local turretInterface = getTurretUserInterface()
    guiSetEnabled(turretInterface.turretOwnerDeleteButton, false)
    
    local selectedRow, selectedColumn = guiGridListGetSelectedItem(turretInterface.turretOwnerList)
    if selectedRow > -1 and selectedColumn > -1 then 
        local owner = guiGridListGetItemData(turretInterface.turretOwnerList, selectedRow, 1)
        if owner then
            guiSetEnabled(turretInterface.turretOwnerDeleteButton, true)
        end
    end
end

function onAddTurretOwner (button, inputField, status, message, owners) -- server feedback
    showLoadingStatus ("addTurretOwner", false)
    guiSetEnabled(button, true)
    if status then
        updateTurretOwnerGridList(owners)
        guiSetText(inputField, "")
    end
    if message then
        outputStatusMessage(status, message)
    end
end

function deleteTurretOwner ()
    local turret_ID = getElementData(source, "turret_ID", true) -- inherit
    if turret_ID then
        local turretInterface = getTurretUserInterface()
        
        local selectedRow, selectedColumn = guiGridListGetSelectedItem(turretInterface.turretOwnerList)
        if selectedRow > -1 and selectedColumn > -1 then 
            local owner = guiGridListGetItemData(turretInterface.turretOwnerList, selectedRow, 1)
            if owner then
                guiSetEnabled(turretInterface.turretOwnerList, false)
                showLoadingStatus ("deleteTurretOwner", true)
                callServer("deleteTurretOwner",  turret_ID, owner , onDeleteTurretOwner)
            end
        end
    end
end

function onDeleteTurretOwner (status, message, owners) -- server feedback
    showLoadingStatus ("deleteTurretOwner", false)
    if message then
        outputStatusMessage(status, message)
    end
    updateTurretOwnerGridList(owners)
end

function becomeTurretOwner ()
    local turret_ID = getElementData(source, "turret_ID", true) -- inherit
    if turret_ID then
        guiSetEnabled(source, false)
        showLoadingStatus ("becomeTurretOwner", true)
        callServer("becomeTurretOwner", turret_ID,  onBecomeTurretOwner, source)
    end
end

function onBecomeTurretOwner (button, status, message, owners) -- server feedback
    showLoadingStatus ("becomeTurretOwner", false)
    guiSetEnabled(button, true)
    if status then
        updateTurretOwnerGridList(owners)
    end
    if message then
        outputStatusMessage(status, message)
    end
end


function updateTurretOwnerGridList (owners)
    --[[

        Update the owner list of the selected turret

    ]]
    local turretInterface = getTurretUserInterface()
    
    guiGridListClear ( turretInterface.turretOwnerList )
    guiSetEnabled(turretInterface.turretOwnerList, true)
    guiSetEnabled(turretInterface.turretOwnerDeleteButton, false)

    if owners then
        for owner, boolean in pairs(owners) do
            local rowIndex = guiGridListAddRow(turretInterface.turretOwnerList, owner)
            guiGridListSetItemData(turretInterface.turretOwnerList, rowIndex, 1, owner)
        end
    end
end



--[[

    Initialize

]]

addEventHandler("onClientResourceStart", resourceRoot,
function()
    guiSetInputMode ( "no_binds_when_editing"  )
    
    local turretInterface = getTurretUserInterface()

    addEventHandler("onClientGUIClick", turretInterface.closeTurretPanel, closeTurretPanel, false)

    addEventHandler("onClientGUIClick", turretInterface.addTurretButton, addTurret, false)
    addEventHandler("onClientGUIClick", turretInterface.turretList, turretItemClick)
    addEventHandler("onClientGUIClick", turretInterface.deleteTurretButton, deleteTurret, false)

    addEventHandler("onClientGUIClick", turretInterface.turretOwnerAddButton, addTurretOwner, false)
    addEventHandler("onClientGUIClick", turretInterface.turretBecomeOwnerButton, becomeTurretOwner, false)

    addEventHandler("onClientGUIClick", turretInterface.turretOwnerList, ownerItemClick)
    addEventHandler("onClientGUIClick", turretInterface.turretOwnerDeleteButton, deleteTurretOwner, false)
    addEventHandler("onClientGUIClick", turretInterface.setCurrentOrientation, setCurrentOrientation, false)

    for i=1, #inputFields do
        local inputField = inputFields[i]
        addEventHandler("onClientGUIChanged", turretInterface[inputField.inputName], onTurretInputChange)
    end
end, false, "low")




do
    --[[

        The following code is used for displaying the loading text.

    ]]

    local loadingActions = {}
    local shown = false

    local duration = 1000

    local labelAnimationTimer
    local animateLabel = function ()
        local turretInterface = getTurretUserInterface()
        local timeNow = getTickCount()
        
        guiSetText(turretInterface.loadingStatus, "Loading" .. string.rep(".",  math.ceil((timeNow % duration) / duration * 4) ) )

    end
    
    function showLoadingStatus (action, status)
        if status then
            loadingActions[action] = (loadingActions[action] or 0) + 1
        elseif loadingActions[action] then
            loadingActions[action] = loadingActions[action] - 1
            if loadingActions[action] < 1 then
                loadingActions[action] = nil
            end
        end

        local turretInterface = getTurretUserInterface()
        if not shown then
            if status then
                guiSetVisible(turretInterface.loadingStatus, true)

                if isTimer(labelAnimationTimer) then
                    killTimer(labelAnimationTimer)
                end
                labelAnimationTimer = setTimer(animateLabel, 300, 20)

                shown = true
            end
        else
            if not next(loadingActions) then
                guiSetVisible(turretInterface.loadingStatus, false)

                if isTimer(labelAnimationTimer) then
                    killTimer(labelAnimationTimer)
                end
                labelAnimationTimer = nil
                shown = false
            end
        end
    end
end