-- Name: BSU_bunkerSiloOverwrites
-- Author: Chissel

BSU_bunkerSiloOverwrites = {}


function BSU_bunkerSiloOverwrites:update(dt)
    if not self:getCanInteract(true) then
        BSU_bunkerSiloOverwrites.unregisterCloseCoverActionEvent(self)
        BSU_bunkerSiloOverwrites.unregisterClearAreaActionEvent(self)
        BSU_bunkerSiloOverwrites.unregisterReopenCoverActionEvent(self)
        BSU_bunkerSiloOverwrites.unregisterChangeCoverActionEvent(self)
        return
    end

    local fillType = g_fillTypeManager:getFillTypeByIndex(self.fermentingFillType)
    if fillType ~= nil then
        g_currentMission:addExtraPrintText(string.format("%s: %s", g_i18n:getText("info_BSU_SILO_COVER"), fillType.title))
    end

    BSU_bunkerSiloOverwrites.registerChangeCoverActionEvent(self)

    if self.fillLevel == 0 then
        BSU_bunkerSiloOverwrites.unregisterClearAreaActionEvent(self)
    else
        BSU_bunkerSiloOverwrites.registerClearAreaActionEventIfNeeded(self)
    end

    if self.state == BunkerSilo.STATE_CLOSED then
        BSU_bunkerSiloOverwrites.registerReopenCoverActionEvent(self)
    else
        BSU_bunkerSiloOverwrites.unregisterReopenCoverActionEvent(self)
    end

    if g_localPlayer == nil or g_localPlayer.rootNode == nil then
        return
    end

    local ix, iy, iz = getWorldTranslation(g_localPlayer.rootNode)
    local closerToFront = self:getIsCloserToFront(ix, iy, iz)

    if closerToFront then
        if self.isOpenedAtFront then
            BSU_bunkerSiloOverwrites.registerCloseCoverActionEvent(self)
        else
            BSU_bunkerSiloOverwrites.unregisterCloseCoverActionEvent(self)
        end
    end

    if not closerToFront then
        if self.isOpenedAtBack then
            BSU_bunkerSiloOverwrites.registerCloseCoverActionEvent(self)
        else
            BSU_bunkerSiloOverwrites.unregisterCloseCoverActionEvent(self)
        end
    end
end

-- Clear area

function BSU_bunkerSiloOverwrites.registerClearAreaActionEventIfNeeded(bunkerSilo)
    if bunkerSilo.isClient and bunkerSilo.bsu_clearAreaEventId == nil and bunkerSilo.fillLevel > 0 then
        local _, clearAreaEventId = g_inputBinding:registerActionEvent(InputAction.BSU_CLEAR_AREA, bunkerSilo, bunkerSilo.openClearAreaDialog, false, true, false, true)

        if clearAreaEventId == nil then
            return
        end

        g_inputBinding:setActionEventTextVisibility(clearAreaEventId, true)
        g_inputBinding:setActionEventTextPriority(clearAreaEventId, GS_PRIO_VERY_HIGH)
        bunkerSilo.bsu_clearAreaEventId = clearAreaEventId
    end
end

function BSU_bunkerSiloOverwrites.unregisterClearAreaActionEvent(bunkerSilo)
    if bunkerSilo.bsu_clearAreaEventId ~= nil then
        g_inputBinding:removeActionEvent(bunkerSilo.bsu_clearAreaEventId)
        bunkerSilo.bsu_clearAreaEventId = nil
    end
end

-- Close cover

function BSU_bunkerSiloOverwrites.registerCloseCoverActionEvent(bunkerSilo)
    if bunkerSilo.isClient and bunkerSilo.bsu_closeCoverEventId == nil then
        local _, closeCoverEventId = g_inputBinding:registerActionEvent(InputAction.BSU_CLOSE_COVER, bunkerSilo, bunkerSilo.closeCoverCallback, false, true, false, true)

        if closeCoverEventId == nil then
            return
        end

        g_inputBinding:setActionEventTextVisibility(closeCoverEventId, true)
        g_inputBinding:setActionEventTextPriority(closeCoverEventId, GS_PRIO_VERY_HIGH)
        bunkerSilo.bsu_closeCoverEventId = closeCoverEventId
    end
end

function BSU_bunkerSiloOverwrites.unregisterCloseCoverActionEvent(bunkerSilo)
    if bunkerSilo.bsu_closeCoverEventId ~= nil then
        g_inputBinding:removeActionEvent(bunkerSilo.bsu_closeCoverEventId)
        bunkerSilo.bsu_closeCoverEventId = nil
    end
end

-- Reopen

