bee swarm simulator

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

-- DECLARATIONS
local p = {}

-- libraries
local getArgs = require('Dev:Arguments').getArgs
local tabber = require('Module:Tabber')._main

-- system functions
local str_gsub = string.gsub
local str_lower = string.lower
local mth_fmod = math.fmod
local mth_rand = math.random
local mth_randseed = math.randomseed

-- data
local data = mw.loadData('Module:Item data')

-- constants
local MOD = 1000000007
local timeSeed = mth_fmod(os.time(os.date('*t')), MOD)
local darkBackground = '#0e191a'
local lightBackground = '#ffffff'

-- HELPER FUNCTIONS
-- copy a table
-- Source - https://stackoverflow.com/a/16077650
local function deepcopy(o, seen)
  seen = seen or {}
  if o == nil then return nil end
  if seen[o] then return seen[o] end

  local no
  if type(o) == 'table' then
    no = {}
    seen[o] = no

    for k, v in next, o, nil do
      no[deepcopy(k, seen)] = deepcopy(v, seen)
    end
    setmetatable(no, deepcopy(getmetatable(o), seen))
  else -- number, string, boolean, etc
    no = o
  end
  return no
end
-- dealing with truthy/falsy value\
local function conditional(value)
	local falsy = {0, "", false}
	for _, fal in pairs(falsy) do 
		if (value == fal) then
			return false
		end
	end
	return (value ~= nil) 
end
-- sorted pairs()
local function spairs(t, order)
    local keys = {}
    for k in pairs(t) do keys[#keys+1] = k end

    if order then
        table.sort(keys, function(a,b) return order(t, a, b) end)
    else
        table.sort(keys)
    end

    local i = 0
    return function()
        i = i + 1
        if keys[i] then
            return keys[i], t[keys[i]]
        end
    end
end
-- get CSS class from name
local function getCSSClassName(name)
	return 'color-template-' .. str_gsub(str_lower(name), '%s+', '-')
end
-- get size of table
local function getTableSize(t)
    local count = 0
    for _, _ in pairs(t) do
        count = count + 1
    end
    return count
end
-- hash a string (for seed generation)
local function hash(str)
    local h = 5381

    for i = 1, #str do
       h = mth_fmod(h*32 + h + str:byte(i), MOD)
    end
    return h
end

-- extra constants
local nameList = data.nameList
local cntNames = getTableSize(nameList)

-- MAIN FUNCTIONS
-- checks if name is legal (not empty and exists in database)
function p.checkName(name)
	return not ((not name) or (not data.possibleInputs[name]))
end
-- creates element
function p.span(name, display, extra, noLink)
	if (not p.checkName(name)) then
		return error('Template error! ' .. (name or '<blank or nil>') .. ' not found in database')
	end
	
	-- prepare variables
	local entry = data.possibleInputs[name]
	local classString = 'color-template ' 
					  .. getCSSClassName(name) 
					  .. (entry["backgroundClip"] and ' color-template-background-clip' or '')
	local text = (conditional(display) and display or name) 
	extra = (conditional(extra) and extra or '')
	
	-- generate span
	local spanString ='<span class="' .. classString .. '">' .. text .. '</span>'
	if entry["noLink"] or noLink then 
		return spanString .. extra
	end
	local pageName = (conditional(entry["customLink"]) and str_gsub(entry["customLink"], '$1', name)) 
				  or name
	return '[[' .. pageName .. '|' .. spanString .. ']]' .. extra
end
-- creates element (AF edition)
function p.AFspan(name, display, extra, noLink)
	if (not p.checkName(name)) then
		return error('Template error! ' .. (name or '<blank or nil>') .. ' not found in database')
	end

	-- set random seed
	local elementHash = hash((name or '') .. (display or '') .. (extra or '') .. (noLink or ''))
	local seed = mth_fmod(timeSeed * elementHash, MOD)
	mth_randseed(seed)
	
	-- prepare variables
	local entry = data.possibleInputs[name]
	local text = (conditional(display) and display or name)
	
	-- generate span
	local AFname = nameList[mth_rand(cntNames)]
	local pageName = (conditional(entry["customLink"]) and str_gsub(entry["customLink"], '$1', name)) 
				  or name
	local ret = str_gsub(p.span(AFname, text, extra, noLink), "%[%[[%a%A]+|", "[[" .. pageName .. "|")
	return ret
end
-- main function
function p.main(frame)
	local args = getArgs(frame, {
		wrapper = 'Template:Color', 
		parentOnly = true, 
		removeBlanks = true, 
	})
	local span = data.isAprilFools and p.AFspan or p.span
	
	if (args["multi"]) then
		local ret = ""
		local i = 1
		while args["name" .. i] do
			ret = ret .. span(args["name" .. i], args["display" .. i], 
							  args["extra" .. i], args["noLink" .. i])
			i = i + 1
		end
		return ret
	end
	return span(args[1], args[2], args[3], args[4])
end

-- TEST SUITE
-- test function (copy of main but can be called from outside template)
function p.test(frame)
	local args = getArgs(frame, {
		wrapper = 'Template:Color', 
		parentOnly = true, 
		removeBlanks = true, 
	})
	local span = data.isAprilFools and p.AFspan or p.span
	
	if (args["multi"]) then
		local ret = ""
		local i = 1
		while args["name" .. i] do
			ret = ret .. span(args["name" .. i], args["display" .. i], 
							  args["extra" .. i], args["noLink" .. i])
			i = i + 1
		end
		return ret
	end
	return span(args[1], args[2], args[3], args[4])
end
-- display table with all possible inputs
function p.docsTable()
	local output = { '{| class="wikitable mw-collapsible COLORTEMPLATE_THEME"',
		'|+ Possible inputs<br/><small>(sorted in alphabetic order)</small>',
	}
	local counter = 0
	local span = data.isAprilFools and p.AFspan or p.span
	for item, entry in spairs(data.possibleInputs) do
		if counter == 0 then
			output[#output + 1] = '|- COLORTEMPLATE_STYLE'
		end
		
		local link = (entry["noLink"] and '\'\'No link\'\'')
		or '[[' .. ((conditional(entry["customLink"]) and str_gsub(entry["customLink"], '$1', item)) or item) .. ']]'

		output[#output + 1] = '| ' .. p.span(item) .. '<br/><small>\'\'\'Link\'\'\': ' .. link .. '</small><br/><small>\'\'\'CSS class\'\'\': ' .. getCSSClassName(item) .. '</small>'
		
		counter = mth_fmod(counter + 1, 5)
	end
	output[#output + 1] = '|}'
	
	local outputDark = deepcopy(output)
	local outputLight = deepcopy(output)
	outputDark = str_gsub(table.concat(outputDark, '\n'), "COLORTEMPLATE_STYLE", ' style="color:white;background-color:' .. darkBackground .. '"')
	outputDark = str_gsub(outputDark, "COLORTEMPLATE_THEME", "theme-fandomdesktop-dark")
	outputLight = str_gsub(table.concat(outputLight, '\n'), "COLORTEMPLATE_STYLE",' style="color:black;background-color:' .. lightBackground .. '"')
	outputLight = str_gsub(outputLight, "COLORTEMPLATE_THEME", "theme-fandomdesktop-light")
	mw.log(outputDark)
	
	output = {}
	output["centerTabs"] = 1;
	output[1] = "Dark theme"
	output[2] = outputDark
	output[3] = "Light theme"
	output[4] = outputLight
	
	return tabber(output)
end

return p