Puzzle Potato Dry Brush.png
UnNews Logo Potato1.png

Welcome to the Mother Ship of amateur comedy writing! (Amateur means we don't pay you to do it.)

This is where the original Uncyclopedia wound up. You might as well pick a user name. We have no "partners" that want to sell you stuff. Giving your email simply lets you recover your password; we don't send spam. Uncyclopedians get a talk page, private edit area, and a welcome, maybe, if you actually edit; and we won't de-platform you for your views, if they're funny.


Module:Weather box/row

From Uncyclopedia, the content-free encyclopedia
Jump to navigation Jump to search

To update this module against Wikipedia's version, copy the content of wikipedia:Module:Weather box and paste it into Uncyclopedia's Module:Weather box.


local w = {}
local math_mod = require('Module:Math')
local wbc = require('Module:Weather box/colors')

local traceText
local Value
Value = {
	lang = mw.getContentLanguage(),
	getDisplay = function (self, second)
		if not self:isValid() then
			return nil
		end
		local display = self.string
		if display == 'trace' then
			if second then
				-- If a cell displays "cm (inch)", show "trace" not "trace (trace)".
				return nil
			end
			return traceText or 'trace'
		end
		if math.abs(self.number) >= 1000 then
			display = self.lang:formatNum(math.abs(self.number))
			if self.number < 0 then
				display = '−' .. display
			end
		elseif self.number < 0 then
			display = '−' .. display:sub(2)
		end
		return display
	end,
	getPrecision = function (self)
		local result = rawget(self, 'precision')
		if not result then
			if self:isValid() then
				result = math.max(0, math_mod._precision(self.string))
			else
				result = 0
			end
			rawset(self, 'precision', result)
		end
		return result
	end,
	isValid = function (self)
		return self.number ~= nil and self.number ~= -9999
	end,
	new = function (v)
		local val, str, precision
		if type(v) == 'string' then
			if v == 'trace' then
				val, str, precision = 0, 'trace', 0
			else
				val, str = math_mod._cleanNumber(v)
			end
		elseif type(v) == 'number' then
			val, str = v, tostring(v)
		end
		if not val then
			val, str = -9999, ''
		end
		return setmetatable({
			number = val,
			string = str,
			precision = precision,
		}, Value)
	end,
	converts = {
		in2cm = { factor = 2.54              },
		in2mm = { factor = 25.4              },
		cm2in = { factor = 1/2.54, p2max = 1 },
		mm2in = { factor = 1/25.4, p2max = 0 },
	},
	setConvert = function (self, invalue, units)
		-- Use method modified from [[Module:Convert]] to determine precision.
		if invalue.string == 'trace' then
			self.number, self.string, self.precision = 0, 'trace', 0
			return
		end
		local convert = self.converts[units] or error('Unknown units')
		local outnum = invalue.number * convert.factor
		local precision = invalue:getPrecision()
		if outnum > 0 then
			local adjust = math.log10(1/convert.factor) + math.log10(2)
			local p1 = math.floor(precision + adjust)
			local p2 = 1 - math.floor(math.log10(outnum))
			if convert.p2max then
				p2 = math.min(p2, convert.p2max)
			end
			precision = math.max(p1, p2)
		end
		self:setNumberRounded(outnum, precision)
	end,
	setNumberRounded = function (self, number, precision)
		if precision > 2 then
			precision = 2
		end
		self.number = math_mod._round(number, precision)
		if precision < 0 then
			self.string = tostring(self.number)
		else
			local fmt = '%.' .. string.format('%d', precision) .. 'f'
			self.string = string.format(fmt, self.number)
		end
	end,
}
Value.__index = Value

local function checkFlag( flag, default )
	if flag == nil then
		return default
	elseif type( flag ) == 'boolean' then
		return flag
	elseif type( flag ) == 'string' then
		flag = flag:lower()
		if flag == '0' or flag == 'false' or
				flag == '' or flag == 'no' or
				flag == 'n' then
			return false
		else
			return true
		end
	else
		return error( 'Flag type not valid' )
	end
end

local function makeLine( label, first_values, second_values, color_values )
	local result = {'|- style="text-align: center;"\n! scope="row" style="height: 16px;" | ', label, "\n"}
	for i = 1,13 do
		local color_str = color_values[i]

		if i == 13 then
			table.insert( result, table.concat( {'|style="', color_str, ' border-left-width:medium" | '} ) )
		else
			table.insert( result, table.concat( {'|style="', color_str, '" | '} ) )
		end

		local display = first_values[i]:getDisplay()
		if display then
			table.insert( result, display )
			if second_values ~= nil then
				display = second_values[i]:getDisplay(true)
				if display then
					table.insert( result, "<br />(" .. display .. ")" )
				end
			end
		else
			table.insert( result, '—' )
		end

		table.insert( result, "\n" )
	end

	return table.concat( result )
end

local function getInputs( frame, group_name, suffix, include_space )
	local month_names = { 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
		'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'year' }
	local str
	local values = {}
	if suffix == nil then
		for i, mon in ipairs( month_names ) do
			if include_space then
				str = frame.args[ mon .. ' ' .. group_name ] or ''
			else
				str = frame.args[ mon .. group_name ] or ''
			end
			values[i] = Value.new(str)
		end
	else
		for i, mon in ipairs( month_names ) do
			local value, updated
			for var, suf in ipairs( suffix ) do
				if include_space then
					str = frame.args[ mon .. ' ' .. group_name .. ' ' .. suf ]
				else
					str = frame.args[ mon .. group_name .. ' ' .. suf ]
				end
				if str ~= nil and str ~= '' then
					value = Value.new(str)
					value.variant = var
					updated = true
					break
				end
			end
			if not updated then
				value = Value.new()
				value.variant = 0
			end
			values[i] = value
		end
	end
	return values
end

local function getAnnualValue( values, mode )
	if mode == 'avg' or mode == 'sum' then
		local total = 0
		local p1, p2, variant
		p1 = 0
		for i = 1, 12 do
			if not values[i]:isValid() then
				return Value.new()
			end
			if not variant then
				local var = values[i].variant
				if var and var ~= 0 then
					variant = var
				end
			end

			p2 = values[i]:getPrecision()
			if p2 > p1 then
				p1 = p2
			end

			total = total + values[i].number
		end
		local value = Value.new(total)
		if mode == 'avg' then
			value:setNumberRounded( total / 12, p1 )
		end
		value.variant = variant
		return value
	elseif mode == 'min' then
		local target
		for i = 1, 12 do
			if values[i]:isValid() then
				if target == nil or values[i].number < target.number then
					target = values[i]
				end
			end
		end
		return target or Value.new()
	elseif mode == 'max' then
		local target
		for i = 1, 12 do
			if values[i]:isValid() then
				if target == nil or values[i].number > target.number then
					target = values[i]
				end
			end
		end
		return target or Value.new()
	else
		error( 'Unrecognized Annual Mode' )
	end
end

local function reconcileTemperature( C_values, F_values )
	for i = 1,13 do
		local p
		if C_values[i].string == '' then
			if F_values[i]:isValid() then
				p = F_values[i]:getPrecision()
				C_values[i]:setNumberRounded( (F_values[i].number - 32)*5/9, p )
			end
		elseif F_values[i].string == '' then
			if C_values[i]:isValid() then
				p = C_values[i]:getPrecision()
				F_values[i]:setNumberRounded( C_values[i].number*9/5 + 32, p )
			end
		end
	end
end

local function reconcilePrecipitation( M_values, I_values, prefer_cm )
	local v_class = 0
	for i = 1,13 do
		if M_values[i].variant == 1 then
			v_class = 1
		elseif M_values[i].variant == 2 then
			v_class = 2
		end
	end
	if v_class == 0 then
		if prefer_cm then
			v_class = 1
		else
			v_class = 2
		end
	end
	for i = 1,13 do
		local units
		if M_values[i].string == '' then
			if I_values[i]:isValid() then
				if v_class == 1 then
					units = 'in2cm'
				else
					units = 'in2mm'
				end
				M_values[i]:setConvert( I_values[i], units )
				M_values[i].variant = v_class
			end
		elseif I_values[i].string == '' then
			if M_values[i]:isValid() then
				if M_values[i].variant == 1 then
					units = 'cm2in'
				else
					units = 'mm2in'
				end
				I_values[i]:setConvert( M_values[i], units )
			end
		end
	end
end

function w.buildRow( frame )
	local mode = (frame.args.mode or 'basic'):lower()
	local group_name = frame.args.group_name
	local first_values, second_values
	local color_values
	local color_scheme = frame.args.color_scheme or 't'
	local scale_factor = math_mod._cleanNumber( frame.args.scale_factor) or 1
	local date_mode = checkFlag( frame.args.date_mode, false )
	local label = frame.args.label or ''
	local annual_mode = (frame.args.annual_mode or 'avg'):lower()
	local include_space = checkFlag( frame.args.include_space, true )
	local second_line = checkFlag( frame.args.second_line, false )
	local prefer_cm = checkFlag( frame.args.prefer_cm, false )
	local pframe = frame:getParent()
	local imperial_first = checkFlag( frame.args['imperial first'] or pframe.args['imperial first'] )
	local metric_first = checkFlag( frame.args['metric first'] or pframe.args['metric first'] )
	local single_line = checkFlag( frame.args['single line'] or pframe.args['single line'] )
	local trace = pframe.args.trace
	if trace and trace ~= '' then
		traceText = trace
	end

	if imperial_first == nil then
		imperial_first = metric_first == nil and true or not metric_first
	end

	if mode == 'basic' then
		first_values = getInputs( pframe, group_name, nil, include_space )
		second_values = nil
	elseif mode == 'temperature' then
		first_values = getInputs( pframe, group_name, {'C'}, include_space )
		second_values = getInputs( pframe, group_name, {'F'}, include_space )
		reconcileTemperature( first_values, second_values )
	elseif mode == "precipitation" then
		first_values = getInputs( pframe, group_name, {'cm', 'mm'}, include_space )
		second_values = getInputs( pframe, group_name, {'inch'}, include_space )
		reconcilePrecipitation( first_values, second_values, prefer_cm )
	else
		error( 'Requested mode not recognized' )
	end

	local good = false
	for i = 1,13 do
		if first_values[i].string ~= '' then
			good = true
			break
		end
	end
	if not good then
		return ''
	end

	if first_values[13].string == '' then
		first_values[13] = getAnnualValue( first_values, annual_mode )
	end
	if second_values ~= nil then
		if second_values[13].string == '' then
			second_values[13] = getAnnualValue( second_values, annual_mode )
		end
	end

	color_scheme = wbc.interpret_color_code( color_scheme )

	color_values = {}
	local month_adj = { 31/30, 28.25/30, 31/30, 1, 31/30, 1,
		31/30, 31/30, 1, 31/30, 1, 31/30, 365.25/30 }
	for i = 1,13 do
		if first_values[i]:isValid() then
			local adj = scale_factor
			if date_mode then
				adj = adj / month_adj[i]
			end
			if mode == "precipitation" then
				if first_values[i].variant == 1 then
					adj = adj * 10
				end
			end
			table.insert( color_values, color_scheme( first_values[i].number * adj ) )
		else
			table.insert( color_values, color_scheme( nil ) )
		end
	end

	if imperial_first and second_values ~= nil then
		first_values, second_values = second_values, first_values
	end

	if not single_line then
		if second_line and second_values ~= nil then
			first_values = second_values
		end
		second_values = nil
	end

	return makeLine( label, first_values, second_values, color_values )
end

return w