require('strict');

local utilities = require ('Module:WPSHIPS_utilities');
local infobox_ship_flag = utilities._infobox_ship_flag;
local ship_name_format = utilities._ship_name_format;
local synonym_check = utilities._synonym_check;
local unbulleted_list = utilities._unbulleted_list;

local get_args = require ('Module:Arguments').getArgs;

local data = mw.loadData ('Module:Infobox_ship/data');

local namespace = mw.title.getCurrentTitle().namespace;
local has_unknown_params = false;

--[[--------------------------< L I N E _ I T E M S >-----------------------------------------------------------------------------

spin through <params_t> sequence.  Get parameter name and matching infobox label.  Look in <args_t> for parameter name.  When parameter
name has a value, add infobox label and parameter value to the infobox table <infobox_ship_t>.  <i> identifies where label and data
enumerators begin.

]]

local function line_items (args_t, params_t, infobox_ship_t, i, frame)
	for _, v in ipairs (params_t) do											-- v is a sequence table with parameter name and associated infobox label
		if args_t[v[1]] then													-- if parameter has a value
			infobox_ship_t['label' .. i] = v[2];								-- add the label
			infobox_ship_t['data' .. i] = unbulleted_list (args_t[v[1]]);		-- and add the parameter value as data
			i = i + 1;															-- bump the enumerator
		end
	end
end


--[[--------------------------< U N K N O W N _ P A R A M S _C H E C K >---------------------------------------

check parameters supplyed in <template> against known parameters for that template.  Emit preview warning when
a parameter is unknown.

]]

local function unknown_params_check (args_t, known_params_t, template)
	for k, v in pairs (args_t) do
		local param = k:gsub ('%d+$', '#');										-- for enumerated parameters, replace enumerator with '#'
		if not known_params_t[param] then										-- add warning message when <param> is not known for <template>
			mw.addWarning (string.format (data.warning_fmt_str, data.warn_span_style, data.warn_code_style, template, template, data.warn_code_style, k, v));
			has_unknown_params = (0 == namespace);								-- add unknown params category when infobox is rendered; mainspace only
		end
	end
end


--[[--------------------------< I N F O B O X _ S H I P _ B E G I N >------------------------------------------

fill infobox table parameters 'bodystyle' and 'title' (infobox caption); auto-article title formatting ({{DISPLAYTITLE}})

]]

local function infobox_ship_begin (args_t, infobox_ship_t, frame)
	infobox_ship_t['bodystyle'] = data.styles_t.mainbox;
	if args_t.infobox_caption then
		local name = mw.title.getCurrentTitle().text;
		if 'yes' == args_t.infobox_caption then									-- format article title as infobox caption
			infobox_ship_t.title = ship_name_format ({name=name, adj='off', showerrs=args_t.showerrs, sclass=args_t.sclass});
		elseif 'nodab' == args_t.infobox_caption then							-- format article title without disambiguation as infobox caption
			infobox_ship_t.title = ship_name_format ({name=name, dab='none', showerrs=args_t.showerrs});
		else																	-- use value supplied in |infobox_caption= as infobox caption
			infobox_ship_t.title = args_t.infobox_caption;
		end
	else
		infobox_ship_t.title = '';												-- to allow for possible displaytitle concatenation
	end

	if args_t.display_title and ('none' ~= args_t.display_title) then			-- any value but 'none'
		if 'ital' == args_t.display_title then									-- use {{italic title}} template
			infobox_ship_t.title = infobox_ship_t.title .. frame:expandTemplate ({title='italic title'});
		else																	-- use value in |display_title= for {{DISPLAYTITLE}} magic word
			infobox_ship_t.title = infobox_ship_t.title .. frame:preprocess ('{{DISPLAYTITLE:' .. args_t.display_title .. '}}');
		end
	end
end	


--[[--------------------------< I N F O B O X _ S H I P _ I M A G E >------------------------------------------

Returns a child infobox for Infobox ship

TODO: allow stand-alone when |child= set to anything but 'yes'?  How do that?

]]