function BSU_bunkerSiloOverwrites.registerReopenCoverActionEvent(bunkerSilo)
    if bunkerSilo.isClient and bunkerSilo.bsu_reopenCoverEventId == nil then
        local _, reopenCoverEventId = g_inputBinding:registerActionEvent(InputAction.BSU_REOPEN_COVER, bunkerSilo, bunkerSilo.openReopenCoverDialog, false, true, false, true)

        if reopenCoverEventId == nil then
            return
        end

        g_inputBinding:setActionEventTextVisibility(reopenCoverEventId, true)
        g_inputBinding:setActionEventTextPriority(reopenCoverEventId, GS_PRIO_VERY_HIGH)
        bunkerSilo.bsu_reopenCoverEventId = reopenCoverEventId
    end
end

function BSU_bunkerSiloOverwrites.unregisterReopenCoverActionEvent(bunkerSilo)
    if bunkerSilo.bsu_reopenCoverEventId ~= nil then
        g_inputBinding:removeActionEvent(bunkerSilo.bsu_reopenCoverEventId)
        bunkerSilo.bsu_reopenCoverEventId = nil
    end
end

-- Change cover

function BSU_bunkerSiloOverwrites.registerChangeCoverActionEvent(bunkerSilo)
    if bunkerSilo.isClient and (bunkerSilo.bsu_changeCoverEventId == nil or bunkerSilo.bsu_changeCoverEventId == "") then
        local _, changeCoverEventId = g_inputBinding:registerActionEvent(InputAction.BSU_CHANGE_COVER, bunkerSilo, bunkerSilo.changeCoverCallback, false, true, false, true)

        if changeCoverEventId == nil then
            return
        end

        g_inputBinding:setActionEventTextVisibility(changeCoverEventId, true)
        g_inputBinding:setActionEventTextPriority(changeCoverEventId, GS_PRIO_VERY_HIGH)
        bunkerSilo.bsu_changeCoverEventId = changeCoverEventId
    end
end

function BSU_bunkerSiloOverwrites.unregisterChangeCoverActionEvent(bunkerSilo)
    if bunkerSilo.bsu_changeCoverEventId ~= nil then
        g_inputBinding:removeActionEvent(bunkerSilo.bsu_changeCoverEventId)
        bunkerSilo.bsu_changeCoverEventId = nil
    end
end

------------------------------------------------------------------------------------

function BSU_bunkerSiloOverwrites.setState(self, superFunc, state, showNotification)
    if state ~= self.state then
        if state == BunkerSilo.STATE_FILL then
            if self.state == BunkerSilo.STATE_CLOSED then
                self.compactedFillLevel = self.fillLevel
                self.compactedPercent = 100
                self:switchFillTypeToInputFillType()
            else
                self.compactedFillLevel = 0
                self.compactedPercent = 0
            end
        end
    end
    superFunc(self, state, showNotification)
end

-- Close cover

function BunkerSilo:closeCoverCallback()
    local ix,iy,iz = self:getInteractionPosition()
    local closeAtFront = self:getIsCloserToFront(ix,iy,iz)

    if self.isServer then
        self:closeCover(closeAtFront)
    else
        g_client:getServerConnection():sendEvent(BSU_closeCoverEvent.new(self, closeAtFront))
    end
end

function BunkerSilo:closeCover(closeAtFront)
    if closeAtFront and self.isOpenedAtFront then
        self.isOpenedAtFront = false
    elseif not closeAtFront and self.isOpenedAtBack then
        self.isOpenedAtBack = false
    end

    if not self.isOpenedAtFront and not self.isOpenedAtBack then
        self:setState(BunkerSilo.STATE_FERMENTED)

        if self.isServer then
            g_densityMapHeightManager:removeFixedFillTypesArea(self.bunkerSiloArea)
            g_densityMapHeightManager:removeConvertingFillTypeAreas(self.bunkerSiloArea)

            self:raiseDirtyFlags(self.bunkerSiloDirtyFlag)
        end
    end

    self:switchFillTypeToFermenting(closeAtFront)

    self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloCovered"))
end

function BunkerSilo:switchFillTypeToFermenting(switchAtFront)
    local a0x, a0z
    local a1x, a1z
    local a2x, a2z
    local area = self.bunkerSiloArea
    local offset = 0

    if switchAtFront then
        local length = math.max(self.openingLength, self:getBunkerAreaOffset(true, area.offsetFront, self.fermentingFillType) + 1)
        a0x, a0z = area.sx + (offset * area.dhx_norm), area.sz + (offset * area.dhz_norm)
        a1x, a1z = a0x + area.dwx, a0z + area.dwz
        a2x, a2z = area.sx + ((offset + length) * area.dhx_norm), area.sz + ((offset + length) * area.dhz_norm)
        self.bunkerSiloArea.offsetFront = 0
    else
        local length = math.max(self.openingLength, self:getBunkerAreaOffset(false, area.offsetBack, self.fermentingFillType) + 1)
        a0x, a0z = area.hx - (offset * area.dhx_norm), area.hz - (offset * area.dhz_norm)
        a1x, a1z = a0x + area.dwx, a0z + area.dwz
        a2x, a2z = area.hx - ((offset + length) * area.dhx_norm), area.hz - ((offset + length) * area.dhz_norm)
        self.bunkerSiloArea.offsetBack = 0
    end

    DensityMapHeightUtil.changeFillTypeAtArea(a0x,a0z, a1x,a1z, a2x,a2z, self.outputFillType, self.fermentingFillType)
