Jump to content

Module:EUPP seats/sandbox

From Wikipedia, the free encyclopedia

  1. ^ "European People's Party". Authority for European Political Parties and European Political Foundations. Retrieved 4 November 2024.
require ('strict');
local get_args = require ('Module:Arguments').getArgs;							-- function to fetch frame and parent frame arguments
local cfg = mw.loadData ('Module:EUPP seats/config');							-- defines, configuration data, and i18n support
local namespace = mw.title.getCurrentTitle().namespace;							-- used for categorization


--[[==========================< S E C T I O N _ 1 : F U N C T I O N A L _ F U N C T I O N S >=======================]]

--[[--------------------------< S U B S T I T U T E >----------------------------------------------------------

Substitutes $1, $2, etc in <message> with data from <data_t>. Returns plain-text substituted string when
<data_t> not nil; returns <message> else.

]]

local function substitute (message, data_t)
	return data_t and mw.message.newRawMessage (message, data_t):plain() or message;
end


--[[--------------------------< M A K E _ E R R O R _ M S G >--------------------------------------------------

Assembles an error message from template name, message text, help link, and error category.

]]

local function make_error_msg (msg, template_name, nocat)
	local category;

	local category_link = ((0 == namespace) and not nocat) and substitute ('[[Category:$1]]', {cfg.settings_t.err_category}) or '';
	return substitute ('<span style="color:#d33">Error: &#x7B;{$1}}: $2 ([[:Template:$1|$3]])</span>$4',
		{
		template_name or cfg.settings_t.template_name or frame:getParent():getTitle(),	-- the template name without namespace
		msg,																	-- the error message
		cfg.settings_t.help,													-- help wikilink display text
		category_link															-- link to error category (main namespace only)
		})
end
	

--[[--------------------------< R O U N D >--------------------------------------------------------------------

return the rounded value of the arguments with two digits

]]

local function round (n)
  return math.floor(100 * n + 0.5) / 100										-- round argument to two decimals
end


--[[--------------------------< S T R I P _ U R L >--------------------------------------------------------------------

return the stripped down URL

]]

local function strip_URL (URL)
	local new_URL = URL;
	local patterns_t = {'^https://www.', '^http://www.', '^https://', '^http://', '/$'};				-- valid <width> patterns
	for i, pattern in ipairs (patterns_t) do									-- loop through the patterns in <patterns_t>
		new_URL = new_URL.gsub(new_URL, pattern, "");
	end
	return "[" .. URL .. " " .. new_URL .. "]"
end



--[[==========================< S E C T I O N _ 2 : V A L I D A T I O N _ F U N C T I O N S >=======================]]

--[[--------------------------< V A L I D A T E _ W I D T H >--------------------------------------------------

validates data format for width parameter (for composition bar()); returns boolean true when valid; nil else

]]

local function validate_width (width)
	local patterns_t = {'^%d+$', '^%d+px$', '^%d+%%$', '^%d+em$'};				-- valid <width> patterns
	for i, pattern in ipairs (patterns_t) do									-- loop through the patterns in <patterns_t>
		if width:match (pattern) then											-- is there a match?
			return true;														-- yes, done
		end
	end
end


--[[--------------------------< S T R I P _ H O U S E _ T Y P E >----------------------------------------------

strips down parts of the house type (for calls relating to lower and upper houses)

]]

local function harmonise_lower_upper_house_name (house_type)
	if house_type == "LOWER-HOUSE" or house_type == "LOWER" or house_type == "MS-LOWER-HOUSE"then	-- three accepted formats for input
		return "LOWER_HOUSE";													-- format actually used in the code
	elseif house_type == "UPPER-HOUSE" or house_type == "UPPER" or house_type == "MS-UPPER-HOUSE" then		-- three accepted formats for input
		return "UPPER_HOUSE";													-- format actually used in the code
	else
		return house_type;
	end
end


--[[--------------------------< V A L I D A T E _ I N S T I T U T I O N >----------------------------

validates institution

returns boolean true when valid; error message else

]]

local function validate_institution (institution, template_name)
	
	if institution and not cfg.institutions_t[institution] and not cfg.national_institutions_t[institution] then
		return make_error_msg (substitute (cfg.error_messages_t.unknown_inst, {institution}), template_name);	-- if institution is present, it must be known
	end

	return true;
end



--[[==========================< S E C T I O N _ 3 : G E T _ F U N C T I O N S >=======================]]

--[[--------------------------< G E T _ D A T A >----------------------------------------------------------

return data for the requested property for a party

<frame> required to expand {{wikidata}} template

]]

