Module:System

From IxWiki
Jump to navigation Jump to search

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

local System = {}

local Array = require( 'Module:Array' )
local Starmap = require( 'Module:Starmap_old' )
local Infobox = require( 'Module:InfoboxNeue' )
local TNT = require( 'Module:Translate' ):new()
local config = mw.loadJsonData( 'Module:System/config.json' )

local lang
if config[ 'module_lang' ] then
	lang = mw.getLanguage( config[ 'module_lang' ] )
else
	lang = mw.getContentLanguage()
end
local langCode = lang:getCode()

--- Wrapper function for Module:Translate.translate
-- @param key string The translation key
-- @param addSuffix boolean Adds a language suffix if config.smw_multilingual_text is true
-- @return string If the key was not found in the .tab page, the key is returned
local function t( key, addSuffix, ... )
	return TNT:translate( 'Module:System/i18n.json', config, key, addSuffix, {...} ) or key
end

--- Remove parentheses and their content
local function removeParentheses( inputString )
    return mw.ustring.match( mw.ustring.gsub( inputString, '%b()', '' ), '^%s*(.*%S)' ) or ''
end

--- Alternative for doing table[key][key], this returns nil instead of an error if it doesn't exist
-- @param table object
local function e( object, ... )
	local value = object
	if not value then return end
	for _, key in ipairs( { ... } ) do
		value = value[ key ]
		if value == nil then return nil end
	end
	return value
end

--- Does string end with x
-- @param str string
-- @param suffix string
-- @return boolean
local function endsWith( str, suffix )
    return mw.ustring.sub( str, -string.len( suffix ) ) == suffix
end

--- Does string start with x
-- @param str string
-- @param prefix string
-- @return boolean
local function startsWith( str, prefix )
    return mw.ustring.sub( str, 1, mw.ustring.len( prefix ) ) == prefix
end

--- Filter table
-- @param array table
-- @param key string
-- @param value any
-- @param zero any Value to return if zero matches
local function filter( array, key, value, zero )
	local matches = {}
	if array then
		for _, item in ipairs( array ) do
			if item[ key ] == value then
				table.insert( matches, item )
			end
		end
	end
	if zero and #matches == 0 then
		return zero
	else
		return matches
	end
end

--- Split a string with seperator
-- @param str string Input
-- @param sep string Seperator
local function split( str, sep )
	local matches = {}
	for str in mw.ustring.gmatch( str, '([^' .. sep .. ']+)' ) do
		table.insert( matches, mw.ustring.gsub( str, '%b()', '' ) or '' )
	end
	return matches
end

-- @param str string
local function trim( str )
    return mw.ustring.match( str, '([^:%(%s]+)' )
end

--- If but inline
-- @param condition boolean
-- @param truthy any What to return if true
-- @param falsy any What to return if false
local function inlineIf( condition, truthy, falsy )
	if not not condition then return truthy else return falsy end
end

-- @param categories table Plain text categories in array
local function convertCategories( categories )
	local mapped = {}
	for _, category in pairs( categories ) do
		if category ~= nil then
			if mw.ustring.sub( category, 1, 2 ) ~= '[[' then
				category = mw.ustring.format( '[[Category:%s]]', category )
			end
			
			table.insert( mapped, category )
		end
	end
	return table.concat( mapped )
end

--- Bypass for a bug
local function cuteArray( array )
	local newArray = {}
	for _, val in ipairs( array ) do 
		table.insert( newArray, val )
	end
	return newArray
end

