Module:Utils

local p = {} local mathOps = require("Module:MathOps") local frame = mw.getCurrentFrame local _brigtnessTreshold = 0.36

function p.getCount(subject) local list --if you have another list just add it into a list then call appropriate function if		subject == "map"		then list = maps elseif	subject == "realm"		then list = realms elseif	subject == "killer"		then list = killers elseif	subject == "survivor"	then list = survivors elseif	subject == "dlc"		then list = dlcs elseif	subject == "chapter"	then return getCountDlcType(1) elseif	subject == "paragraph"	then return getCountDlcType(2) elseif	subject == "clothing"	then return getCountDlcType(3) elseif	subject == "ost"		then return getCountDlcType(4) elseif	subject == "character"	then return getCountDlcType(5) elseif	subject == "ccy"		then return getCountCCY(true) elseif	subject == "ccy-gc"		then return getCountCCY(true) --redundant option to keep convention elseif	subject == "ccy-rc"		then return getCountCCY(false) else return 0 end local x = 0 for _, item in ipairs(list) do if item.skip then x = x + 1 end end return #list - x end

function getCountDlcType(type) local count = 0 for i, dlc in ipairs(dlcs) do		if dlc.category == type and not dlc.skip then count = count + 1 end end return count end

function getCountCCY(gc) local list = ccy

local i = 0 while list[i + 1] and list[i + 1].gc == gc do i = i + 1 end

return i end

-- Function allowing for consistent treatment of boolean-like wikitext input. -- It works similarly to the template.

function p.bool(val, default) -- If your wiki uses non-ascii characters for any of "yes", "no", etc., you -- should replace "val:lower" with "mw.ustring.lower(val)" in the -- following line. val = type(val) == 'string' and val:lower or val if val == nil then return nil elseif val == true or val == 'yes' or val == 'y'		or val == 'true' or val == 't'		or val == 'on' or tonumber(val) == 1 then return true elseif val == false or val == 'no' or val == 'n'		or val == 'false' or val == 'f'		or val == 'off' or tonumber(val) == 0 then return false else return default end end

--Example usage: --amount = 1333444.1 --print(format_num(amount,2)) --print(format_num(amount,-2,"US$")) --amount = -22333444.5634 --print(format_num(amount,2,"$")) --print(format_num(amount,2,"$","")) --print(format_num(amount,3,"$","NEG "))

--Output: --1,333,444.10 --US$1,333,400 ---$22,333,444.56 --($22,333,444.56) --NEG $22,333,444.563

function p.format_num(amount, decimal, prefix, neg_prefix) local str_amount, formatted, famount, remain

decimal = decimal or 2 -- default 2 decimal places neg_prefix = neg_prefix or "-" -- default negative sign

famount = math.abs(mathOps.round(amount,decimal)) famount = math.floor(famount)

remain = mathOps.round(math.abs(amount) - famount, decimal)

-- comma to separate the thousands formatted = p.commaFormat(famount)

-- attach the decimal portion if (decimal > 0) then remain = string.sub(tostring(remain),3) formatted = formatted .. "." .. remain .. string.rep("0", decimal - string.len(remain)) end

-- attach prefix string e.g '$' formatted = (prefix or "") .. formatted

-- if value is negative then format accordingly if (amount<0) then if (neg_prefix=="") then formatted = "("..formatted ..")" else formatted = neg_prefix .. formatted end end

return formatted end

function p.commaFormat(amount) local formatted = amount while true do     formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2') if (k==0) then break end end return formatted end

--Converting Arabic numbers to Roman function ToRomanNumerals(s) local numbers = { 1, 5, 10, 50, 100, 500, 1000 } local chars = { "I", "V", "X", "L", "C", "D", "M" }

s = tonumber(s) if not s or s ~= s then error"Unable to convert to number" end if s == math.huge then error"Unable to convert infinity" end s = math.floor(s) if s <= 0 then return s end local ret = "" for i = #numbers, 1, -1 do       local num = numbers[i] while s - num >= 0 and s > 0 do           ret = ret .. chars[i] s = s - num end for j = 1, i - 1 do           local n2 = numbers[j] if s - (num - n2) >= 0 and s 0 and num - n2 ~= n2 then ret = ret .. chars[j] .. chars[i] s = s - (num - n2) break end end end return ret end