local function allpp_get_data (frame, party, property_id, option)
	local args_t = get_args (frame);
	local reference = args_t.reference and args_t.reference:lower();
	local template_name = frame:getParent():getTitle();

	local data = "";
	local verbose = args_t.verbose and args_t.verbose:lower();
	verbose = 'yes' == verbose;												-- make a boolean
	
	if reference == 'yes' and option ~= "raw-noref" then
		reference = 'references';
	else
		reference = '';
	end
	
	local party_qid = "";
	
	if not party then
		return make_error_msg (substitute (cfg.error_messages_t.unknown_party, {party}), template_name);
	elseif cfg.parties_t[party] then
		party_qid = cfg.parties_t[party];
	elseif cfg.alliances_t[party] then
		party_qid = cfg.alliances_t[party];
	elseif party:match ('^Q%d+$') then
		party_qid = party;
	elseif property_id == 'P465' and (party == "ALL" or party == "IND" or party == "NONE") then
		return '#BBB';
	elseif party ~= "THISPARTY" then
		return make_error_msg (substitute (cfg.error_messages_t.unknown_party, {party}), template_name);
	end
	
	if property_id == "label" then
		if not party then
			data = frame:expandTemplate ({title='wikidata', args = {'label'}});
		else
			data = frame:expandTemplate ({title='wikidata', args = {'label', party_qid}});
		end
	elseif property_id == "individual members date" then
		if not party then
			data = frame:expandTemplate ({title='wikidata', args = {'qualifier', 'preferred', 'P2124', 'P585'}});
		else
			data = frame:expandTemplate ({title='wikidata', args = {'qualifier', 'preferred', party_qid, 'P2124', 'P585'}});
		end
	else
		if not party then
			if option == "raw" or option == "raw-noref" then
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, 'raw', property_id}});
			elseif option == "linked" then
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, 'linked', property_id}});
			else
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, property_id}});
			end
		else
			if option == "raw" or option == "raw-noref" then
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, 'raw', party_qid, property_id}});
			elseif option == "linked" then
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, 'linked', party_qid, property_id}});
			else
				data = frame:expandTemplate ({title='wikidata', args = {'property', reference, party_qid, property_id}});
			end
		end
	end
	
	if property_id == cfg.data_prop_t.colour then
		if '' == data then
			data = '#BBB';
		else
			data = '&#35;' .. data;
		end
	elseif property_id == cfg.data_prop_t.website then
		if '' == data then
			data = "";
		else
			data = strip_URL (data);
		end
	end

	if '' == data and verbose then															-- if no delegation size
		return make_error_msg (substitute (cfg.error_messages_t.no_data, {party_qid, property_id}));
	end

	return data;
end


--[[--------------------------< H O U S E _ Q I D _ F R O M _ M E M B E R _ S T A T E >----------------------------------------------------------

return the qID of a house based on its name (lower house or upper house) and its member state

<frame> required to expand {{wikidata}} template

]]

local function house_qid_from_member_state (house_type, member_state)
	local house_qid = "";
	for row, _ in ipairs (cfg.ms_data_t) do
		if member_state == cfg.ms_data_t[row].member_state then
			if house_type == "LOWER_HOUSE" then
				house_qid = cfg.ms_data_t[row].lower_house_qid;							-- get the lower house qid
			elseif house_type == "UPPER_HOUSE" then
				house_qid = cfg.ms_data_t[row].upper_house_qid;							-- get the upper house qid
			end
		end
	end
	return house_qid;
end


--[[--------------------------< G E T _ C O L O U R >----------------------------------------------------------

return the hex colour of a European party with '#' prefix

<frame> required to expand {{wikidata}} template

]]

local function eupp_get_colour (frame, party)
	local args_t = {'property'};												-- build an arguments table for expandTemplate()
	if party ~= "THISPARTY" then												-- when not on a party page
		if cfg.parties_t[party] then
			table.insert (args_t, cfg.parties_t[party]);						-- must name the party
		elseif cfg.alliances_t[party] then
			table.insert (args_t, cfg.alliances_t[party]);						-- must name the alliance
		end
	end
	table.insert (args_t, 'P465');												-- last argument is P465; sRGB color hex triplet property
	
	local color = frame:expandTemplate ({title='wikidata', args = args_t});		-- get the color
	if '' == color then															-- if no color
		color = 'BBB';															-- use a default color; some sort of gray
	end
	return '#' .. color;														-- add the '#' prefix
end


--[[--------------------------< I N S T I T U T I O N _ S I Z E >----------------------------------------------------------

return the size of an institution

<frame> required to expand {{wikidata}} template

]]

local function institution_size (frame, institution)
	local institution_size = frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}});	-- get the institution size
	if '' == institution_size then															-- if no institution size
		return make_error_msg (substitute (cfg.error_messages_t.unknown_inst, {institution_qid}));
	end
	return institution_size;
end


--[[--------------------------< M E M B E R _ S T A T E _ D E L E G A T I O N _ S I Z E >----------------------------------------------------------

return the size of a member state's delegation in the European Parliament

<frame> required to expand {{wikidata}} template

]]

local function member_state_delegation_size (frame, member_state_qid)
	local delegation_size = frame:expandTemplate ({title='wikidata', args = {'property', member_state_qid, 'P1410', P194 = 'Q8889'}});		-- get the delegation size
	if '' == delegation_size then															-- if no delegation size
		return make_error_msg (substitute (cfg.error_messages_t.not_member_state, {member_state_qid}));
	end
	return delegation_size;
end


--[[--------------------------< S I N G L E _ H O U S E _ S E A T S >------------------------------------------------

returns the number of seats in a given lower or upper house (identified by a row in the master table) from
wikidata.  When <house_type> not recognized or when <ms_data_t> does not have 'that' house, returns 0

]]