-- @param frame table https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Frame_object
function System.main( frame )
	local args = frame:getParent().args
	local infobox = Infobox:new( { placeholderImage = config[ 'placeholder_image' ] } )
	
	--- The idea of this mega table is to get all data, then set it in the infobox, better organization.
	local mega = {
		[ 'image' ] = nil,
		[ 'name' ] = nil,
		[ '#name' ] = nil,
		[ 'code' ] = nil,
		[ 'system' ] = {},
		[ 'type' ] = nil,
		[ '#type' ] = nil,
		[ 'size' ] = nil,
		[ '#size' ] = nil,
		[ 'status' ] = nil,
		[ '#status' ] = nil,
		[ 'system_objects' ] = {},
		[ 'star_types' ] = {},
		[ '#star_types' ] = nil,
		[ 'affiliation' ] = {},
		[ '#affiliation' ] = nil,
		[ '#population' ] = nil,
		[ 'planet_count' ] = nil,
		[ 'satellite_count' ] = nil,
		[ 'asteroid_belt_count' ] = nil,
		[ 'asteroid_field_count' ] = nil,
		[ 'anomaly_count' ] = nil,
		[ 'station_count' ] = nil,
		[ 'jumppoint_count' ] = nil,
		[ 'blackhole_count' ] = nil,
		[ 'poi_count' ] = nil,
		[ 'sensor_danger' ] = nil,
		[ 'sensor_economy' ] = nil,
		[ 'sensor_population' ] = nil,
		[ 'discovered_in' ] = nil,
		[ 'discovered_by' ] = nil,
		[ 'historical_names' ] = {},
		[ '#historical_names' ] = nil,
		[ 'starmap_link' ] = nil,
		[ 'starmap_id' ] = nil,
		[ 'cornerstone_link' ] = nil,
		[ 'verseguide_link' ] = nil,
		[ 'categories' ] = {},
	}
	
	table.insert( mega[ 'categories' ], 'Systems' ) -- Default category for systems
	
	mega[ 'image' ] = args[ 'image' ]
	mega[ 'name' ] = args[ 'name' ]
	mega[ 'code' ] = args[ 'code' ]
	if mega[ 'name' ] == nil and mega[ 'code' ] == nil then
		return infobox:renderInfobox( infobox:renderMessage( { 
			title = t( 'error_title' ),
			desc = t( 'error_invalid_args_desc' )
		} ) )
	end
	
	--- Trim 'system' from the name
	if mega[ 'name' ] ~= nil and endsWith( mega[ 'name' ], 'system' ) then
		mega[ 'name' ] = trim( mw.ustring.sub( mega[ 'name' ], 1, -6 ) )
	end
	
	mega[ 'system' ] = Starmap.findStructure( 'system', mega[ 'code' ] or mega[ 'name' ] ) or {}
	if mega[ 'system' ] ~= nil then
		if mega[ 'name' ] == nil then mega[ 'name' ] = removeParentheses( mega[ 'system' ][ 'name' ] ) end
		mega[ 'code' ] = mega[ 'system' ][ 'code' ]
	end
	
	mega[ '#name' ] = mega[ 'name' ]
	--- Add ' system' to end of `#name`
	if endsWith( mega[ '#name' ], ' system' ) == false then
		mega[ '#name' ] = mega[ '#name' ] .. ' system'
	end
	
	mega[ 'type' ] = args[ 'type' ] or mega[ 'system' ][ 'type' ]
	if mega[ 'type' ] ~= nil then
		mega[ '#type' ] = t( 'val_type_' .. mw.ustring.lower( mega[ 'type' ] ) )
		table.insert( mega[ 'categories' ], mega[ '#type' ] .. ' systems' )
	end
	
	mega[ 'size' ] = args[ 'size' ] or mega[ 'system' ][ 'aggregated_size' ]
	if mega[ 'size' ] ~= nil and tonumber( mega[ 'size' ] ) then
		mega[ 'size' ] = tonumber( mega[ 'size' ] )
		mega[ '#size' ] = tostring( mega[ 'size' ] ) .. ' AU'
	else mega[ '#size' ] = '? AU' end
	
	mega[ 'status' ] = args[ 'status' ] or mega[ 'system' ][ 'status' ]
	if mega[ 'status' ] ~= nil then mega[ '#status' ] = t( 'val_status_' .. mw.ustring.lower( mega[ 'status' ] ) ) end
	
	mega[ 'system_objects' ] = Starmap.systemObjects( mega[ 'code' ] or mega[ 'name' ] )
	
	mega[ 'star_types' ] = args[ 'startypes' ]
	if mega[ 'star_types' ] then
		mega[ 'star_types' ] = split( mega[ 'star_types' ], ',' )
	elseif mega[ 'system_objects' ] then
		mega[ 'star_types' ] = {}
		for _, star in ipairs( filter( mega[ 'system_objects' ], 'type', 'STAR' ) ) do
			if star[ 'subtype' ] then
				table.insert( mega[ 'star_types' ], config[ 'subtype_rename' ][ star[ 'subtype' ][ 'name' ] ] or star[ 'subtype' ][ 'name' ] )
			end
		end
	else
		mega[ 'star_types' ] = {} -- Revert back to default
	end
	mega[ '#star_types' ] = table.concat( mega[ 'star_types' ], ', ' )
	
	if args[ 'affiliation' ] then
		mega[ 'affiliation' ] = split( args[ 'affiliation' ], ',' )
	elseif e( mega, 'system', 'affiliation' ) ~= nil then
		mega[ 'affiliation' ] = {}
		for _, empire in ipairs( mega[ 'system' ][ 'affiliation' ] ) do
			table.insert( mega[ 'affiliation' ], t( 'val_affiliation_' .. mw.ustring.lower( empire[ 'code' ] ) ) )
		end
	end
	if mega[ 'affiliation' ][ 1 ] then table.insert( mega[ 'categories' ], mega[ 'affiliation' ][ 1 ] .. ' systems' ) end
	mega[ '#affiliation' ] = {}
	for _, name in ipairs( mega[ 'affiliation' ] ) do
		table.insert( mega[ '#affiliation' ], mw.ustring.format( '[[%s]]', name ) )
	end
	mega[ '#affiliation' ] = table.concat( mega[ '#affiliation' ], ', ' )
	
	mega[ '#population' ] = args[ 'population' ]
	
	mega[ 'planet_count' ] = args[ 'planets' ] or #filter( mega[ 'system_objects' ], 'type', 'PLANET', nil )
	mega[ 'satellite_count' ] = args[ 'satellites' ] or #filter( mega[ 'system_objects' ], 'type', 'SATELLITE', nil )
	mega[ 'asteroid_belt_count' ] = args[ 'asteroidbelts' ] or #filter( mega[ 'system_objects' ], 'type', 'ASTEROID_BELT', nil )
	mega[ 'asteroid_fields_count' ] = args[ 'asteroidfields' ] or #filter( mega[ 'system_objects' ], 'type', 'ASTEROID_FIELDS', nil )
	mega[ 'anomaly_count' ] = args[ 'anomalies' ] or #filter( mega[ 'system_objects' ], 'type', 'ANOMALY', nil )
	mega[ 'station_count' ] = args[ 'stations' ] or #filter( mega[ 'system_objects' ], 'type', 'MANMADE', nil )
	mega[ 'jumppoint_count' ] = args[ 'jumppoints' ] or #filter( mega[ 'system_objects' ], 'type', 'JUMPPOINT', nil )
	mega[ 'blackholes_count' ] = args[ 'blackholes' ] or #filter( mega[ 'system_objects' ], 'type', 'BLACKHOLE', nil )
	mega[ 'poi_count' ] = args[ 'pois' ] or #filter( mega[ 'system_objects' ], 'type', 'POI', nil )
	
	mega[ 'sensor_danger' ] = args[ 'sensordanger' ] or e( mega[ 'system' ][ 'aggregated_danger' ] )
	if mega[ 'sensor_danger' ] ~= nil and mega[ 'sensor_danger' ] ~= 0 then
		mega[ 'sensor_danger' ] = tonumber( mega[ 'sensor_danger' ] )
		mega[ '#sensor_danger' ] = tostring( mega[ 'sensor_danger' ] ) .. '/10'
	else mega[ 'sensor_danger' ] = nil end
	
	mega[ 'sensor_economy' ] = args[ 'sensoreconomy' ] or e( mega[ 'system' ][ 'aggregated_economy' ] )
	if mega[ 'sensor_economy' ] ~= nil and mega[ 'sensor_economy' ] ~= 0 then
		mega[ 'sensor_economy' ] = tonumber( mega[ 'sensor_economy' ] )
		mega[ '#sensor_economy' ] = tostring( mega[ 'sensor_economy' ] ) .. '/10'
	else mega[ 'sensor_danger' ] = nil end
	
	mega[ 'sensor_population' ] = args[ 'sensorpopulation' ] or e( mega[ 'system' ][ 'aggregated_population' ] )
	if mega[ 'sensor_population' ] ~= nil and mega[ 'sensor_population' ] ~= 0 then
		mega[ 'sensor_population' ] = tonumber( mega[ 'sensor_population' ] )
		mega[ '#sensor_population' ] = tostring( mega[ 'sensor_population' ] ) .. '/10'
	else mega[ 'sensor_population' ] = nil end
	
	mega[ 'discovered_in' ] = args[ 'discoveredin' ]
	mega[ 'discovered_by' ] = args[ 'discoveredby' ]
	mega[ 'historical_names' ] = args[ 'historicalnames' ]
	if mega[ 'historical_names' ] then
		mega[ 'historical_names' ] = split( mega[ 'historical_names' ], ',' )
		mega[ '#historical_names' ] = table.concat( mega[ 'historical_names' ], ', ' )
	else
		mega[ 'historical_names' ] = {} -- Revert back to default
	end
	
	mega[ 'starmap_link' ] = args[ 'starmap' ]
	if mega[ 'starmap_link' ] == nil and mega[ 'code' ] then mega[ 'starmap_link' ] = Starmap.link( mega[ 'code' ] ) end
	mega[ 'starmap_id' ] = e( mega, 'system', 'id' )
	mega[ 'cornerstone_link' ] = args[ 'cornerstone' ]
	if mega[ 'cornerstone_link' ] == nil and Array.contains( cuteArray( config[ 'cornerstone_systems' ] ), mega[ 'code' ] ) then mega[ 'cornerstone_link' ] = mw.ustring.format( config[ 'cornerstone' ], mega[ 'name' ] ) end
	mega[ 'verseguide_link' ] = args[ 'verseguide' ]
	if mega[ 'verseguide_link' ] == nil and Array.contains( cuteArray( config[ 'verseguide_systems' ] ), mega[ 'code' ] ) then mega[ 'verseguide_link' ] = mw.ustring.format( config[ 'verseguide' ], string.upper( mega[ 'name' ] ) ) end
	
	infobox:renderImage( mega[ 'image' ] )
	infobox:renderHeader( {
		title = mega[ '#name' ],
		subtitle = mega[ '#affiliation' ]
	} )
	infobox:renderSection( {
		content = {
			infobox:renderItem( {
				label = t( 'lbl_type' ),
				data = mega[ '#type' ],
			} ),
			infobox:renderItem( {
				label = t( 'lbl_size' ),
				data = mega[ '#size' ],
			} ),
			infobox:renderItem( {
				label = t( 'lbl_status' ),
				data = mega[ '#status' ],
			} ),
			infobox:renderItem( {
				label = inlineIf( #mega[ 'star_types' ] == 1, t( 'lbl_star_type' ), t( 'lbl_star_types' ) ),
				data = mega[ '#star_types' ],
			} ),
			infobox:renderItem( {
				label = t( 'lbl_population' ),
				data = mega[ '#population' ],
			} ),
		},
		col = 2
	} )
	infobox:renderSection( {
		title = t( 'lbl_astronomical_objects' ),
		content = {
			infobox:renderItem( {
				label = t( 'lbl_planets' ),
				data = inlineIf( (mega[ 'planet_count' ] or nil) ~= 0, mega[ 'planet_count' ] or nil, nil )
			} ),
			infobox:renderItem( {
				label = t( 'lbl_satellites' ),
				data = inlineIf( (mega[ 'satellite_count' ] or nil) ~= 0, mega[ 'satellite_count' ] or nil, nil )
			} ),
			infobox:renderItem( {
				label = t( 'lbl_asteroid_belts' ),
				data = inlineIf( (mega[ 'asteroid_belt_count' ] or nil) ~= 0, mega[ 'asteroid_belt_count' ] or nil, nil )
			} ),
			infobox:renderItem( {
				label = t( 'lbl_asteroid_fields' ),
				data = inlineIf( (mega[ 'asteroid_field_count' ] or nil) ~= 0, mega[ 'asteroid_field_count' ] or nil, nil )
			} ),
			infobox:renderItem( {
				label = t( 'lbl_anomalies' ),
				data = inlineIf( (mega[ 'anomaly_count' ] or nil) ~= 0, mega[ 'anomaly_count' ] or nil, nil )
			} ),
			infobox:renderItem( {
				label = t( 'lbl_stations' ),
				data = inlineIf( (mega[ 'station_count' ] or nil) ~= 0, mega[ 'station_count' ] or nil, nil )
			} ),
			infobox:renderItem( {
				label = t( 'lbl_jump_points' ),
				data = inlineIf( (mega[ 'jumppoint_count' ] or nil) ~= 0, mega[ 'jumppoint_count' ] or nil, nil )
			} ),
			infobox:renderItem( {
				label = t( 'lbl_blackholes' ),
				data = inlineIf( (mega[ 'blackhole_count' ] or nil) ~= 0, mega[ 'blackhole_count' ] or nil, nil )
			} ),
			infobox:renderItem( {
				label = t( 'lbl_pois' ),
				data = inlineIf( (mega[ 'poi_count' ] or nil) ~= 0, mega[ 'poi_count' ] or nil, nil )
			} )
		},
		col = 3
	} )
	if mega[ 'sensor_danger' ] ~= 0 and mega[ 'sensor_economy' ] ~= 0 and mega[ 'sensor_population' ] ~= 0 then
		infobox:renderSection( {
			title = t( 'lbl_sensors' ),
			content = {
				infobox:renderItem( {
					label = t( 'lbl_sensor_danger' ),
					data = mega[ '#sensor_danger' ]
				} ),
				infobox:renderItem( {
					label = t( 'lbl_sensor_economy' ),
					data = mega[ '#sensor_economy' ]
				} ),
				infobox:renderItem( {
					label = t( 'lbl_sensor_population' ),
					data = mega[ '#sensor_population' ]
				} )
			},
			col = 3
		} )
	end
	infobox:renderSection( {
		title = t( 'lbl_history' ),
		content = {
			infobox:renderItem( {
				label = t( 'lbl_discovered_in' ),
				data = mega[ 'discovered_in' ],
			} ),
			infobox:renderItem( {
				label = t( 'lbl_discovered_by' ),
				data = mega[ 'discovered_by' ],
			} ),
			infobox:renderItem( {
				label = inlineIf( #mega[ 'historical_names' ] == 1, t( 'lbl_historical_name' ), t( 'lbl_historical_names' ) ),
				data = mega[ '#historical_names' ],
			} )
		},
		col = 2
	} )
	infobox:renderSection( {
		class = 'infobox__section--metadata infobox__section--hasBackground',
		content = {
			infobox:renderItem( {
				label = t( 'lbl_starmap_id' ),
				data = mega[ 'starmap_id' ],
				row = true,
				spacebetween = true
			} ),
			infobox:renderItem( {
				label = t( 'lbl_starmap_code' ),
				data = mega[ 'code' ],
				row = true,
				spacebetween = true
			} ),
		}
	} )
	infobox:renderFooter( {
		button = {
			icon = 'WikimediaUI-Globe.svg',
			label = t( 'lbl_other_sites' ),
			type = 'popup',
			content = infobox:renderSection( {
				content = {
					infobox:renderItem( {
						label = t( 'lbl_official_sites' ),
						data = infobox:renderLinkButton( {
							label = t( 'lbl_starmap' ),
							link = mega[ 'starmap_link' ]
						} )
					} ),
					infobox:renderItem( {
						label = t( 'lbl_community_sites' ),
						data = infobox:renderLinkButton( {
							label = t( 'lbl_cornerstone' ),
							link = mega[ 'cornerstone_link' ]
						} ) .. infobox:renderLinkButton( {
							label = t( 'lbl_verseguide' ),
							link = mega[ 'verseguide_link' ]
						} )
					} ),
				},
				class = 'infobox__section--linkButtons',
			}, true )
		}
	} )


	mw.smw.set( {
		[ t( 'lbl_starmap_id' ) ] = mega[ 'starmap_id' ],
		[ t( 'lbl_starmap_code' ) ] = mega[ 'code' ],
		[ t( 'lbl_system_type' ) ] = mega[ 'type' ],
		[ t( 'lbl_system_size' ) ] = mega[ 'size' ],
		[ t( 'lbl_system_status' ) ] = mega[ 'status' ],
		[ t( 'lbl_star_type' ) ] = mega[ 'star_types' ]
	} )

	if mega[ 'planet_count' ] ~= nil and mega[ 'planet_count' ] ~= 0 and mega[ '#type' ] ~= nil then
		frame:callParserFunction( 'SHORTDESC', mw.ustring.format( 
			inlineIf( mega[ 'planet_count' ] == 1, t( 'shortdesc_1_singular' ), t( 'shortdesc_1_plural' ) ), 
			string.gsub( mw.ustring.lower( mega[ '#type' ] ), '^%l', mw.ustring.upper ),
			mega[ 'planet_count' ]
		) )
	elseif (mega[ 'planet_count' ] == nil or mega[ 'planet_count' ] == 0) and mega[ '#type' ] ~= nil then
		frame:callParserFunction( 'SHORTDESC', mw.ustring.format( 
			t( 'shortdesc_2' ),
			string.gsub( mw.ustring.lower( mega[ '#type' ] ), '^%l', mw.ustring.upper )
		) )
	elseif mega[ 'planet_count' ] ~= nil and mega[ 'planet_count' ] ~= 0 then
		frame:callParserFunction( 'SHORTDESC', mw.ustring.format( 
			inlineIf( mega[ 'planet_count' ] == 1, t( 'shortdesc_3_singular' ), t( 'shortdesc_3_plural' ) ), 
			mega[ 'planet_count' ]
		) )
	else frame:callParserFunction( 'SHORTDESC', t( 'shortdesc_4' ) ) end

	return tostring( infobox:renderInfobox( nil, mega[ '#name' ] ) ) .. convertCategories( mega[ 'categories' ] )
end

function System.test( name )
	if not name then name = 'Stanton' end -- System and Star
	System.main( { [ 'getParent' ] = function() return { [ 'args' ] = { [ 'name' ] = name } } end } )
end

return System