-- ====================================================================================
-- TUM.OBJECTIVES - HANDLES THE MISSION OBJECTIVES
-- ====================================================================================
-- ====================================================================================

TUM.objectives = {}

do
    local objectives = {}

    local function updateObjectiveText(index)
        if index < 1 or index > #objectives then return end

        local taskDB = Library.tasks[objectives[index].taskID]
        local suffix = ""
        if DCSEx.table.contains(taskDB.flags, DCSEx.enums.taskFlag.MOVING) then
            suffix = "\n(last position known to intel, target is moving)"
        end

        local text = "Objective "..objectives[index].name..":\n"..taskDB.description.short.." ("..TUM.objectives.getObjectiveProgress(index)..")"..suffix
        trigger.action.setMarkupText(objectives[index].markerTextID, text)
    end

    function TUM.objectives.add()
        local objective = TUM.objectivesMaker.create()

        if not objective then
            TUM.log("Failed to spawn a group for objective #"..tostring(#objectives + 1)..".", TUM.logger.logLevel.WARNING)
            return false
        end

        table.insert(objectives, objective)
        updateObjectiveText(#objectives)
        return true
    end

    function TUM.objectives.getCount()
        return #objectives
    end

    function TUM.objectives.getCompletedCount()
        if #objectives == 0 then return 0 end

        local count = 0
        for i=1,#objectives do
            if objectives[i].completed then count = count + 1 end
        end

        return count
    end

    function TUM.objectives.getCenter()
        local point2 = { x = 0, y = 0 }

        if #objectives == 0 then return point2 end

        for _,o in ipairs(objectives) do
            point2.x = point2.x + o.point2.x
            point2.y = point2.y + o.point2.y
        end

        point2.x = point2.x / #objectives
        point2.y = point2.y / #objectives

        return point2
    end

    function TUM.objectives.getRadius()
        if #objectives < 2 then return 10000 end -- Default to a 10km radius if no objectives or a single objective

        local center = TUM.objectives.getCenter()
        local radius = 0

        for _,o in ipairs(objectives) do
            local dist = DCSEx.math.getDistance2D(center, o.point2)
            if dist > radius then radius = dist end
        end

        return radius
    end

    function TUM.objectives.getObjective(index)
        if index < 1 or index > #objectives then return nil end
        return DCSEx.table.deepCopy(objectives[index])
    end

    function TUM.objectives.getObjectiveProgress(index, doublePercentage)
        doublePercentage = doublePercentage or false
        if index < 1 or index > #objectives then return "" end

        if TUM.DEBUG_MODE then
            return tostring(#objectives[index].completedUnitsID).."/"..tostring(math.max(1, #objectives[index].unitsID))
        else
            local percentage = 0
            if #objectives[index].unitsID > 0 then
                percentage = math.floor((#objectives[index].completedUnitsID / math.max(1, #objectives[index].unitsID)) * 100.0)
            end

            if doublePercentage then
                return tostring(percentage).."%%"
            else
                return tostring(percentage).."%"
            end
        end
    end

    function TUM.objectives.removeAll()
        TUM.log("Removing all objectives...")

        for _,o in ipairs(objectives) do
            if o.groupID then
                local g = DCSEx.world.getGroupByID(o.groupID)
                if g then g:destroy() end
            elseif o.unitsID then -- Some objects (such as static object) do not belong to a group, must be removed one by one
                for _,id in ipairs(o.unitsID) do
                    local u = DCSEx.world.getUnitByID(id)
                    if u then
                        u:destroy()
                    else
                        local s = DCSEx.world.getStaticObjectByID(id)
                        if s then s:destroy() end
                    end
                end
            end

            trigger.action.removeMark(o.markerID)
            trigger.action.removeMark(o.markerTextID)
        end

        objectives = {}
    end

    function TUM.objectives.areAllCompleted()
        if #objectives == 0 then return false end

        return TUM.objectives.getCompletedCount() == TUM.objectives.getCount()
    end

    function TUM.objectives.getSceneryObjectObjective(sceneryObject)
        if #objectives == 0 then return nil end
        if not sceneryObject then return nil end
        if Object.getCategory(sceneryObject) ~= Object.Category.SCENERY then return nil end

        for i=1,#objectives do
            if DCSEx.math.isSamePoint(sceneryObject:getPoint(), objectives[i].point3) then
                return i
            end
        end

        return nil
    end

    local function markObjectiveAsComplete(index)
        if index < 1 or index > #objectives then return end -- Out of bounds
        if objectives[index].completed then return end -- Objective already completed

        objectives[index].completed = true
        TUM.playerScore.awardCompletedObjective()

        if TUM.objectives.areAllCompleted() then
            TUM.mission.checkMissionStatus()
        else
            TUM.radio.playForCoalition(TUM.settings.getPlayerCoalition(), "commandObjectiveComplete", { objectives[index].name }, "Command", true)
        end

        DCSEx.dcs.outPicture("Pic-ObjectiveComplete.png", 5, true, 0, 1, 1, 25, 1)
        trigger.action.outSound("UI-MissionEnd.ogg")
    end

    local function onObjectiveEvent(index, event)
        if not event.initiator then return end

        if index < 1 or index > #objectives then return end -- Out of bounds
        if objectives[index].completed then return end -- Objective already completed

        local completionEvent = Library.tasks[objectives[index].taskID].completionEvent

        if completionEvent == DCSEx.enums.taskEvent.DAMAGE then
            if event.id ~= world.event.S_EVENT_DEAD and event.id ~= world.event.S_EVENT_HIT and event.id ~= world.event.S_EVENT_UNIT_LOST then return end
        elseif completionEvent == DCSEx.enums.taskEvent.DESTROY then
            if event.id ~= world.event.S_EVENT_DEAD and event.id ~= world.event.S_EVENT_UNIT_LOST then return end
        elseif completionEvent == DCSEx.enums.taskEvent.LAND then
            if event.id ~= world.event.S_EVENT_LAND then return end
            if Object.getCategory(event.initiator) ~= Object.Category.UNIT then return end
            if event.initiator:getDesc().category ~= Unit.Category.HELICOPTER then return end
            if event.initiator:getCoalition() ~= TUM.settings.getPlayerCoalition() then return end
            if DCSEx.math.getDistance2D(DCSEx.math.vec3ToVec2(event.initiator:getPoint()), objectives[index].point2) > 500 then return end -- Too far from objective

            -- Remove target group if it exists (to simulate it was picked up/captured)
            if objectives[index].groupID then
                local targetGroup = DCSEx.world.getGroupByID(objectives[index].groupID)
                if targetGroup then
                    targetGroup:destroy()
                end
            end

            timer.scheduleFunction(markObjectiveAsComplete, index, timer.getTime() + 3)
            updateObjectiveText(index)
            return
        end

        if objectives[index].isAirbaseTarget then
            if Object.getCategory(event.initiator) == Object.Category.BASE then
                if DCSEx.math.isSamePoint(event.initiator:getPoint(), objectives[index].point3) then
                    timer.scheduleFunction(markObjectiveAsComplete, index, timer.getTime() + 3)
                end
            end
        elseif objectives[index].isSceneryTarget then
            if Object.getCategory(event.initiator) == Object.Category.SCENERY then
                if DCSEx.math.isSamePoint(event.initiator:getPoint(), objectives[index].point3) then
                    timer.scheduleFunction(markObjectiveAsComplete, index, timer.getTime() + 3)
                end
            end
        else
            if Object.getCategory(event.initiator) == Object.Category.UNIT or Object.getCategory(event.initiator) == Object.Category.STATIC then
                local unitID = DCSEx.dcs.getObjectIDAsNumber(event.initiator)

                if DCSEx.table.contains(objectives[index].completedUnitsID, unitID) then return end
                if not DCSEx.table.contains(objectives[index].unitsID, unitID) then return end

                table.insert(objectives[index].completedUnitsID, unitID)
                if #objectives[index].completedUnitsID == #objectives[index].unitsID then
                    timer.scheduleFunction(markObjectiveAsComplete, index, timer.getTime() + 3)
                end
            end
        end

        updateObjectiveText(index)
    end

    function TUM.objectives.onEvent(event)
        for i,_ in ipairs(objectives) do
            onObjectiveEvent(i, event)
        end
    end
end