local function infobox_ship_image (frame)
	local args_t = get_args (frame);
	local infobox_ship_t = {
		child = args_t.child or 'yes';											-- default to child
		image1 = frame:callParserFunction ({name='#invoke', args = {'InfoboxImage', 'InfoboxImage', image=args_t.image, size=args_t.image_size, alt=args_t.image_alt, sizedefault = '300px', upright='1'}});
		caption1 = args_t.image_caption;
		}

	unknown_params_check (args_t, data.known_infobox_ship_image_params_t, 'Infobox ship/image');

	return frame:expandTemplate ({title='Infobox', args = infobox_ship_t});		-- return a rendering of this infobox
end


--[[--------------------------< I N F O B O X _ S H I P _ C A R E E R >----------------------------------------

Returns a child infobox

TODO: allow stand-alone when |child= set to anything but 'yes'?  How do that?

]]

local function infobox_ship_career (frame)
	local args_t = get_args (frame);
	args_t.hide_header= args_t.hide_header and args_t.hide_header:lower();		-- set to lowercase if set

	local infobox_ship_t = {
		child = args_t.child or 'yes';											-- default to child
		headerstyle = data.styles_t.country;
		}

	local i = 1;

	if 'yes' ~= args_t.hide_header then											-- |hide_header=yes then no header
		if not ('title' == args_t.hide_header) then								-- |hide_header=title then no title bar
			local spoof_t = {
				child = 'yes';													-- default to child
				decat = 'yes';													-- spoof infobox does not have data; don't categorize in Category:Articles using infobox templates with no data rows
				headerstyle = data.styles_t.history;
				header1 = 'History';
				}

			infobox_ship_t.data1 = frame:expandTemplate ({title='Infobox', args = spoof_t});	-- return a rendering of this spoof infobox
			i = i + 1;
		end

		if args_t.ship_country and args_t.ship_flag then
			infobox_ship_t['header' .. i] = infobox_ship_flag (args_t.ship_flag) .. '<span style="padding-left:1em">' .. args_t.ship_country .. '</span>';
		elseif args_t.ship_country then
			infobox_ship_t['header' .. i] = args_t.ship_country;
		elseif args_t.ship_flag then
			infobox_ship_t['header' .. i] = infobox_ship_flag (args_t.ship_flag);
		end
	end

	if infobox_ship_t['header' .. i] then
		i = i + 1;
	end
	
	local error_flag;
	error_flag = synonym_check (args_t, 'ship_stricken', 'ship_struck', error_flag);	-- error if both synonymous parameters set
	synonym_check (args_t, 'ship_honours', 'ship_honors', error_flag);

	line_items (args_t, data.infobox_career_params_t, infobox_ship_t, i, frame);		-- go do all of the other infobox parameters
	unknown_params_check (args_t, data.known_infobox_ship_career_params_t, 'Infobox ship/career');

	return frame:expandTemplate ({title='Infobox', args = infobox_ship_t});		-- return a rendering of this infobox
end


--[[--------------------------< I N F O B O X _ S H I P _ C H A R A C T E R I S T I C S >----------------------

Returns a child infobox (default); may be called independently

TODO: allow stand-alone when |child= set to anything but 'yes'?  How do that?

]]

local function infobox_ship_characteristics (frame)
	local args_t = get_args (frame);
	args_t.hide_header= args_t.hide_header and args_t.hide_header:lower();		-- set to lowercase if set

	local infobox_ship_t = {
		child = args_t.child or 'yes',											-- default to child
		headerstyle = data.styles_t.general,
		}
	
	local i = 1;

	if 'yes' ~= args_t.hide_header then											-- |hide_header=yes then no header
		local header = 'General characteristics';								-- the default header
		if args_t.header_caption then
			header = header .. ' ' .. args_t.header_caption;					-- concatenate |header_caption= onto default header
		end
		infobox_ship_t['header' .. i] = header;									-- add the header
		i = i + 1;																-- bump the enumerator
	end

	local error_flag;
	error_flag = synonym_check (args_t, 'ship_armour', 'ship_armor', error_flag);	-- error if both synonymous parameters set
	synonym_check (args_t, 'ship_draught', 'ship_draft', error_flag);				-- when both set modify with error message and category

	line_items (args_t, data.infobox_characteristics_params_t, infobox_ship_t, i, frame);	-- go do all of the other infobox parameters
	unknown_params_check (args_t, data.known_infobox_ship_characteristics_params_t, 'Infobox ship/characteristics');

	return frame:expandTemplate ({title='Infobox', args = infobox_ship_t});		-- return a rendering of this infobox