local function single_house_seats (frame, row, house_type)
	local house_qid;

	if house_type == "LOWER_HOUSE" then
		house_qid = cfg.ms_data_t[row].lower_house_qid;							-- get the lower house qid
	elseif house_type == "UPPER_HOUSE" then
		house_qid = cfg.ms_data_t[row].upper_house_qid;							-- get the upper house qid
	end

	return house_qid and frame:expandTemplate ({title='wikidata', args = {'property', house_qid, 'P1342'}}) or 0;	-- house_qid is nil when no upper or lower house 
end


--[[--------------------------< T O T A L _ H O U S E _ S E A T S >------------------------------------------------

returns the total number of seats of all lower or upper houses in all member states.

]]

local function total_house_seats (frame, house_type)
	local sum_seats = 0;														-- init sum of seats of European party's member parties in house_type

	for row, _ in ipairs (cfg.ms_data_t) do										-- for all member states
		sum_seats = sum_seats + single_house_seats (frame, row, house_type);		-- increase sum_seats
	end

	return sum_seats;
end


--[[--------------------------< A L L P P _ S E A T S _  R E F >---------------------------------------------------------------

return the reference for a seat claim relating to <institution> listed in <cfg.parties_t> or in <cfg.alliances_t> (so not including lower and upper houses)

<frame> required to expand {{wikidata}} template

]]

local function allpp_seats_ref (frame, party, institution)
	local args_t = get_args (frame);
	local party_type = args_t[1] and args_t[1]:lower();							-- force to lower case
	
	if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
		if party_type == 'european_entity' then
			return '';
		elseif party_type == 'national_party' then
			if party == "THISPARTY" then
				local member_state = allpp_get_data (frame, mw.wikibase.getEntityIdForCurrentPage(), cfg.data_prop_t.country);
				local house_qid = house_qid_from_member_state (institution, member_state)
				return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P194 = house_qid}});
			elseif party:match ('^Q%d+$') then
				local member_state = allpp_get_data (frame, party, cfg.data_prop_t.country);
				local house_qid = house_qid_from_member_state (institution, member_state)
				return frame:expandTemplate ({title='wikidata', args = {'references', party, 'P1410', P194 = house_qid}});
			end
		end
	elseif institution == 'EC' or institution == 'EUCO' then
		if party == "THISPARTY" then
			return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P208 = cfg.institutions_t[institution]}});
		elseif cfg.parties_t[party] then
			return frame:expandTemplate ({title='wikidata', args = {'references', cfg.parties_t[party], 'P1410', P208 = cfg.institutions_t[institution]}});
		elseif cfg.alliances_t[party] then
			return frame:expandTemplate ({title='wikidata', args = {'references', cfg.alliances_t[party], 'P1410', P208 = cfg.institutions_t[institution]}});
		elseif party:match ('^Q%d+$') then
			return frame:expandTemplate ({title='wikidata', args = {'references', party, 'P1410', P208 = cfg.institutions_t[institution]}});
		end
	else
		if party == "THISPARTY" then
			return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P194 = cfg.institutions_t[institution]}});
		elseif cfg.parties_t[party] then
			return frame:expandTemplate ({title='wikidata', args = {'references', cfg.parties_t[party], 'P1410', P194 = cfg.institutions_t[institution]}});
		elseif cfg.alliances_t[party] then
			return frame:expandTemplate ({title='wikidata', args = {'references', cfg.alliances_t[party], 'P1410', P194 = cfg.institutions_t[institution]}});
		elseif party:match ('^Q%d+$') then
			return frame:expandTemplate ({title='wikidata', args = {'references', party, 'P1410', P194 = cfg.institutions_t[institution]}});
		end
	end
end

local function allpp_get_seats_ref_qid (frame, institution_qid)
	return frame:expandTemplate ({title='wikidata', args = {'references', 'P1410', P194 = institution_qid}});
end



--[[==========================< S E C T I O N _ 4 : S U M _ F U N C T I O N S >=======================]]

--[[--------------------------< A L L P P _ M A K E _ S H A R E _ I N _ E U _ I N S T I T U T I O N S >--------------------------------------------------------------

return the share of a party's seats relative to the total size of a given institution listed in <cfg.parties_t> or <cfg.alliances_t> (so not including lower and upper houses)

<frame> required to expand {{wikidata}} template 

Note: P1342 is the property "number of seats", used to record an institution's number of seats

]]

local function allpp_make_share_in_eu_institutions (frame, party_seats, institution)
	local args_t = get_args (frame);
	local constituency = args_t['constituency'];								-- argument overriding the house's number of seats
	local party_type = args_t[1] and args_t[1]:lower();							-- force to lower case
	local party = args_t[3] and args_t[3]:upper();								-- force to lower case
	
	if constituency then
		return tonumber (party_seats) and round (100 * party_seats / constituency) or party_seats;
	elseif party_type == "national_party" and institution == "EP" then
		local member_state_qid = allpp_get_data (frame, party, cfg.data_prop_t.country, 'raw-noref');
		return tonumber (party_seats) and round (100 * party_seats / member_state_delegation_size (frame, member_state_qid)) or party_seats;
	else
		return tonumber (party_seats) and round (100 * party_seats / frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}})) or party_seats;
	end
