util.group = {}

util.group.groupIndex = 1

--- checks if the specified group (all units in the group) is still alive
--- @param group table (see DCS Group)
--- @return boolean
function util.group.isGroupAlive(group)
    if type(group) ~= "table" then error(util.error.argErr(group, "table", 1)) end

    local units = Group.getUnits(group)

    -- for every unit in group check if their life is still above 0
    for _i, unit in ipairs(units) do
        if unit ~= nil and unit:getLife() > 0 then return true end
    end

    return false
end

--- generates a group table out of aunit table and appends waypoint for movement
--- @param units table[] units the group should consist of (see DCS Unit)
--- @param attributes table table of group attributes (done so parameters are variable)
--- @param TEMPLATE table template of group you want to create (const)
--- @return table @(see DCS Group)
function util.group.generateGroupTable(units, attributes, TEMPLATE)
    if type(units) ~= "table" then error(util.error.argErr(units, "table", 1)) end
    if type(attributes) ~= "table" then error(util.error.argErr(attributes, "table", 2)) end
    if type(TEMPLATE) ~= "table" then error(util.error.argErr(TEMPLATE, "table", 3)) end

    -- copy group template and populate with data
    local group= util.misc.deepCopy(TEMPLATE)

    group.units = units
    group.route = attributes.route
    group.name = util.naming.create("mission_group_", { tostring(util.group.groupIndex) })

    -- increment global group index used for unique name generation
    util.group.groupIndex = util.group.groupIndex + 1

    return group
end

--- generates a spawnable template from a group placed in the mission editor (includes all attributes)
---
--- INFO: this implementation returns nil if no group could be found
--- @param name string name of group
--- @return table|nil @ready to modify and spawn template (copied from original)
function util.group.generateGroupTableFromME(name)
    if type(name) ~= "string" then error(util.error.argErr(name, "string", 1)) end

    local rel = env.mission.coalition or {}

    -- get path in wich the unit is located (max 30 so we dont crash the whole mission if they changed something in the structure)
    local pth = util.misc.recFind(rel, name, "name", 30)
    if not pth then return nil end

    -- go through the path and move the rel pointer down until we reach the group
    local i, curr = #pth, ""
    repeat
        -- index is been hold, so we dont accidently iterate over the table boundaries
        i, curr = i - 1, pth[i]
        rel = rel[curr]
    until curr == "group" or i <= 1

    -- this should only occur if DCS changed something about the structure, or there is an object with the same name in the rel dir
    if i <= 1 then
        error("path index to small (most likely no group attribute found). Check " .. rel .. " structure.")
    end

    -- this unit most likely is going to be modified. So deepcopy seems worth the calculation const
    return util.misc.deepCopy(rel[pth[i]])
end

--- returns the group id (index) wich was assigned to the name on group creation
---
--- WARNING: This is not the DCS unit id.
--- @param groupName string name of group
--- @return number
function util.group.getGroupId(groupName)
    if type(groupName) ~= "string" then error(util.error.argErr(groupName, "string", 1)) end

    local delInd = util.naming.getDelIndices(groupName)

    return tonumber(groupName:sub((delInd[#delInd] or 0) + 1, #groupName))
end

--- returns all units (DCS Unit objects) matching the regex expression
--- @param regex string regex pattern used for filtering
--- @param coalitionId? number if provided all other coalitions are excluded
--- @return table[]
function util.group.getGroupByRegex(regex, coalitionId)
    if type(regex) ~= "string" then error(util.error.argErr(regex, "string", 1)) end

    local coalitions = coalitionId and { coalitionId } or util.misc.getValues(coalition.side)
    local groups = {}

    -- retrieve all units from coalitions
    for _i, id in ipairs(coalitions) do
        util.misc.append(groups, coalition.getGroups(id))
    end

    -- return groups matching regex name
    return util.misc.filter(groups, function(v) return v:getName():match(regex) == v:getName() end)
end