--Converting Roman numbers to Arabic function ToNumeral(roman) local Num = { ["M"] = 1000, ["D"] = 500, ["C"] = 100, ["L"] = 50, ["X"] = 10, ["V"] = 5, ["I"] = 1 } local numeral = 0 local i = 1 local strlen = string.len(roman) while i < strlen do       local z1, z2 = Num[ string.sub(roman,i,i) ], Num[ string.sub(roman,i+1,i+1) ] if z1 < z2 then numeral = numeral + ( z2 - z1 ) i = i + 2 else numeral = numeral + z1           i = i + 1 end end if i <= strlen then numeral = numeral + Num[ string.sub(roman,i,i) ] end return numeral end

function resolveNameWithRomanNumbers(str) local index = string.find(str, " [^ ]*$") + 1 local romanNumber = (string.sub(str, index)) local result if string.match(romanNumber, "[MDCLXVI]+$") then --finding ONLY Roman letters in last "word" --Cowshed mw.log(romanNumber) result = str --result = string.sub(str, 1, index - 1) .. ToNumeral(romanNumber) else mw.log("Non-Roman form") result = str end return result end

function p.CapitalizeName(str) return string.gsub(" "..str, "%W%l", string.upper):sub(2) end

function p.FirstLetterLower(str) return str:sub(1, 1):lower .. str:sub(2) end

function p.RemoveSpecialCharacters(str) str = string.gsub(str, "[']", "") str = string.gsub(str, "[®]", "") str = string.gsub(str, "[™]", "") str = string.gsub(str, "[:]", "") str = string.gsub(str, "[!]", "") --perks str = string.gsub(str, "[&]", "And") --probably can be changed to lower: "and" --Diacritics --str = string.gsub(str, "[ÁÂ]", "A") str = string.gsub(str, "[áâ]", "a") str = string.gsub(str, "[ÉĚ]", "E") str = string.gsub(str, "[éě]", "e") str = string.gsub(str, "[Í]", "I") str = string.gsub(str, "[í]", "i") str = string.gsub(str, "[Ó]", "O") str = string.gsub(str, "[ó]", "o") str = string.gsub(str, "[ÚŮ]", "U") str = string.gsub(str, "[úů]", "u") str = string.gsub(str, "[Ý]", "Y") str = string.gsub(str, "[ý]", "y") return str end

function p.isValidFileName(name) name = p.RemoveSpecialCharacters(name) return not (name == "" or not mw.title.new("File:" .. name .. ".png").exists) end

function p.resolveFileName(str, keepSpaces) keepSpaces = keepSpaces or false local result = "" result = string.lower(str) --mw.log(result) result = p.RemoveSpecialCharacters(result) --mw.log(result) result = p.CapitalizeName(result) if not keepSpaces then result = string.gsub(result, "[ ]", "") end --In future if there will be needed replace charactere such as "é" just add another substitution return result end function p.resolveImageName(name) if mw.title.new("File:" .. name .. ".png").exists then return name .. ".png" end if mw.title.new("File:" .. name .. ".jpg").exists then return name .. ".jpg" end return name .. ".png" end

function p.GetDisplayName(item) return (item.tName or item.name) end

function p.clr(text, color) return frame:expandTemplate{title = "clr", args = {color, text}} end

function p.resolveTextColorByBackground(hexBgColor) if(type(hexBgColor) == "table") then hexBgColor = hexBgColor.args[1] end local red = tonumber(string.sub(hexBgColor, 1, 2), 16) local green = tonumber(string.sub(hexBgColor, 3, 4), 16) local blue = tonumber(string.sub(hexBgColor, 3, 4), 16) local darkness = (0.299 * red + 0.587 * green + 0.114 * blue) / 255 mw.log("Red: " .. red .." | Blue: " .. blue .. " | Green: " .. green) mw.log(darkness) if(darkness < _brigtnessTreshold) then return "white" else return "black" end end