end


--[[--------------------------< A L L P P _ S E A T S _ I N _ E U _ I N S T I T U T I O N S >------------------------------------------------------------------

return the number of seats occupied by one European party in an <institution> listed in <cfg.parties_t> or in <cfg.alliances_t> (so not including lower and upper houses). <body_prop> is the wikidata property:
	P194: legislative body
	P208: executive body

<frame> required to expand {{wikidata}} template 

Note: P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies

]]

local function allpp_seats_in_eu_institutions (frame, party, institution, body_prop)
	local args_t = {};	
	if party == "THISPARTY" then												-- flag used when module is called from the page of a European party; less expensive
		args_t = {'property', 'P1410'};											-- init some of the {{wikidata}} parameters with THISPARTY (only when called from the page of a European party)
	elseif cfg.alliances_t[party] then
		args_t = {'property', cfg.alliances_t[party], 'P1410'};					-- init some of the {{wikidata}} parameters
	elseif cfg.parties_t[party] then
		args_t = {'property', cfg.parties_t[party], 'P1410'};					-- init some of the {{wikidata}} parameters
	elseif party:match ('^Q%d+$') then
		args_t = {'property', party, 'P1410'};					-- init some of the {{wikidata}} parameters
	end
	args_t[body_prop] = cfg.institutions_t[institution];

	local retval = frame:expandTemplate ({title='wikidata', args = args_t})
	if '' == retval then														-- {{wikidata}} returns empty string when <party> not known to <institution>
		if party == "THISPARTY" then											-- specific error message if the module was called with THISPARTY from the wrong page
			return make_error_msg (cfg.error_messages_t.thisparty);
		elseif not party then
			return	make_error_msg (substitute (cfg.error_messages_t.party_req_share));
		else
			return  make_error_msg (substitute (cfg.error_messages_t.inst_unknown_party, {institution, party}));
		end
	end
	return retval;
end


--[[--------------------------< E U P P _ S U M _ S E A T S _ I N _ E U _ I N S T I T U T I O N S >------------------------------------------------------------------------

return the sum of seats for all parties of <institution> listed in <cfg.parties_t> (so not including lower and upper houses).  <body_prop> is the wikidata
property:
	P194: legislative body
	P208: executive body

<frame> required to expand {{wikidata}} template 

Note: P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies

]]

local function eupp_sum_seats_in_eu_institutions (frame, institution, body_prop)
	local sum = 0;																-- init

	local args_t = {[1]='property', [3]='P1410'};								-- init some of the {{wikidata}} parameters
	args_t[body_prop] = cfg.institutions_t[institution];

	for _, qid in pairs (cfg.parties_t) do										-- loop through all parties in <cfg.parties_t>
		args_t[2] = qid;														-- set the last {{wikidata}} parameter
		sum = sum + frame:expandTemplate ({title='wikidata', args = args_t});	-- expand and tally
	end

	return sum;
end


--[[--------------------------< E U P P _ S E A T S _ I N _ E U _ I N S T I T U T I O N S >--------------------------------------------------------------------

return a number of seats either for an institution or occupied by one or more entities listed in <cfg.parties_t> or <cfg.alliances_t>, or by none of them, in an <institution> (so not including lower and upper houses).

<frame> required to expand {{wikidata}} template 

Note: 
* P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
* P1342 is the property "number of seats", used to record an institution's number of seats
* P208 is the property "executive body"
* P194 is the property "legislative body"

]]

local function eupp_seats_in_eu_institutions (frame, party, institution)
	if party == "IND" and institution == "EUCO" then						-- special case of independent politicians on European Council
		return frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}});

	elseif party == "NONE" then													-- returns seats not occupied by European parties
		local retval = frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}});	-- get number of seats in the institution

		if institution == "EUCO" then											-- if EUCO, use P208 and separate case to account for independent politicians
			local ind = frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}});
			return retval - (eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]) + ind);

		else																	-- COR, EC, EP
			return retval - eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]);
		end

	elseif party == "ALL" then													-- returns seats occupied by all European parties combined
		return eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]);

	elseif party:match ('^Q%d+$') then
		local party_name = cfg.rev_parties_t[party] or cfg.rev_alliances_t[party];
		return allpp_seats_in_eu_institutions (frame, party_name, institution, cfg.body_prop_t[institution]);
	else																		-- returns the number of seats occupied by one party in one institution
		return allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
	end
end


--[[--------------------------< E U P P _ S E A T _ S H A R E _ I N _ E U _ I N S T I T U T I O N S >--------------------------------------------------------

return a share of seats occupied by one or more entities listed in <cfg.parties_t> or <cfg.alliances_t>, or by none of them, in an <institution> (so not including lower and upper houses).

<frame> required to expand {{wikidata}} template 

Note: 
* P1410 is the property "number of seats in assembly", used to record an entity's seats in legislative or executive bodies
* P1342 is the property "number of seats", used to record an institution's number of seats
* P208 is the property "executive body"
* P194 is the property "legislative body"

]]

