attack_mission = {}

-- requires => all modules that are required by this module. contains => all submodules this module contains.
-- This difference is made, to prevent the import of submodules without its parent
attack_mission.requires = {"util"}
attack_mission.contains = {"attack_mission.DATA", "attack_mission.helpers",}


-- holds all active attack_missions as well as the number of attack_missions generated since last reload
attack_mission.active = {}
-- holds the difficulty of an active attack mission, index is equals to active
attack_mission.active_zType = {}

attack_mission.generationIndex = 1

-- holds all handler functions
attack_mission.eventHandler = {}

--- this function is registered as an DCS event listener (see DCS event listeners)
---
--- INFO: This funcion is meant to only be called by the DCS scripting engine.
--- @param event table event attributed supplied by the dcs scripting engine
--- @return boolean
function attack_mission.eventHandler:onEvent(event)
    -- there was an error in the dcs event engine => return with satus code false
    if event == nil or event.initiator == nil or event.target == nil then 
        return false
    end

    if (event.target:getCategory() ~= Object.Category.UNIT) then
        return false
    end

    -- any unit was killed
    if event.id == world.event.S_EVENT_KILL then
        -- get the callers group
        local group = event.target:getGroup()

        -- check if this group was registerd as an attack mission and if the entire groop is dead => mission finished
        if attack_mission.active[group:getName()] ~= nil and not util.group.isGroupAlive(group) then
            attack_mission.success(group)
        end
    end

    return true
end

--- used to mark an attack_mission as succeeded (all units destroyed)
--- @param group table group of the caller (see DCS Group)
function attack_mission.success(group)
    -- create event for this action
    local event = util.misc.deepCopy(attack_mission.DATA.EVENT_TEMPLATE)
        event.id = attack_mission.DATA.EVENT_TYPES.AZ_SUCCESS
        event.group = group
        event.zName = attack_mission.active[group:getName()]
        event.zType = attack_mission.active_zType[group:getName()]

    -- throw event
    util.mEvent.throwME("AZ", event)

    -- remove zone from active and trigger success message
    attack_mission.active[group:getName()] = nil
    attack_mission.active_zType[group:getName()] = nil

    trigger.action.outText("ATTACK ZONE MISSION SUCCESS: mission #" .. util.group.getGroupId(group:getName()) .. " " .. event.zType .. " completed", 20, false)

    -- a mission type can supply it's own finishing sound
    -- if not, a default sound is used
    local sound_file = (attack_mission.DATA.SOUND_END[event.zType] or attack_mission.DATA.SOUND_END_DEFAULT)
    trigger.action.outSoundForCoalition(coalition.side.BLUE, sound_file)
end

--- spawns an attack_mission. This function includes all generation of data and is meant to be called without parameters
--- @param DIFF_DATA string difficulty string
function attack_mission.spawn(ZONE_TYPE, DIFF_DATA)
    -- generate the trigger zone. Abort if no nonactive if available
    local ok1, zone = util.error.wpcall(function() return attack_mission.helpers.pickZone(ZONE_TYPE) end)
    if not ok1 then util.error.raise(zone) return nil end

    if zone == nil then
        trigger.action.outText("No available " .. tostring(ZONE_TYPE) .. " trigger zones. Aborting spawn", 10, false)
        return nil
    end

    -- generate types and coords
    local ok2, types, coords = util.error.wpcall(function() return attack_mission.helpers.getTypPos(zone, DIFF_DATA:upper()) end)
    if not ok2 then util.error.raise(types) return nil end

    -- randomize headings for each unit
    local headings = util.misc.fill({}, function() return math.random() * 2*math.pi end, #types)

    -- generate the unit and group tables themself
    local ok3, units = util.error.wpcall(function() return util.unit.generateUnitTable(types, coords, headings, attack_mission.DATA.UNIT_TEMPLATE) end)
    if not ok3 then util.error.raise(units) return nil end
    local ok4, group = util.error.wpcall(function() return util.group.generateGroupTable(units, {}, attack_mission.DATA.GROUP_TEMPLATE) end)
    if not ok4 then util.error.raise(ok4) return nil end

    -- save generated group and incement index
    attack_mission.generationIndex = attack_mission.generationIndex + 1
    attack_mission.active[group.name] = zone.name
    attack_mission.active_zType[group.name] = ZONE_TYPE
    

    -- spawn attack_mission and trigger notification
    coalition.addGroup(country.id.CJTF_RED, Group.Category.GROUND, group)
    trigger.action.outText("ATTACK ZONE ACTIVE: mission #" .. util.group.getGroupId(group.name) .. " Spawned", 20, false)

    local sound_file = (attack_mission.DATA.SOUND[ZONE_TYPE] or attack_mission.DATA.SOUND_DEFAULT)
    trigger.action.outSoundForCoalition(coalition.side.BLUE, sound_file)

    -- create event for this action
    local event = util.misc.deepCopy(attack_mission.DATA.EVENT_TEMPLATE)
        event.id = attack_mission.DATA.EVENT_TYPES.AZ_CREATE
        event.group = Group.getByName(group.name) -- compatibility get group with functions
        event.zName = zone.name
        event.zType = ZONE_TYPE

    -- dispatch event
    util.mEvent.throwME("AZ", event)

    return nil
end

function attack_mission.init()
    util.missionCommands.add("/MISSIONS", "CREATE EASY Attack Mission", attack_mission.spawn, "EASY", "EASY")
    util.missionCommands.add("/MISSIONS", "CREATE HARD Attack Mission", attack_mission.spawn, "HARD", "HARD")

    util.missionCommands.add("/MISSIONS/PRACTICE/LAND", "CREATE CIVILIAN Mission", attack_mission.spawn, "PR", "PR_CIV")
    util.missionCommands.add("/MISSIONS/PRACTICE/LAND", "CREATE UNARMOURED Mission", attack_mission.spawn, "PR", "PR_NOARMOUR")
    util.missionCommands.add("/MISSIONS/PRACTICE/LAND", "CREATE ARMOURED Mission", attack_mission.spawn, "PR", "PR_ARMOR")
    util.missionCommands.add("/MISSIONS/PRACTICE/LAND", "CREATE AAA Mission", attack_mission.spawn, "PR", "PR_AAA")
    util.missionCommands.add("/MISSIONS/PRACTICE/LAND", "CREATE SAM Mission", attack_mission.spawn, "PR", "PR_SAM")

    world.addEventHandler(attack_mission.eventHandler)
end

function attack_mission.cleanup()
    util.missionCommands.remove("/MISSIONS", "CREATE EASY Attack Mission")
    util.missionCommands.remove("/MISSIONS", "CREATE HARD Attack Mission")

    util.missionCommands.remove("/MISSIONS/PRACTICE/LAND", "CREATE CIVILIAN Mission")
    util.missionCommands.remove("/MISSIONS/PRACTICE/LAND", "CREATE ARMOURED Mission")
    util.missionCommands.remove("/MISSIONS/PRACTICE/LAND", "CREATE UNARMOURED Mission")
    util.missionCommands.remove("/MISSIONS/PRACTICE/LAND", "CREATE AAA Mission")
    util.missionCommands.remove("/MISSIONS/PRACTICE/LAND", "CREATE SAM Attack Mission")

    world.removeEventHandler(attack_mission.eventHandler)
end