local Public = {}

-- Get the mean value of a table
function Public.mean(t)
    local sum = 0
    local count = 0

    for k, v in pairs(t) do
        if type(v) == 'number' then
            sum = sum + v
            count = count + 1
        end
    end

    return (sum / count)
end

-- Get the mode of a table.  Returns a table of values.
-- Works on anything (not just numbers).
function Public.mode(t)
    local counts = {}

    for k, v in pairs(t) do
        if counts[v] == nil then
            counts[v] = 1
        else
            counts[v] = counts[v] + 1
        end
    end

    local biggestCount = 0

    for k, v in pairs(counts) do
        if v > biggestCount then
            biggestCount = v
        end
    end

    local temp = {}

    for k, v in pairs(counts) do
        if v == biggestCount then
            table.insert(temp, k)
        end
    end

    return temp
end

-- Get the median of a table.
function Public.median(t)
    local temp = {}

    -- deep copy table so that when we sort it, the original is unchanged
    -- also weed out any non numbers
    for k, v in pairs(t) do
        if type(v) == 'number' then
            table.insert(temp, v)
        end
    end

    table.sort(temp)

    -- If we have an even number of table elements or odd.
    if math.fmod(#temp, 2) == 0 then
        -- return mean value of middle two elements
        return (temp[#temp / 2] + temp[(#temp / 2) + 1]) / 2
    else
        -- return middle element
        return temp[math.ceil(#temp / 2)]
    end
end

-- Get the standard deviation of a table
function Public.standardDeviation(t)
    local m
    local vm
    local sum = 0
    local count = 0
    local result

    m = Public.mean(t)

    for k, v in pairs(t) do
        if type(v) == 'number' then
            vm = v - m
            sum = sum + (vm * vm)
            count = count + 1
        end
    end

    result = math.sqrt(sum / (count - 1))

    return result
end

-- Get the max and min for a table
function Public.maxmin(t)
    local max = -math.huge
    local min = math.huge

    for k, v in pairs(t) do
        if type(v) == 'number' then
            max = math.max(max, v)
            min = math.min(min, v)
        end
    end

    return max, min
end

return Public
