--- This is the Shindo module. Named after the Japanese term used for classifying earthquakes , this module provides utility for seismic intensity scales.
---
-- Seismic intensity data generated on Module:Shindo/data. Messages on Module:Shindo/messages.
-- @module shindo
-- @alias p
-- @require Module:Arguments
-- @require Module:MakeInvokeFunc
-- @require Module:Message
-- @require Module:Yesno
-- @release beta
---  
local p = {}
local getArgs = require("Module:Arguments").getArgs
local data = mw.loadData("Module:Shindo/data")
local messages = mw.loadData("Module:Shindo/messages")
local makeInvokeFunc = require("Module:MakeInvokeFunc")(p)
local message = require("Module:Message")(messages)
local yn = require("Module:Yesno")  
--- Gets the grayscale value of a specific color
-- @function getValueOfColor
-- @param {table} tbl table for colors
-- @param {number} tbl[1] red value
-- @param {number} tbl[2] green value
-- @param {number} tbl[3] blue value
-- @return {number} Decimal value of the color.
local function getValueOfColor(tbl)
return (tbl[1] + tbl[2] + tbl[3]) / 3 / 255
end  
--- Gets the color as a comma-separated value for CSS
-- @function rgbColor
-- @todo compute alpha transparency for dark mode, etc.
-- @param {table} tbl table for colors
-- @param {number} tbl[1] red value
-- @param {number} tbl[2] green value
-- @param {number} tbl[3] blue value
-- @return {string} The color in the format red, green, blue
local function rgbColor(tbl)
return tbl[1] .. (tbl[2] and ", " .. tbl[2] .. (tbl[3] and ", " .. tbl[3] or "") or "")
end  
--- Gets the average of multiple colors
-- @function averageColor
-- @param {table} tbl table of multiple colors
-- @return {number} Decimal value of the color.
local function averageColor(tbl)
local colors = {}
for k,v in pairs(tbl) do
colors[k] = v
end
local avg = {0, 0, 0}
for _,color in pairs(colors) do
avg[1] = avg[1] + color[1]
avg[2] = avg[2] + color[2]
avg[3] = avg[3] + color[3]
end
avg[1] = math.ceil(avg[1] / #colors) - avg[1] / #colors > 0.5 and math.floor(avg[1] / #colors) or math.ceil(avg[1] / #colors)
avg[2] = math.ceil(avg[2] / #colors) - avg[2] / #colors > 0.5 and math.floor(avg[2] / #colors) or math.ceil(avg[2] / #colors)
avg[3] = math.ceil(avg[3] / #colors) - avg[3] / #colors > 0.5 and math.floor(avg[3] / #colors) or math.ceil(avg[3] / #colors)
return avg
end  
--- Gets all the intensity values from a scale
-- @function listIntensitiesFromScale
-- @param {string} scale First scale name
-- @param {string} intensities Table of intensity values
-- @param {boolean} labelScale Whether to label a scale
-- @param {string} scale Second scale name
-- @return {string} List of intensities
local function listIntensitiesFromScale(scale, intensities, labelScale, scale2)
local out = ''
if yn(labelScale) then
out = out .. data[scale].short .. ' '
end
local categoriesAreSame = true
local category = ""
for k,v in pairs(intensities) do
if data[scale].ranks[v] == nil then error(message("invalidIntensity", {v, scale})) end
out = out .. data[scale].ranks[v].label
if k ~= #intensities then
if #intensities == 2 then
out = out .. '–'
else
out = out .. '/'
end
end
if category == "" and categoriesAreSame then
category = data[scale].ranks[v].category or ""
end
categoriesAreSame = categoriesAreSame and category ~= "" and (data[scale].ranks[v].category and data[scale].ranks[v].category == category or false)
end
if categoriesAreSame and category ~= "" and not scale2 then
out = out .. " (*" .. category .. "*)"
end
return out
end  
--- Gets the inline CSS for a particular scale's intensity color
-- @function p._color
-- @param {table} args arguments
-- @param {string} args.scale The name of the scale
-- @param {string} args.intensity The intensity of the scale
-- @return {string} Preprocessed text output
p._color = function(args)
local scale = string.lower(args.scale or args[1] or error(message("noScaleShortCode")))
local intensity = string.upper(args.intensity or args[2] or error(message("noIntensity")))
if data[scale] == nil then error(message("invalidScale", {scale})) end
if data[scale].ranks[intensity] == nil then error(message("invalidIntensity", {intensity, scale})) end
local order = data[scale].ranks[intensity].order
local color = data[scale].colors[order]
local colorIntensity = getValueOfColor(color)
return 'background-color:rgb(' .. rgbColor(color) .. '); color:' .. (colorIntensity < 0.5 and "white" or "black") .. ";"
end  
--- Gets the format of the scale as a wikitable
-- @function p._formatInWikitable
-- @param {table} args arguments
-- @param {string} args.scale The name of the scale
-- @param {string} args.intensity The intensity of the scale
-- @param {string} args.tagProps additional properties for the wikitable row
-- @param {boolean} args.header if the formatting is done as a header
-- @param {boolean} args.link whether to link to the scale page
-- @param {boolean} args.labelScale whether to include the name of the scale
-- @return {string} Preprocessed text output
p._formatInWikitable = function(args)
local scale = string.lower(args.scale or args[1] or error(message("noScaleShortCode")))
local link = args.link ~= nil and args.link or true
local labelScale = args.labelScale ~= nil and args.labelScale or true
local doColor = args.color ~= nil and args.color or true
local intensity = string.upper(args.intensity or args[2] or error(message("noIntensity")))
local intensities = mw.text.split(intensity, "/") or { intensity }
if data[scale] == nil then error(message("invalidScale", {scale})) end
local colors = {}
for k,v in pairs(intensities) do
local order = data[scale].ranks[v].order
colors[k] = data[scale].colors[order]
end
local color = averageColor(colors)
local colorIntensity = getValueOfColor(color)
local out = ""
if yn(args.header or false) then
out = out .. "! "
else
out = out .. "| "
end
out = out .. (args.tagProps ~= nil and args.tagProps or "")
if (yn(doColor)) then
out = out .. 'white" or "black") .. ';' .. (args.style or "") .. '" | '
elseif (args.style) then
out = out .. '") .. '" | '
end
if yn(link) then
out = out .. '[[' .. data[scale].name .. "#" .. data[scale].id_prefix .. data[scale].ranks[intensity].id .. "|"
end
if yn(doColor) then
out = out .. '<span style=\"color:' .. (colorIntensity < 0.5 and "white" or "black") .. ';">'
end
out = out .. listIntensitiesFromScale(scale, intensities, labelScale, false)
if yn(doColor) then
out = out .. '</span>'
end
if yn(link) then
out = out .. "]]"
end
return out
end  
--- Gets the format of the scale as a tag
-- @function p._formatTag
-- @param {table} args arguments
-- @param {string} args.scale The name of the scale
-- @param {string} args.scale2 The name of a second scale
-- @param {string} args.intensity The intensity of the scale
-- @param {string} args.intensity2 The intensity for the second scale
-- @param {string} args.tag Tag name
-- @param {string} args.style styling for the tag
-- @param {string} args.tagProps additional properties for the tag
-- @param {boolean} args.color Whether to color the entry
-- @param {boolean} args.link whether to link to the scale page
-- @return {string} Preprocessed text output
p._formatTag = function(args)
local scale = string.lower(args.scale or args[1] or error(message("noScaleShortCode")))
local scale2 = args.scale2 or args[3] or nil
if scale2 ~= nil then scale2 = string.lower(scale2) end
local link = args.link ~= nil and args.link or true
local labelScale = args.labelScale ~= nil and args.labelScale or true
local doColor = args.color ~= nil and args.color or true
local intensity = string.upper(args.intensity or args[2] or error(message("noIntensity")))
local intensities = mw.text.split(intensity, "/") or { intensity }
local intensity2 = args.intensity2 or args[4] or (scale2 and error(message("noIntensity"))) or nil
local intensities2 = {}
if intensity2 ~= nil then
intensity2 = string.upper(intensity2)
intensities2 = mw.text.split(intensity2, "/") or { intensity2 }
end