end

function BunkerSilo:switchFillTypeToInputFillType()
    local a0x, a0z
    local a1x, a1z
    local a2x, a2z
    local area = self.bunkerSiloArea
    local offset = 0

    local a = area.hx - area.sx
    local b = area.hz - area.sz

    local length = math.sqrt(a^2 + b^2)

    a0x, a0z = area.sx + (offset * area.dhx_norm), area.sz + (offset * area.dhz_norm)
    a1x, a1z = a0x + area.dwx, a0z + area.dwz
    a2x, a2z = area.sx + ((offset + length) * area.dhx_norm), area.sz + ((offset + length) * area.dhz_norm)

    DensityMapHeightUtil.changeFillTypeAtArea(a0x,a0z, a1x,a1z, a2x,a2z, self.fermentingFillType, self.inputFillType)
end

-- Reopen cover

function BunkerSilo:openReopenCoverDialog()
    YesNoDialog.show(self.reopenCoverCallback, self, g_i18n:getText("BSU_REOPEN_COVER_DIALOG_TEXT"), g_i18n:getText("BSU_REOPEN_COVER_DIALOG_TITLE"))
end

function BunkerSilo:reopenCoverCallback(success)
    if not success then
        return
    end

    if self.isServer then
        self:reopenCover()
    else
        g_client:getServerConnection():sendEvent(BSU_reopenCoverEvent.new(self))
    end
end

function BunkerSilo:reopenCover()
    self:setState(BunkerSilo.STATE_FILL)

    self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloOpened"))
end

-- Clear area

function BunkerSilo:openClearAreaDialog()
    YesNoDialog.show(self.clearAreaCallback, self, g_i18n:getText("BSU_CLEAR_AREA_DIALOG_TEXT"), g_i18n:getText("BSU_CLEAR_AREA_DIALOG_TITLE"))
end

function BunkerSilo:clearAreaCallback(success)
    if not success then
        return
    end

    if self.isServer then
        self:clearArea()
    else
        g_client:getServerConnection():sendEvent(BSU_clearAreaEvent.new(self))
    end
end

function BunkerSilo:clearArea()
    self:setState(BunkerSilo.STATE_DRAIN)
    self.fermentingPercent = 0
    self.compactedPercent = 0
    self.bunkerSiloArea.offsetFront = 0
    self.bunkerSiloArea.offsetBack = 0
    self.isOpenedAtFront = false
    self.isOpenedAtBack = false

    self:clearSiloArea()
    self:raiseDirtyFlags(self.bunkerSiloDirtyFlag)

    self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloIsEmpty"))
end

-- Change cover

local function indexOf(array, value)
    for i, v in ipairs(array) do
        if v == value then
            return i
        end
    end

    return 0
end

function BunkerSilo:changeCoverCallback()
    local availableFillTypes = BSU_bunkerSiloOverwrites.availableFillTypes
    local index = indexOf(availableFillTypes, self.fermentingFillType)
    local newIndex = index + 1

    if newIndex > #availableFillTypes then
        newIndex = 1
    end

    local fillType = availableFillTypes[newIndex]

    if fillType == nil then
        print("Error BSU: FillType not available!")
        return
    end

    if self.isServer then
        self:changeCover(fillType)
    else
        g_client:getServerConnection():sendEvent(BSU_changeCoverEvent.new(self, fillType))
    end
end

function BunkerSilo:changeCover(fillType)
    self:switchFillTypeFromTo(self.fermentingFillType, fillType)
    self.fermentingFillType = fillType
end

function BunkerSilo:switchFillTypeFromTo(from, to)
    local a0x, a0z
    local a1x, a1z
    local a2x, a2z
    local area = self.bunkerSiloArea
    local offset = 0

    local a = area.hx - area.sx
    local b = area.hz - area.sz

    local length = math.sqrt(a^2 + b^2)

    a0x, a0z = area.sx + (offset * area.dhx_norm), area.sz + (offset * area.dhz_norm)
    a1x, a1z = a0x + area.dwx, a0z + area.dwz
    a2x, a2z = area.sx + ((offset + length) * area.dhx_norm), area.sz + ((offset + length) * area.dhz_norm)

    DensityMapHeightUtil.changeFillTypeAtArea(a0x, a0z, a1x, a1z, a2x, a2z, from, to)
end