function p.getPageTitle return mw.title.getCurrentTitle.text end - function p.getSumOfASTiles(row) local result = 0 local i = 1 while row[i] do		result = result + row[i][1] -- hardcoded first variable in table i = i + 1 end return result end

function compASTiles(row1, row2) local sum1 = row1.ASTiles local sum2 = row2.ASTiles if(type(sum1) == "table") then sum1 = p.getSumOfASTiles(sum1) --converting back from table to number end if(type(sum2) == "table") then sum2 = p.getSumOfASTiles(sum2) end if sum1 > sum2 then return true elseif sum1 < sum2 then return false else if row1.realm < row2.realm then return true elseif row1.realm > row2.realm then return false else return resolveNameWithRomanNumbers(row1.name) < resolveNameWithRomanNumbers(row2.name) end end end

function compMapRateSize(row1, row2) return row1.size > row2.size --comparison specificly made for mapRates table end

function compName(row1, row2) return row1.name < row2.name end

function compInt(row1, row2) return row1 < row2 end

function p.sortMapsByASTiles local m = require("Module:Datatable") --mw.log(mw.dumpObject(maps)) table.sort(maps,compASTiles) --mw.log(mw.dumpObject(maps)) end

function p.sortMapRates(rankTable) --mw.log(mw.dumpObject(rankTable)) table.sort(rankTable, compMapRateSize) --mw.log(mw.dumpObject(rankTable)) end

function p.sortItemsByName(tableList) table.sort(tableList, compName) end

function p.sortTable(tableList) table.sort(tableList, compInt) end

-

function p.getCountOfSoundtracks return utils.getCount("ost") end

function p.resolveDateTime(datetime) --with weekday matchYear = "^(##)%.(##)%.(%d%d%d%d)$" matchMonth = "^(##)%.(%d%d)%.(%d%d%d%d)$" local rDate = os.time(p.GetDatetime(datetime)) if string.find(datetime, matchYear) then return os.date("%Y", rDate) elseif string.find(datetime, matchMonth) then return os.date("%B %Y", rDate) end return os.date("%d %B %Y (%A)", rDate) end

function p.IsFullDateTime(datestamp) local day, month, year = datestamp:match("^(..)%.(..)%.(....)$") if month == "##" or day == "##" or year == "####" then return false end return true end

function p.GetDatetime(datestamp) local day, month, year = datestamp:match("^(..)%.(..)%.(%d%d%d%d)$") if month == "##" then month = 1 end if day == "##" then day = 1 end return {year = year, month = month, day = day} end

function p.regularReplace(reggedString, regexTable) local result = "" local regexString = regex --"#pl%((%d)%)" -- looking and extracting number from "#pl(x)" for key, value in pairs(regexTable) do		reggedString = reggedString:gsub(key, value) end --for m in reggedString:gmatch(regex) do	--	mw.log(mw.dumpObject(m)) --	result = reggedString:gsub(regexString, "string") --	mw.log(result) --end return reggedString end

function p.getIcon(icon) mw.log(icon) if type(icon) == "table" then icon = icon.args[1] or mw.title.getCurrentTitle.text end require("Module:Datatable/Icons") mw.log(icon) for _, element in ipairs(icons) do		if icon == element.icon then mw.log(element.iconFile) return element.iconFile end end return icons[1].iconFile --Icon not found, then pick the first one which is supposed to be the Unknown one end

function p.getIconTest(icon) local iconR = "" if type(icon) == "table" then icon = icon.args[1] or mw.title.getCurrentTitle.text end require("Module:Datatable/Icons") for _, element in ipairs(icons) do iconR = iconR .. "icon [" .. icon .. "] == [" .. element.icon .. "] element.icon " if icon == element.icon then iconR = iconR .. "FOUND" return iconR end end iconR = iconR .. "NOT FOUND" return iconR end

--************************* survivors & killers ******************************--

function p.getCharacterById(id, charTable) for _, character in ipairs(charTable) do		if character.id == id then return character end end return "Character not found!" end

return p