--[[
Interface: 1.6.0.0 b9173

Copyright (C) GtX (Andy), 2019

Author: GtX | Andy
Date: 14.09.2019
Version: 1.0.0.0

Contact:
https://forum.giants-software.com
https://github.com/GtX-Andy

History:
V 1.0.0.0 @ 14.09.2019 - Release Version

Important:
Free for use in other mods - no permission needed.
No changes are to be made to this script without permission from GtX | Andy

Frei verwendbar - keine erlaubnis nötig
An diesem Skript dürfen ohne Genehmigung von GtX | Andy keine Änderungen vorgenommen werden
]]


SiloDisplayGui = {}
local SiloDisplayGui_mt = Class(SiloDisplayGui, YesNoDialog)

SiloDisplayGui.CONTROLS = {
    DISPLAY_LIST = "displayList",
    LIST_ITEM_TEMPLATE = "listItemTemplate",
    SET_SEEK_RANGE = "setSeekRange",
    SEEK_RANGE_HEADER = "seekRangeHeader",
    MESSAGE_BOX_HEADER = "messageBoxHeader",
    MESSAGE_BACKGROUND = "messageBackground",
    MESSAGE_ONE_TEXT = "messageOneText",
    MESSAGE_TWO_TEXT = "messageTwoText",
    WARNING_BACKGROUND = "warningBackground",
    WARNING_TEXT = "warningText",
    CONFIRM_BUTTON = "confirmButton"
}

SiloDisplayGui.SEEK_RADIUS = {
    "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
    "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40",
    "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60",
    "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80",
    "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100"
}

function SiloDisplayGui:new(target)
    local self = YesNoDialog:new(target, SiloDisplayGui_mt)

    self:registerControls(SiloDisplayGui.CONTROLS)

    self.seekRadius = 0
    self.setupComplete = false

    self.selectedSlotIndex = 1
    self.slotIndexToElement = {}

    self.displaySlots = {}
    self.sortedDisplaySlots = {}

    self.stationsInRange = {}
    self.numStationsInRange = 0
    self.numFillTypesInRange = 0

    self.availableFillTypesData = {}
    self.fillTypeToAvailableDataId = {}

    self.hasWarning = false

    self.leftDelay = 0
    self.rightDelay = 0

    self.i18n = g_i18n

    return self
end

function SiloDisplayGui:loadCallback(callback, target)
    self.target = target
    self.callback = callback
end

function SiloDisplayGui:loadSlotData(displaySlots, seekRadius, warningText)
    self.setupComplete = false

    self.displaySlots = displaySlots

    self:getUpdatedData(seekRadius, false)
    self:setScreenLayout(displaySlots)

    self:createDisplayList()

    self.setSeekRange:setTexts(SiloDisplayGui.SEEK_RADIUS)
    self.setSeekRange:setState(seekRadius, true)

    self.warningText:setText(warningText)
    self:updateWarning()

    self.selectedSlotIndex = 1
    self.setupComplete = true
end

function SiloDisplayGui:getUpdatedData(seekRadius, seekUpdateCheck)
    if self.target == nil then
        return
    end

    local storages = {}
    local sortedFillTypes = {}
    local availableFillTypes = {}

    local stationsInRange = self.target:getLoadingStationsInRange(false, self.target:getOwnerFarmId(), seekRadius)
    local numStationsInRange = #stationsInRange

    for i = 1, numStationsInRange do
        local station = stationsInRange[i]
        for storage, _ in pairs (station.sourceStorages) do
            if storage.fillLevels ~= nil and storages[storage] == nil then
                storages[storage] = true
            end
        end
    end

    for storage, _ in pairs (storages) do
        for fillType, _ in pairs (storage.fillTypes) do
            if availableFillTypes[fillType] == nil then
                availableFillTypes[fillType] = false

                table.insert(sortedFillTypes, fillType)
            end
        end
    end

    if not seekUpdateCheck then
        self.stationsInRange = stationsInRange
        self.numStationsInRange = numStationsInRange

        table.sort(sortedFillTypes)

        self.sortedDisplaySlots = nil
        self.numFillTypesInRange = #sortedFillTypes

        local typeData = {title = self.i18n:getText("ui_off"), id = 1, elementsUsing = {}}
        self.availableFillTypesData = {typeData}

        for i = 1, self.numFillTypesInRange do
            local id = i + 1
            local fillTypeIndex = sortedFillTypes[i]

            self.availableFillTypesData[id] = {}
            typeData = self.availableFillTypesData[id]

            typeData.id = id
            typeData.elementsUsing = {}
            typeData.fillTypeIndex = sortedFillTypes[i]
            typeData.title = g_fillTypeManager:getFillTypeByIndex(typeData.fillTypeIndex).title
            self.fillTypeToAvailableDataId[typeData.fillTypeIndex] = id

            if i <= #self.displaySlots then
                if self.sortedDisplaySlots == nil then
                    self.sortedDisplaySlots = {}
                    for j = 1, #self.displaySlots do
                        self.sortedDisplaySlots[j] = {userSet = false}
                    end
                end

                self.sortedDisplaySlots[i].fillTypeIndex = fillTypeIndex
            end
        end
    else
        return stationsInRange, #sortedFillTypes
    end