local function eupp_seat_share_in_eu_institutions (frame, party, institution)
	if party == "IND" and institution == "EUCO" then							-- special case of independent politicians on European Council
		return allpp_make_share_in_eu_institutions (frame, frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}}), institution);

	elseif party == "NONE" then													-- returns seats not occupied by European parties
		local retval = frame:expandTemplate ({title='wikidata', args = {'property', cfg.institutions_t[institution], 'P1342'}});

		if institution == "EUCO" then											-- if EUCO, use P208 and separate case to account for independent politicians
			local ind = frame:expandTemplate ({title='wikidata', args = {'property', cfg.misc_parties_t['IND'], 'P1410', P208 = cfg.institutions_t[institution]}})
			return allpp_make_share_in_eu_institutions (frame, retval - (eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]) + ind), institution);

		else																	-- for COR, EC, EP
			return allpp_make_share_in_eu_institutions (frame, retval - eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]), institution);
		end

	elseif party == "ALL" then													-- returns seats occupied by all European parties combined
		return allpp_make_share_in_eu_institutions (frame, eupp_sum_seats_in_eu_institutions (frame, institution, cfg.body_prop_t[institution]), institution);

	elseif party:match ('^Q%d+$') then
		party = cfg.rev_parties_t[party] or cfg.rev_alliances_t[party];
		return allpp_make_share_in_eu_institutions (frame, allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]), institution);
	else																		-- returns the number of seats occupied by one party in one institution
		return allpp_make_share_in_eu_institutions (frame, allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]), institution);
	end
end


--[[--------------------------< N P P _ S E A T S _ P E R _ R O W >------------------------------

returns the number of seats occupied by a given party (identified by a given row in the master table) in the
lower or upper house of its member state from wikidata.  When <house_type> not recognized or when <tab_data_t>
does not have 'that' house, returns 0

]]

local function npp_seats_per_row (frame, row, house_type)
	local house_qid = "";
	local national_party_qid = cfg.tab_data_t[row].national_party_qid;

	if house_type == "LOWER_HOUSE" then
		house_qid = cfg.tab_data_t[row].lower_house_qid;
	elseif house_type == "UPPER_HOUSE" then
		house_qid = cfg.tab_data_t[row].upper_house_qid;
	end
	
	return house_qid and frame:expandTemplate ({title='wikidata', args = {'property', national_party_qid, 'P1410', P194 = house_qid}}) or 0;
end


--[[--------------------------< E U P P _ S E A T S _ I N _ N A T I O N A L _ I N S T I T U T I O N S >------------------------------

returns the sum of seats occupied by all national parties members of a given European party in the lower or upper house of its member state.

]]

local function eupp_seats_in_national_institutions (frame, party, house_type)
	local sum_seats = 0;														-- init sum of seats of European party's member parties in house_type

	for row, _ in ipairs (cfg.tab_data_t) do
		if party == "THISPARTY" then											-- if called from the page of a European party
			local thisparty_qid = mw.wikibase.getEntityIdForCurrentPage();		-- get party qiD
			local thisparty_name = cfg.rev_parties_t[thisparty_qid] or cfg.rev_alliances_t[thisparty_qid];	-- use party name or when no party use alliance name

			if thisparty_name == cfg.tab_data_t[row]['european_party'] then
				sum_seats = sum_seats + npp_seats_per_row (frame, row, house_type);	-- increase sum_seats
			end
		elseif party == "ALL" or party == "NONE" then							-- not accepted parameters
			return make_error_msg (substitute (cfg.error_messages_t.all_none_unavailable, {party}));
		elseif party == "IND" then												-- not accepted parameter
			return make_error_msg (substitute (cfg.error_messages_t.ind_only_euco));
		elseif party:match ('^Q%d+$') then										-- if party name is a qID
			local thisparty_name = cfg.rev_parties_t[party] or cfg.rev_alliances_t[party];	-- get European party name from reversed tables

			if thisparty_name == cfg.tab_data_t[row]['european_party'] then
				sum_seats = sum_seats + npp_seats_per_row (frame, row, house_type);	-- increase sum_seats
			end
		else																	--for any other party name (already approved via party_type validation)
			if party == cfg.tab_data_t[row]['european_party'] then
				sum_seats = sum_seats + npp_seats_per_row (frame, row, house_type);	-- increase sum_seats
			end
		end
	end

	return sum_seats;
end


--[[--------------------------< E U P P _ S E A T _ S H A R E _ I N _ N A T I O N A L _ I N S T I T U T I O N S >--------------------------------------------------------

return a share of seats occupied by one or more entities listed in <cfg.parties_t> or <cfg.alliances_t>, or by none of them, in an <institution> (so not including lower and upper houses).

<frame> required to expand {{wikidata}} template 

]]

local function eupp_seat_share_in_national_institutions (frame, party, institution)
	return round (100 * eupp_seats_in_national_institutions (frame, party, institution) / total_house_seats (frame, institution));	-- return share of seats by calling seat_share()