end


--[[--------------------------< I N F O B O X _ S H I P _ C L A S S _ O V E R V I E W >------------------------

Returns a child infobox

TODO: allow stand-alone when |child= set to anything but 'yes'?  How do that?

]]

local function infobox_ship_class_overview (frame)
	local args_t = get_args (frame);
	args_t.hide_header= args_t.hide_header and args_t.hide_header:lower();		-- set to lowercase if set

	local infobox_ship_t = {
		child = args_t.child or 'yes',											-- default to child
		headerstyle = data.styles_t.general
		}
	
	local i = 1;

	if 'yes' ~= args_t.hide_header then											-- |hide_header=yes then no header
		infobox_ship_t['header' .. i] = 'Class overview';						-- add the header
		i = i + 1;																-- bump the enumerator
	end

	line_items (args_t, data.infobox_class_overview_params_t, infobox_ship_t, i, frame);	-- go do all of the other infobox parameters
	unknown_params_check (args_t, data.known_infobox_ship_class_overview_params_t, 'Infobox ship/class');

	return frame:expandTemplate ({title='Infobox', args = infobox_ship_t});		-- return a rendering of this infobox
end


--[[--------------------------< I N F O B O X _ S H I P _ S E R V I C E _ R E C O R D >------------------------

Returns a child infobox.  This function implements the ship-only portion of {{Infobox service record}}; does not
know about |is_ship= and |is_multi= parameters.  Adds support for |hide_header= parameter

TODO: allow stand-alone when |child= set to anything but 'yes'?  How do that?

]]

local function infobox_ship_service_record (frame)
	local args_t = get_args (frame);
	args_t.hide_header= args_t.hide_header and args_t.hide_header:lower();		-- set to lowercase if set

	local infobox_ship_t = {
		child = args_t.child or 'yes',											-- default to child
		headerstyle = data.styles_t.general
		}
	
	local i = 1;

	if 'yes' ~= args_t.hide_header then											-- |hide_header=yes then no header
		infobox_ship_t['header' .. i] = args_t.label or 'Service record';		-- add the header
		i = i + 1;																-- bump the enumerator
	end

	line_items (args_t, data.infobox_ship_service_record_params_t, infobox_ship_t, i, frame);	-- go do all of the other infobox parameters
	unknown_params_check (args_t, data.known_infobox_ship_service_record_params_t, 'Infobox ship/service record');

	return frame:expandTemplate ({title='Infobox', args = infobox_ship_t});		-- return a rendering of this infobox
end


--[[--------------------------< I N F O B O X _ S H I P >------------------------------------------------------

{{#invoke:Infobox ship|infobox_ship}}

]]

local function infobox_ship (frame)
	local args_t = get_args (frame);

	local infobox_ship_t = {}													-- table that holds infobox parameters

	infobox_ship_begin (args_t, infobox_ship_t, frame);

	for k, v in pairs (args_t) do												-- copy infobox parameters from the frame into our local table
		local enum = k:match ('section(%d+)');									-- <enum> gets a value when this parameter is |section<n>= 
		if enum then
			infobox_ship_t['data'..enum] = v;									-- translate |section<n> = to |data<n>=
		else
			infobox_ship_t[k] = v;												-- assume that parameter name is one known to Module:Infobox
		end

	end
	unknown_params_check (args_t, data.known_infobox_ship_params_t, 'Infobox ship');

	return frame:expandTemplate ({title='Infobox', args = infobox_ship_t}) .. (has_unknown_params and '[[Category:Pages using infobox ship with unknown parameters]]' or '');
end

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

return {
	infobox_ship = infobox_ship,
	infobox_ship_image = infobox_ship_image,
	infobox_ship_career = infobox_ship_career,
	infobox_ship_characteristics = infobox_ship_characteristics,
	infobox_ship_class_overview = infobox_ship_class_overview,
	infobox_ship_service_record = infobox_ship_service_record,
	}