end

function SiloDisplayGui:setScreenLayout(slots)
    self.currentScreenLayout = {}

    if slots == nil then
        slots = self.displaySlots

        if slots == nil then
            slots = {}
        end
    end

    for i = 1, #slots do
        local stateOff = true
        local fillTypeIndex = slots[i].fillTypeIndex

        if fillTypeIndex ~= nil then
            local typeDataId = self.fillTypeToAvailableDataId[fillTypeIndex]
            local typeData = self.availableFillTypesData[typeDataId]

            if typeData ~= nil then
                stateOff = false
                self.currentScreenLayout[i] = {title = typeData.title, id = typeData.id, fillTypeIndex = fillTypeIndex}
            end
        end

        if stateOff then
            local title = self.availableFillTypesData[1].title
            self.currentScreenLayout[i] = {title = title, id = 1}
        end

        if self.sortedDisplaySlots ~= nil then
            local sortedDisplay = self.sortedDisplaySlots[i]
            sortedDisplay.userSet = (sortedDisplay.fillTypeIndex ~= fillTypeIndex)
        end
    end
end

function SiloDisplayGui:createDisplayList()
    self.displayList:deleteListItems()

    if self.currentScreenLayout ~= nil then
        local colourCount = 0
        self.slotIndexToElement = {}

        for i = 1, #self.currentScreenLayout do
            self.currentSlotIndex = i
            self.currentSlot = self.currentScreenLayout[i]

            local newRow = self.listItemTemplate:clone(self.displayList)
            newRow:updateAbsolutePosition()

            if colourCount % 2 ~= 0 then
                newRow:setImageColor(nil, 0.118, 0.116, 0.115, 0.20)
            else
                newRow:setImageColor(nil, 0.718, 0.716, 0.715, 0.0625)
            end

            colourCount = colourCount + 1
            self.currentSlot = nil
        end

        self.currentSlotIndex = nil

        self.displayList:clearElementSelection()
        FocusManager:setFocus(self.setSeekRange)
    end
end

function SiloDisplayGui:onCreateSlot(element)
    if self.currentSlot ~= nil then
        element:setText(self.currentSlotIndex)
    end
end