end


--[[--------------------------< N P P _ S E A T S _ A N D _ S E A T _ S H A R E _ I N _ N A T I O N A L _ I N S T I T U T I O N S >------------------------------------------------


]]

local function npp_seats_and_seat_share_in_national_institutions (frame, party, house_type, data)
	local args_t = get_args (frame);											-- get arguments; empty string or whitespace positional parameters set to nil
	local party_qid = "";
	local constituency = args_t['constituency'];								-- argument overriding the house's number of seats
	
	if party == "THISPARTY" then
		party_qid = mw.wikibase.getEntityIdForCurrentPage();
	elseif party:match ('^Q%d+$') then
		party_qid = party;
	end
	
--[=[ data validation for party_qid ]=]	

	if party_qid == '' then
		return make_error_msg (cfg.error_messages_t.no_qid, template_name);	-- yep, abandon with error message
	end

--[=[ get house_qid from party qid and house_seats ]=]	
	
	local member_state = allpp_get_data (frame, party_qid, cfg.data_prop_t.country);
	local house_qid = house_qid_from_member_state (house_type, member_state)
	
	local npp_seats = house_qid and frame:expandTemplate ({title='wikidata', args = {'property', party_qid, 'P1410', P194 = house_qid}}) or 0;
	local house_seats = house_qid and frame:expandTemplate ({title='wikidata', args = {'property', house_qid, 'P1342'}}) or 0;
	
	if data == "seats" then
		return npp_seats;
	elseif data == "seat share" then
		if constituency then
			return round (100 * npp_seats / constituency);
		else
			return round (100 * npp_seats / house_seats);
		end
	elseif data == "house seats" then
		return house_seats;
	end
end


--[[--------------------------< A L L P P _ C O M P O S I T I O N _ B A R >------------------------------------------------

this function does whatever it is that {{composition bar}} does

implements {{EUPP composition bar}}

	{{EUPP composition bar|<institution>|<party>|width=<width>|percent=yes|reference=yes|bar-color=<color>|background-color=<color>|border=<color>}}
	
]]

local function allpp_composition_bar (frame, party, institution, party_type)
	local args_t = get_args (frame);											-- get arguments; empty string or whitespace positional parameters set to nil

	local width = args_t.width;													-- must be a number, or number with unit suffix: 'px', '%', 'em'; whitespace not allowed
	local percentage = args_t.percent and args_t.percent:lower();											-- 
	percentage = 'yes' == percentage;											-- make a boolean
	local reference = args_t.reference and args_t.reference:lower();			
	reference = 'yes' == reference;												-- make a boolean
	local constituency = args_t['constituency'];								-- argument overriding the house's number of seats
	
	local institution_seats = 0;
	local party_seats = 0;
	
	local background_color = args_t['background-color'];
	local border = args_t.border;
	
	if width and not validate_width (width) then
		return make_error_msg (substitute (cfg.error_messages_t.parameter_invalid, {width}), template_name);	-- yep, abandon with error message
	end

