Module:Most recent release

From Yugipedia
Revision as of 01:44, 29 November 2018 by Becasita (talk | contribs) (Parent args over current args always.)
Jump to: navigation, search
local DATA = require( 'Module:Data' );

local REGIONS = DATA( 'region' );

local UNKNOWN = '';

local MONTHS = {
	january   = 1,
	february  = 2,
	march     = 3,
	april     = 4,
	may       = 5,
	june      = 6,
	july      = 7,
	august    = 8,
	september = 9,
	october   = 10,
	november  = 11,
	december  = 12,
};

local CACHE = {
	medium = {};
};

local mwHtmlCreate = mw.html.create;

local function ask( query )
	query = query or {};

	if not query.mainlabel then
		query.mainlabel = '-';
	end

	local ask = mw.smw.ask( query );

	return ask and ask[ 1 ] or {};
end

local function parseDate( date )
	local day, month, year = date:match( '(%d+)%s*(%a+)%s*(%d+)' );

	if not day then
		month, year = date:match( '(%a+)%s*(%d+)' );
	end

	if not month then
		year = date:match( '(%d+)' );
	end

	return {
		day   = tonumber( day ) or 0,
		month = MONTHS[ month:lower() ] or 0,
		year  = tonumber( year ),
	};
end

--[[Doc
@description Less than 0 if date1 < date2
]]
local function compareDates( date1, date2 )
	date1 = parseDate( date1 );
	date2 = parseDate( date2 );

	if date1.year < date2.year then return -1 end
	if date1.year > date2.year then return  1 end

	if date1.month < date2.month then return -1 end
	if date1.month > date2.month then return  1 end

	if date1.day < date2.day then return -1 end
	if date1.day > date2.day then return  1 end

	return 0;
end

local function getReleaseDates( set )
	local res = {};

	for _, region in pairs( REGIONS ) do
		local prop = ('%s release date'):format( region.full );

		local dateInfo = ask{
			('[[%s]]'):format( set ),
			table.concat{ '?', prop },
		};

		-- TODO: remove when the sets store the Sneak Peek dates separately.
		local date = type( dateInfo[ prop ] ) == type( {} )
			and dateInfo[ prop ][ 1 ]
			or dateInfo[ prop ]
		;
		res[ region.full ] = date;
	end

	return res;
end

local function getSets( name )
	local res = {};

	local setInfo = ask{
		('[[%s]]'):format( name.page ),
		'?Set information (JSON)',
	};

	setInfo[ 'Set information (JSON)' ] = type( setInfo[ 'Set information (JSON)' ] ) == type( {} )
		and setInfo[ 'Set information (JSON)' ]
		or { setInfo[ 'Set information (JSON)' ] }
	;

	for index, value in ipairs( setInfo[ 'Set information (JSON)' ] ) do
		for set in value:gmatch( '"name": "(.-)"' ) do
			if not res[ set ] then
				res[ set ] = getReleaseDates( set );
			end
		end
	end

	return res;
end

local function getMostRecentReleases( name )
	local sets = getSets( name );

	local newest = {};

	for set, regions in pairs( sets ) do
		for region, date in pairs( regions ) do
			if not newest[ region ] or compareDates( newest[ region ].date, date ) < 0 then
				newest[ region ] = {
					date = date,
					set = set,
				}
			end

			CACHE.medium[ region ] = CACHE.medium[ region ] or DATA.getMedium( region ).abbr;
			local medium = CACHE.medium[ region ];
			if not newest[ medium ] or compareDates( newest[ medium ].date, date ) < 0 then
				newest[ medium ] = {
					date = date,
					set = set,
				}
			end
		end
	end

	return newest;
end

local function makeNameCell( name )
	return tostring(
		mwHtmlCreate( 'td' )
			:wikitext( ('"[[%s|%s]]"'):format( name.page, name.label ) )
		:done()
	);
end

local function makeDefaultCell()
	return  tostring(
		mwHtmlCreate( 'td' ):done()
	);
end

local function makeDataCell( data )
	return not data and makeDefaultCell() or tostring(
		mwHtmlCreate( 'td' )
			:wikitext( ("%s<br />(''[[%s]]'')"):format( data.date, data.set ) )
		:done()
	);
end

local function makeRow( name, mostRecentDates )
	local tr = mwHtmlCreate( 'tr' )
		:node( makeNameCell( name ) )
		:node( makeDataCell( mostRecentDates[ 'TCG' ] ) )
		:node( makeDataCell( mostRecentDates[ 'OCG' ] ) )
	;

	-- for _, region in pairs( REGIONS ) do
	-- 	local td = makeCell( mostRecentDates[ region.full ] );

	-- 	tr:node( td );
	-- end

	return tostring( tr:done() );
end

local function getName( name )
	local nameInfo = ask{
		('[[%s]]'):format( (name or ''):gsub( '#', '' ) ),
		'?Page name',
		'?English name',
	};

	return {
		page  = nameInfo[ 'Page name' ],
		label = nameInfo[ 'English name' ] or nameInfo[ 'Page name' ],
	};
end

local function process( name )
	name = getName( name );
	return name.page and makeRow( name, getMostRecentReleases( name ) )
end

local function processAll( data )
	local t = mwHtmlCreate( 'table' )
		:addClass( 'wikitable' )
		:addClass( 'sortable' )
		:addClass( 'most-recent-release-dates' )
		:tag( 'tr' )
			:tag( 'th' ):wikitext( 'Name' ):done()
			:tag( 'th' ):wikitext( "''TCG''" ):done()
			:tag( 'th' ):wikitext( "''OCG''" ):done()
		:done()
	;

	for _, result in ipairs( data ) do
		t:node( process( result[ 'Page name' ] ) );
	end

	return tostring( t:done() );
end

local function exec( limit, offset )
	if not mw.smw then
		return 'SMW is down...'
	end

	query = query or {
		'<q>[[Category:OCG cards]] OR [[Category:TCG cards]]</q>',
		'?Page name',
		'offset=' .. ( offset or 0 ),
		'limit=' .. ( limit or 5 ),
		'mainlabel=-'
	};

	local data = mw.smw.ask( query );

	return processAll( data );
end

return setmetatable(
	{
		main = function( frame )
			local parentArgs  = frame:getParent().args;
			local currentArgs = frame.args;

			local limit  = tonumber( parentArgs[ 1 ] )
				or tonumber( parentArgs[ 'limit' ] )
				or tonumber( currentArgs[ 1 ] )
				or tonumber( currentArgs[ 'limit' ] )
			;
			local offset = tonumber( parentArgs[ 2 ] )
				or tonumber( parentArgs[ 'offset' ] )
				or tonumber( currentArgs[ 2 ] )
				or tonumber( currentArgs[ 'offset' ] )
			;

			return limit
				and exec( limit, offset )
				or ('No valid limit... (%s)'):format( mw.dumpObject( limit ) );
		end
	},
	{
		__call = function( t, ... )
			return exec( ... );
		end
	}
);