function SiloDisplayGui:onCreateFillType(element)
    if self.currentSlot ~= nil then
        element:setText(self.currentSlot.title)
        self.slotIndexToElement[self.currentSlotIndex] = element

        local typeData = self.availableFillTypesData[self.currentSlot.id]
        typeData.elementsUsing[#typeData.elementsUsing + 1] = element
    end
end

function SiloDisplayGui:onListSelectionChanged(index)
    self.selectedSlotIndex = index
    FocusManager:unsetFocus(self.setSeekRange)
end

function SiloDisplayGui:onListDoubleClick(index, listItem)
    self.selectedSlotIndex = index
    self:updateSelectedElement(listItem.elements[4], 1)
end

function SiloDisplayGui:updateSelectedElement(element, direction)
    local slot = self.currentScreenLayout[self.selectedSlotIndex]
    if slot ~= nil and element ~= nil then
        local currentId = slot.id

        local oldTypeData = self.availableFillTypesData[currentId]
        local numElementsUsing = #oldTypeData.elementsUsing

        if numElementsUsing > 1 then
            for i = 1, numElementsUsing do
                if oldTypeData.elementsUsing[i] == element then
                    table.remove(oldTypeData.elementsUsing, i)
                    break
                end
            end
        else
            oldTypeData.elementsUsing = {}
        end

        currentId = currentId + direction

        if direction > 0 then
            if currentId > #self.availableFillTypesData then
                currentId = 1
            end
        else
            if currentId < 1 then
                currentId = #self.availableFillTypesData
            end
        end

        local newTypeData = self.availableFillTypesData[currentId]
        newTypeData.elementsUsing[#newTypeData.elementsUsing + 1] = element
        element:setText(newTypeData.title)

        slot.id = currentId
        slot.fillTypeIndex = newTypeData.fillTypeIndex

        if self.sortedDisplaySlots ~= nil then
            local sortedDisplay = self.sortedDisplaySlots[self.selectedSlotIndex]
            if sortedDisplay ~= nil then
                sortedDisplay.userSet = (sortedDisplay.fillTypeIndex ~= slot.fillTypeIndex)
            end
        end
    end

    self:updateWarning()
end

function SiloDisplayGui:updateWarning()
    local hasWarning = false

    for i = 1, #self.availableFillTypesData do
        local typeData = self.availableFillTypesData[i]
        local numElementsUsing = #typeData.elementsUsing

        if numElementsUsing > 0 then
            if numElementsUsing > 1 then
                for j = 1, numElementsUsing do
                    local element = typeData.elementsUsing[j]

                    if typeData.id > 1 then
                        hasWarning = true
                        element:setTextColor(0.8069, 0.0097, 0.0097, 1)
                        element:setTextSelectedColor(0.8069, 0.0097, 0.0097, 1)
                    else
                        element:setTextColor(1, 1, 1, 1)
                        element:setTextSelectedColor(1, 1, 1, 1)
                    end
                end
            else
                typeData.elementsUsing[1]:setTextColor(1, 1, 1, 1)
                typeData.elementsUsing[1]:setTextSelectedColor(1, 1, 1, 1)
            end
        end
    end

    if not hasWarning then
        self.messageOneText:setText(self:getValidMessageText("siloDisplay_guiConnected", self.numStationsInRange, "Connected Silos:  %s"))
        self.messageTwoText:setText(self:getValidMessageText("siloDisplay_guiAvailable", self.numFillTypesInRange, "Available Fill Types:  %s"))
    end

    self.messageBackground:setVisible(not hasWarning)
    self.warningBackground:setVisible(hasWarning)
    self.confirmButton:setDisabled(hasWarning or (self.numStationsInRange < 1) or (self.numFillTypesInRange < 1))

    self.hasWarning = hasWarning
end

function SiloDisplayGui:onClickSeekRange(seekRadius)
    self.seekRadius = seekRadius

    if self.setupComplete then
        local stationsInRange, numFillTypesInRange = self:getUpdatedData(seekRadius, true)
        if #stationsInRange ~= self.numStationsInRange then
            if numFillTypesInRange == self.numFillTypesInRange then
                self.stationsInRange = stationsInRange
                self.numStationsInRange = #stationsInRange
            else
                self:getUpdatedData(seekRadius, false)
                self:setScreenLayout(self.sortedDisplaySlots)
                self:createDisplayList()
            end

            self:updateWarning()
        end
    end
end

function SiloDisplayGui:onClickOk()
    if self:getSuppressFunction() then
        return true
    end

    local element = self.slotIndexToElement[self.selectedSlotIndex]
    self:updateSelectedElement(element, 1)
end

function SiloDisplayGui:onClickActivate()
    if self:getSuppressFunction() or self.hasWarning then
        return true
    end

    if self.target ~= nil then
        local userSet = false
        if self.sortedDisplaySlots ~= nil then
            for i = 1, #self.sortedDisplaySlots do
                if self.sortedDisplaySlots[i].userSet then
                    userSet = true
                    break
                end
            end
        end

        self.callback(self.target, self.seekRadius, userSet, self.currentScreenLayout)
    else
        print("  Error: [SiloDisplayGui]  Target is missing.")
    end

    self:close()
end

function SiloDisplayGui:onClickBack(forceBack, usedMenuButton)
    self:close()
end

function SiloDisplayGui:update(dt)
    SiloDisplayGui:superClass().update(self, dt)

    if self.leftDelay > 0 then
        self.leftDelay = self.leftDelay - dt
    end

    if self.rightDelay > 0 then
        self.rightDelay = self.rightDelay - dt
    end
end

function SiloDisplayGui:inputEvent(action, value, eventUsed)
    eventUsed = SiloDisplayGui:superClass().inputEvent(self, action, value, eventUsed)

    if not eventUsed and not FocusManager:hasFocus(self.setSeekRange) then
        if action == InputAction.MENU_AXIS_LEFT_RIGHT then
            if value < -g_analogStickHTolerance then
                eventUsed = self:inputUpdate(-1)
            elseif value > g_analogStickHTolerance then
                eventUsed = self:inputUpdate(1)
            end
        elseif action == InputAction.MENU_PAGE_PREV then
            eventUsed = self:inputUpdate(-1)
        elseif action ==  InputAction.MENU_PAGE_NEXT then
            eventUsed = self:inputUpdate(1)
        end
    end

    return eventUsed
end

function SiloDisplayGui:inputUpdate(direction)
    local element = self.slotIndexToElement[self.selectedSlotIndex]

    if element ~= nil then
        if direction > 0 then
            if self.rightDelay <= 0 then
                self:updateSelectedElement(element, 1)
                self.rightDelay = 300
            end
        else
            if self.leftDelay <= 0 then
                self:updateSelectedElement(element, -1)
                self.leftDelay = 300
            end
        end
    end

    return true
end

function SiloDisplayGui:getValidMessageText(i18n, value, backup)
    if self.i18n:hasText(i18n) then
        return string.format(self.i18n:getText(i18n), value)
    end

    backup = Utils.getNoNil(backup, "%s")

    return string.format(backup, value)
end

function SiloDisplayGui:getSuppressFunction()
    if (self.numStationsInRange < 1) or (self.callback == nil) then
        return true
    end

    return false
end