--[=[ prepare arguments for composition bar ]=]	

	if party_type == "european_entity" then
		if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
			party_seats = eupp_seats_in_national_institutions (frame, party, institution)		-- get sum of seats occupied by members of a European party
			institution_seats = total_house_seats(frame, institution);			-- get total seats of lower or upper houses
		else
			party_seats = eupp_seats_in_eu_institutions (frame, party, institution);					-- get total seats in <institution> occupied by <party>
			institution_seats = institution_size (frame, institution);							-- get total seats in <institution>
		end
	elseif party_type == "national_party" then
		if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
			party_seats = npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "seats");
			institution_seats = constituency or npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "house seats")
		elseif institution == "EP" then
			local member_state_qid = allpp_get_data (frame, party, cfg.data_prop_t.country, 'raw-noref');
			party_seats = allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
			institution_seats = constituency or member_state_delegation_size (frame, member_state_qid);							-- get total seats in <institution>
		else
			party_seats = allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]);
			institution_seats = constituency or institution_size (frame, institution);							-- get total seats in <institution>
		end
	end
		
	local color = args_t['bar-color'] or allpp_get_data (frame, party, cfg.data_prop_t.colour);			-- get color associated with <party>; |bar-color= overrides wikidata

	local comp_bar_args_t = {
		party_seats,
		institution_seats, 
		color,
		width=width,
		per=percentage,
		['background-color'] = background_color,
		border = border,
	}
	
	if party_type == "european_entity" and (institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE") then
		return frame:expandTemplate ({title='Composition bar', args = comp_bar_args_t});
	else
		return frame:expandTemplate ({title='Composition bar', args = comp_bar_args_t}) .. ((reference and allpp_seats_ref (frame, party, institution)) or '');
	end
end


--[[==========================< S E C T I O N _ 5 : M A I N _ & _ T E S T _ F U N C T I O N S >=======================]]

--[[--------------------------< M A I N >----------------------------------------------------------------------

implements {{EUPP seats}}

carries out input error detection, reporting, and function dispatching

Module called by {{EUPP data}} and {{Political party data}}, as:

{{EUPP data|<data>|<institution>|<party>|width=<width>|percent=yes|reference=yes|bar-color=<color>|background-color=<color>|border=<color>}}

{{Political party data|<data>|<institution>|<party>|width=<width>|percent=yes|reference=yes|bar-color=<color>|background-color=<color>|border=<color>}}

where <data> is:
* seats
* seat share
* seat composition bar
* colour
* individual members
* acronym
* country
* name
* public funding
* website
* foundation date

]]

local function main(frame)
	local template_name = frame:getParent():getTitle()
	local args_t = get_args (frame);											-- get arguments; empty string or whitespace positional parameters set to nil
	local party_type = args_t[1] and args_t[1]:lower();							-- force to lower case
	local data_type = args_t[2] and args_t[2]:lower();							-- force to lower case
	local party = args_t[3] and args_t[3]:upper();								-- force to upper case
	local institution = args_t[4] and args_t[4]:upper();						-- force to upper case
	local party_qid = "";
	local reference = args_t.reference and args_t.reference:lower();			
	reference = 'yes' == reference;												-- make a boolean
	local ref = "";
	
	institution = harmonise_lower_upper_house_name (institution);				-- "ms-lower-house" and "lower" are turned to "lower_house" (same for upper house)
	party = harmonise_lower_upper_house_name (party);							-- in case institution is entered as party
	
	if cfg.institutions_t[party] or party == "LOWER_HOUSE" or party == "UPPER_HOUSE" then
		institution = party;
		party = "THISPARTY";
	end	
	
	if not party then
		party = "THISPARTY";
	end

--[=[ data validation party type ]=]	
	
	if party_type == "european_entity" and not (cfg.parties_t[party] or cfg.alliances_t[party] or cfg.rev_parties_t[party] or cfg.rev_alliances_t[party] or party == "ALL" or party == "NONE" or party == "IND" or party == "THISPARTY") then
		return make_error_msg (substitute (cfg.error_messages_t.not_valid_eupp_parameter, {party}), template_name);
	elseif party_type == "european_entity" and party == "THISPARTY" and not (cfg.rev_parties_t[mw.wikibase.getEntityIdForCurrentPage()] or cfg.rev_alliances_t[mw.wikibase.getEntityIdForCurrentPage()]) then
		return make_error_msg (substitute (cfg.error_messages_t.thisparty), template_name);
	elseif party_type == "national_party" and (cfg.parties_t[party] or cfg.alliances_t[party] or cfg.rev_parties_t[party] or cfg.rev_alliances_t[party] or party == "ALL" or party == "NONE" or party == "IND" or (party == "THISPARTY" and not mw.wikibase.getEntityIdForCurrentPage())) then
		return make_error_msg (substitute (cfg.error_messages_t.not_valid_npp, {party}), template_name);
	end
	
--[=[ data validation institution ]=]	

	local is_valid = false;
	
	is_valid = validate_institution (institution, template_name);
	
	if true ~= is_valid then													-- boolean true when valid; error message else
		return is_valid;														-- yep, abandon with error message
	end

--[=[ function dispatching ]=]

	--[=[ send to seat functions ]=]
	
	if data_type == "seats" then												-- we look for a seat number
		if not institution then													-- institution is required
			return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
		end
		
		if reference then
			ref = allpp_seats_ref (frame, party, institution);
		end
		
		if party_type == "european_entity" then									-- the party is a European party or European alliance (specified by the calling template, not by the user)
			if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then	-- we look for seats aross lower or upper houses
				return eupp_seats_in_national_institutions (frame, party, institution) .. ref;	-- return the number of seats by calling eupp_seats_in_national_institutions
			else																-- we look for seats in a European institution
				return eupp_seats_in_eu_institutions (frame, party, institution) .. ref;	-- return the number of seats by calling eupp_seats_in_eu_institutions
			end
		elseif party_type == "national_party" then								-- the party is a national party
			if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then	-- we look for seats in a lower or upper house
				return npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "seats") .. ref;	-- return the number of seats by calling ...
			else																-- we look for seats in a European institution
				return allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]) .. ref;	-- return the number of seats by calling allpp_seats_in_eu_institutions
			end
		else
			return make_error_msg (substitute (cfg.error_messages_t.unknown_party_type, {party_type}), template_name);
		end
		
	--[=[ send to seat share functions ]=]
	
	elseif data_type == "seat share" then
		if not institution then													-- institution is required
			return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
		end
		
		if party_type == "european_entity" then
			if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
				return eupp_seat_share_in_national_institutions (frame, party, institution);
			else 
				return eupp_seat_share_in_eu_institutions (frame, party, institution);	-- return share of seats by calling seat_share()
			end
		
		elseif party_type == "national_party" then
			if institution == "LOWER_HOUSE" or institution == "UPPER_HOUSE" then
				return npp_seats_and_seat_share_in_national_institutions (frame, party, institution, "seat share");
			else 
				return allpp_make_share_in_eu_institutions (frame, allpp_seats_in_eu_institutions (frame, party, institution, cfg.body_prop_t[institution]), institution);	-- return share of seats by calling seat_share()
			end			
		
		else
			return make_error_msg (substitute (cfg.error_messages_t.unknown_party_type, {party_type}), template_name);
		end
		
	--[=[ send to composition bar functions ]=]
	
	elseif data_type == "seat composition bar" then
		if not institution then													-- institution is required
			return make_error_msg (cfg.error_messages_t.missing_inst, template_name);
		end
		
		return allpp_composition_bar (frame, party, institution, party_type);
		
	--[=[ send to get_data functions ]=]
		
	elseif data_type == "acronym" then
		return allpp_get_data (frame, party, cfg.data_prop_t.acronym);
	elseif data_type == "color" then
		return allpp_get_data (frame, party, cfg.data_prop_t.colour);
	elseif data_type == "country" then
		return allpp_get_data (frame, party, cfg.data_prop_t.country, 'linked');
	elseif data_type == "foundation date" then
		return allpp_get_data (frame, party, cfg.data_prop_t.foundation_date);
	elseif data_type == "individual members" then
		return allpp_get_data (frame, party, cfg.data_prop_t.individual_members);
	elseif data_type == "individual members date" then
		return allpp_get_data (frame, party, 'individual members date');
	elseif data_type == "label" then
		return allpp_get_data (frame, party, 'label');	
	elseif data_type == "official name" then
		return allpp_get_data (frame, party, cfg.data_prop_t.official_name);
	elseif data_type == "parliamentary group" then
		return allpp_get_data (frame, party, cfg.data_prop_t.parliamentary_group, 'linked');
	elseif data_type == "public funding" then
		return allpp_get_data (frame, party, cfg.data_prop_t.public_funding);
	elseif data_type == "website" then
		return allpp_get_data (frame, party, cfg.data_prop_t.website);


	else
		return make_error_msg (substitute (cfg.error_messages_t.unknown_data_type, {data_type}), template_name);
	end
