Documentation for this module may be created at Module:Damage/doc

local getArgs = require('Module:Arguments').getArgs
local p = {}
function string.starts(String,Start)
    return string.sub(String,1,string.len(Start))==Start
end

-- Implement sorted loop through array.
function spairs(t)
    local keys = {}
    for k in pairs(t) do keys[#keys+1] = k end
    table.sort(keys)
    local i = 0
    return function()
        i = i + 1
        if keys[i] then
            return keys[i], t[keys[i]]
        end
    end
end

-- Implement merging tables
function tableMerge(first_table, second_table)
    for k,v in spairs(second_table) do first_table[k] = v end
end

-- Implement rounding.
function round(num, numDecimalPlaces)
    if numDecimalPlaces == nil then
        numDecimalPlaces = 2
    end
    local mult = 10^(numDecimalPlaces or 0)
    return math.floor(num * mult + 0.5) / mult
end

-- Implement splitting string to a table.
function split (inputstr, sep)
    if sep == nil then
            sep = ",%s"
    end
    local t={}
    for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
            table.insert(t, str)
    end
    return t
end

-- Function wrapper for vardefine syntax in MW.
function var(name, dmg)
    return '{{#vardefine:{{formatnum:'..name..'|'..round(dmg)..'}}%}}'
end

-- Main process
function p.list(frame)
    local args = getArgs(frame)

    function inArgs(key)
        if args[key] ~= nil then
            return true
        end
    end

    function inArgsStarts(key)
        for k,v in spairs(args) do
            if string.starts(k, key) then
                return true
            end
        end
    end

    -- Define tables that hold the subsequent damage values.
    -- I know this isn't the best, but I don't want to work with nested tables in this language.
    local fvals = {}
    local tvals = {}
    local pvals1 = {}
    local pvals2 = {}
    local pvals12 = {}
    local vars = {}
    
    -- Handle trait table
    local traits = {}

    if (inArgs('heavy')) then
        traits.heavy = 1.44
    end

    if (inArgs('enhanced')) then
        traits.enhanced = 0.8
    end

    -- Customizable for empowered, it had to be special lol.
    if (inArgs('empowered')) then
        if (args.empowered == 'true') then
            traits.empowered = 1.2
        else
            traits.empowered = args.empowered
        end
    end

    -- Define total/average damage calculation based on damage per hit and hit amount.
    function getTotal(dmg, hits, fval)
        local i = 1
        fvals[fval] = 0
        for k,v in spairs(args) do
            if string.starts(k, 'dmg') then
                -- Apply Useful modifier.
                if string.find(fval, 'useful') then
                    args[dmg .. i] = args[dmg .. i] * args.useful_penalty
                end

                -- Proceed to combine
                fvals[fval] = fvals[fval] + args[dmg .. i] * args[hits .. i]
                i = i + 1
            end
        end
    end

    -- Actually generate the values depending on arguments provided.
    getTotal('dmg', 'hits', 'total_damage')

    if inArgsStarts('avg_hits') then
        getTotal('dmg', 'avg_hits', 'average_damage')
    end

    if inArgsStarts('awk_dmg') then
        getTotal('awk_dmg', 'awk_hits', 'total_damage_awk')
    end

    if inArgsStarts('avg_awk_hits') then
        getTotal('awk_dmg', 'avg_awk_hits', 'average_damage_awk')
    end

    -- Handling traits
    -- Useful handled separately
    if inArgs('useful_penalty') then
        getTotal('dmg', 'hits_useful', 'total_damage_useful')

        if (inArgsStarts('avg_hits_useful')) then
            getTotal('dmg', 'avg_hits_useful', 'average_damage_useful')
        end
    end

    -- Multiply all values with traits and store them in another table.
    for k,v in spairs(fvals) do
        if not string.find(k, 'useful') then
            for kt,vt in spairs(traits) do
                if inArgs(kt) then
                    local dmg_name = k..'_'..kt
                    local dmg_formula = v * vt
                    tvals[dmg_name] = dmg_formula
                end
            end
        end
    end

    -- Define passives and fill the respective tables.
    local passive2 = 0
    if inArgs('passive2') then
        passive2 = split(args.passive2)

        for k,v in spairs(tvals) do
            local dmg_name = k..'_passive2'
            local dmg_formula = v * passive2[1]
            pvals2[dmg_name] = dmg_formula
        end

        -- Useful separately.
        for k,v in spairs(fvals) do
            if (string.find(k, 'useful')) then
                pvals2[k..'_passive2'] = v * passive2[1]
            end
        end
    end

    local passive1 = 0
    if inArgs('passive1') then
        passive1 = split(args.passive1)

        for k,v in spairs(tvals) do
            local dmg_name = k..'_passive1'
            local dmg_formula = v * passive1[1]
            pvals1[dmg_name] = dmg_formula
        end

        -- Useful separately
        for k,v in spairs(fvals) do
            if (string.find(k, 'useful')) then
                pvals1[k..'_passive1'] = v * passive1[1]
            end
        end

        -- Combine both passives.
        if inArgs('passive2') then
            for k,v in spairs(pvals1) do
                pvals12[k..'_passive2'] = v * passive2[1]
            end
        end

    end

    -- Merge all tables into one.
    tableMerge(fvals, tvals)
    tableMerge(fvals, pvals1)
    tableMerge(fvals, pvals2)
    tableMerge(fvals, pvals12)

    -- Get the actual variables with MW syntax.
    for k,v in spairs(fvals) do
        table.insert(vars, var(k, v))
    end

    -- Dump all values.
    local ret = {}
    for k,v in spairs(vars) do
        table.insert(ret, v)
    end

    return frame:preprocess(table.concat(ret, "<br/>"))

    -- return passive1[1]
    -- return frame:preprocess(table.concat(vars))
end

return p