util.naming = {}

util.naming.DEL = {
    DEFAULT = "-",
    ALTERNATIVE = "._;,|#"
}

--- creates a mission name according to naming conventions
---
--- @param prefix string mission / naming prefix used to identify different types of names
--- @param content string[] content of the name
--- @param case? boolean if false or nil name gets converted to lowercase. Defaults to nil
--- @return string
function util.naming.create(prefix, content, case)
    if type(prefix) ~= "string" then error(util.error.argErr(prefix, "string", 1)) end
    content = type(content) == "table" and content or { content }

    -- convert everything to lowercase if case is not set
    prefix = case and tostring(prefix) or tostring(prefix):lower()
    content = case and content or util.misc.arrLower(content, false)

    local str = prefix

    for _i, val in ipairs(content) do
        str = str .. (str ~= "" and util.naming.DEL.DEFAULT or "") .. val
    end

    return str
end

--- checks if a given name fits the given naming convetion,
---
--- INFO: this function implements a non strict match --> name must not exactly match pattern. Additional and sequence changes allowed
--- @param str string name to verify against
--- @param prefix string mission / naming prefix used to identify different types of names
--- @param pattern? string[] name pattern
--- @param case? boolean if false or nil names gets converted to lowercase. Defaults to false
--- @return string
function util.naming.check(str, prefix, pattern, case)
    if type(str) ~= "string" then error(util.error.argErr(str, "string", 1)) end
    if type(prefix) ~= "string" then error(util.error.argErr(str, "string", 2)) end
    pattern = type(pattern) == "table" and pattern or {}
    case = type(case) == "boolean" and case or false

    -- convert everything to lowercase if case is not set
    str = case and str or str:lower()
    prefix = case and tostring(prefix) or tostring(prefix):lower()
    pattern = case and pattern or util.misc.arrLower(pattern, false)

    local del = util.naming.DEL.DEFAULT .. util.naming.DEL.ALTERNATIVE
    prefix = "^" .. prefix

    if not str:find(prefix) then return false end

    for _i, val in ipairs(pattern) do
        if not str:find("[" .. del .. "]" .. val) then return false end
    end

    return true
end

--- checks if a given name fits the given naming convetion,
---
--- INFO: this function implements a strict match --> name must exactly match pattern. No adidtional, no sequence changes
--- @param str string name to verify against
--- @param prefix string mission / naming prefix used to identify different types of names
--- @param pattern? string[] name pattern
--- @param case? boolean if false or nil names gets converted to lowercase. Defaults to false
--- @return string
function util.naming.checkStrict(str, prefix, pattern, case)
    if type(str) ~= "string" then error(util.error.argErr(str, "string", 1)) end
    if type(prefix) ~= "string" then error(util.error.argErr(str, "string", 2)) end
    pattern = type(pattern) == "table" and pattern or {}
    case = type(case) == "boolean" and case or false

    -- convert everything to lowercase if case is not set
    str = case and str or str:lower()
    prefix = case and tostring(prefix) or tostring(prefix):lower()
    pattern = case and pattern or util.misc.arrLower(pattern, false)

    local del = util.naming.DEL.DEFAULT .. util.naming.DEL.ALTERNATIVE
    local regex = "^" .. prefix

    for _i, val in ipairs(pattern) do
        regex = regex .. (regex ~= "^" and "[" .. del .. "]+" or "") .. val
    end

    return str:match(regex) == str
end

--- retunrs an array of indices inside the provided array, wich match all allowed delimiters
--- @param str string input string
--- @return number[]
function util.naming.getDelIndices(str)
    if type(str) ~= "string" then error(util.error.argErr(str, "string", 1)) end

    -- generate pattern from available delimeter
    local regex = "[" .. util.naming.DEL.DEFAULT .. util.naming.DEL.ALTERNATIVE .. "].*"
    local indices, i = {}, 0

    while i ~= nil do
        i = str:find(regex, i + 1)
        indices[#indices+1] = i -- arr[n] = nil will result in an arry with size n-1 so we can ignore last iteration
    end

    return indices
end

--- creates a pattern for matching mission names
--- @param name string original name
--- @return string pattern
function util.naming.generatePattern(name)
    local pattern = ""

    -- for now just create a non case sensitive regex
    for char in string.gmatch(name, ".") do
        pattern = pattern .. "["..char:lower()..char:upper().."]"
    end

    return pattern
end