end


--[[--------------------------< T E S T _ W I K I D A T A _ E N T R I E S >----------------------------------------------------------------------
]]

local function test_wikidata_entries (frame)														-- to test calls and functions, for verification purposes
	local wikidata_error = "Wikidata entries error(s):";
	
	for row, _ in ipairs (cfg.tab_data_t) do
		local national_party_qid = cfg.tab_data_t[row].national_party_qid;
		local national_party_name = "";
		
		if not cfg.tab_data_t[row].national_party then
			national_party_name = cfg.tab_data_t[row].national_party_english;
		else
			national_party_name = cfg.tab_data_t[row].national_party;
		end
		
		local lower_house_qid = cfg.tab_data_t[row].lower_house_qid;
		local lower_house_name = cfg.tab_data_t[row].lower_house;
		local upper_house_qid = cfg.tab_data_t[row].upper_house_qid;
		local upper_house_name = cfg.tab_data_t[row].upper_house;
		local retval_lower = frame:expandTemplate ({title='wikidata', args = {'property', national_party_qid, 'P1410', P194 = lower_house_qid}})
		local retval_upper = frame:expandTemplate ({title='wikidata', args = {'property', national_party_qid, 'P1410', P194 = upper_house_qid}})
		
		if '' == retval_lower then
			wikidata_error = wikidata_error .. " [https://www.wikidata.org/wiki/" .. national_party_qid .. " " .. national_party_name .. "] (" .. lower_house_name .. ")";
		end
		
		if '' == retval_upper then
			wikidata_error = wikidata_error .. " [https://www.wikidata.org/wiki/" .. national_party_qid .. " " .. national_party_name .. "] (" .. upper_house_name .. ")";
		end
	end
	
	if wikidata_error == "Wikidata entries error(s):" then
		wikidata_error = "Wikidata entries: all good!";
	end
	
	return wikidata_error;
end


--[[--------------------------< T E S T >----------------------------------------------------------------------
]]

local function test (frame)													-- to test calls and functions, for verification purposes
	local args_t = get_args (frame);											-- get arguments; empty string or whitespace positional parameters set to nil
	local member_state_qid = args_t[1];
	--local party_qid = args_t[1] and args_t[1]:upper();						-- force to upper case
	--local party = args_t[2] and args_t[2]:upper();
	-- local share = args_t[3] and args_t[3]:upper();
	
	local this_page_qid = mw.wikibase.getEntityIdForCurrentPage();
	--return allpp_get_data (frame, party_qid, cfg.data_prop_t.country, "raw") .. ": " .. allpp_get_data (frame, party_qid, cfg.data_prop_t.country, "linked");
	--return allpp_get_data (frame, party_qid, cfg.data_prop_t.colour);
	--return member_state_delegation_size (frame, member_state_qid)
	--return cfg.institutions_t.COR .. " " .. cfg.parties_t.ALDE .. " " .. cfg.alliances_t.VOLT .. " " .. cfg.body_prop_t.COR .. " " .. cfg.data_prop_t.COLOUR;

	--institution = strip_house_type (institution);								-- here, testing strip_house_type
	return this_page_qid;
	--return institution;
end


--[[--------------------------< E X P O R T S >----------------------------------------------------------------
]]

return {
	main = main,
	test = test,
	test_wikidata_entries = test_wikidata_entries,
	}