Module:Sandbox/trappist the monk/airports convert

From English Wikipedia @ Freddythechick

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

This module reads a lua table of tables and creates a similar table of tables where the data are less redundant.
The redundant form may be convenient for creates of the tables but occupies a rather large amount of space to
hold unused data.  The original form:

local master= {
	{'Africa','Algeria','AZR','DAUA','Touat-Cheikh Sidi Mohamed Belkebir Airport','Adrar'},
	{'Africa','Algeria','QMH','DABO','Oum el Bouaghi Airport','Aïn Beïda', 'Q16896254'},
	{'Africa','Algeria',   '','DAAQ','Aïn Oussera Airport','Aïn Oussera'},
	{'Africa','Botswana',   '','FBXG','Xugana Airport','Xugana'},
	{'Africa','Burkina Faso','XAR','DFOY','Aribinda Airport','Aribinda'},
	{'Africa','Democratic Republic of the Congo','MNO','','','Manono'},
	{'Antartica','Antarctica','TNM','','','King George Island'},
	{'Asia','Afghanistan','LQN','OAQN','Qala i Naw Airport','Badghis'},
}

None of the continent and country data are used.  This module reads the old format and creates a table of tables
in the form:

master = {
	['Africa'] = {
		['Burkina Faso'] = {
			{'XAR', 'DFOY', 'Aribinda Airport', 'Aribinda'},
			},
		['Botswana'] = {
			{''   , 'FBXG', 'Xugana Airport', 'Xugana'},
			},
		['Algeria'] = {
			{'AZR', 'DAUA', 'Touat-Cheikh Sidi Mohamed Belkebir Airport', 'Adrar'},
			{'QMH', 'DABO', 'Oum el Bouaghi Airport', 'Aïn Beïda', 'Q16896254'},
			{''   , 'DAAQ', 'Aïn Oussera Airport', 'Aïn Oussera'},
			},
		['Democratic Republic of the Congo'] = {
			{'MNO', ''    , '', 'Manono'},
			},
		},
	['Asia'] = {
		['Afghanistan'] = {
			{'LQN', 'OAQN', 'Qala i Naw Airport', 'Badghis'},
			},
		},
	['Antartica'] = {
		['Antarctica'] = {
			{'TNM', ''    , '', 'King George Island'},
			},
		},
	};
]]


local function main ()
local master = mw.loadData ("Module:Sandbox/trappist_the_monk/airports_convert/data")
local _master = master._master

local out = {};
local result = {};
local cc_list ={};
	
	for _, airport in ipairs (_master) do										-- for each airport table in _master
		if not out[airport[1]] then												-- if out{} does not have a table for the continent
			out[airport[1]] = {};												-- make one
		end
		if not out[airport[1]][airport[2]] then									-- if the continent table does not have a table for the country
			out[airport[1]][airport[2]] = {}									-- make one
		end
		table.insert (out[airport[1]][airport[2]], {airport[3], airport[4], airport[5]:gsub ("'", "\\'"), airport[6]:gsub ("'", "\\'"), airport[7]});
	end

	table.insert (result, '<pre>master = {<br />')								-- open master table
	table.insert (cc_list, '<pre>master = {<br />')								-- open master table
	for continent_key, continent_table in pairs (out) do						-- for each continent table in out{}
		table.insert (result, table.concat ({'&#9;[\'', continent_key, '\'] = {<br />'}))			-- write the index
		table.insert (cc_list, table.concat ({'&#9;[\'', continent_key, '\'] = {<br />'}))			-- write the index
		for country_key, country_table in pairs (continent_table) do								-- for each country in continent_table{}
			table.insert (result, table.concat ({'&#9;&#9;[\'', country_key, '\'] = {<br />'}));	-- write the country index
			table.insert (cc_list, table.concat ({'&#9;&#9;[\'', country_key, '\'],'}));	-- write the country index
			for _, airport in ipairs (country_table) do												-- for each airport in country_table{}
				local airport_table = {}															-- create airport tables
				for i, v in ipairs (airport) do														-- extract items from the airport table
					local item;
					if (3 > i) and ('' == v) then													-- for IATA and ICAO codes
						item = table.concat ({'&#39;&#39;', string.rep (' ', i+2)});				-- add enough spaces to make the tables pretty
					else
						item = table.concat ({'&#39;', v, '&#39;'})									-- numeric character entities to prevent empty string from being treated as italic markup
					end
					table.insert (airport_table, item);												-- add the item to the airport table
				end
				table.insert (result, table.concat ({'&#9;&#9;&#9;{', table.concat (airport_table, ', '), '},<br />'}))	-- add the airport table to the country table
			end
			table.insert (result, '&#9;&#9;&#9;},<br />');						-- close country table
			table.insert (cc_list, '<br />');									-- close country table
		end
		table.insert (result, '&#9;&#9;},<br />');								-- close continnent table
		table.insert (cc_list, '&#9;&#9;},<br />');										-- close continnent table
	end
	table.insert (result, '&#9;};</pre><br />');								-- close master table
	table.insert (cc_list, '&#9;};</pre><br />');								-- close master table

	return table.concat ({table.concat (result), table.concat (cc_list)}, '<br /><hr /><br />');												-- put it all together and done
end


--[[--------------------------< D U P L I C A T E _ C H E C K >------------------------------------------------

This function looks at new form IATA and ICAO code data in Module:IATA and ICAO code/data.  It attempts to locate
invalid (by length) codes and attempts to detect duplicate codes.

  1               2     3     4
{'North America','USA','ABE','KABE','Lehigh Valley International Airport','Allentown/Bethlehem'},

]]

local function duplicate_check ()
local master = mw.loadData ("Module:IATA_and_ICAO_code/data/sandbox")
local iata_count_table = {};
local icao_count_table = {};

local _master = master._master

local iata = {}
local icao = {}

	for continent_key, continent_table in pairs (_master) do									-- for each continent table in _master{}
		for country_key, country_table in pairs (continent_table) do						-- for each country in continent_table{}
			for i, airport in ipairs (country_table) do							-- for each airport table in country_table{}
				if '' ~= airport[1] then
					if not iata[airport[1]] then
						iata[airport[1]] = 1;									-- state that this is the first time we've seen this code
					else
						iata[airport[1]] = iata[airport[1]] + 1;				-- bump the count for this code
					end
				end
				if '' ~= airport[2] then
					if not icao[airport[2]] then
						icao[airport[2]] = 1;									-- state that this is the first time we've seen this code
					else
						icao[airport[2]] = icao[airport[2]] + 1;				-- bump the count for this code
					end
				end
			end
		end
	end

	for k, v in pairs (iata) do
		if 1 < v then
			table.insert (iata_count_table, table.concat ({k, ' (', v, '×)'}))
		end
	end

	for k, v in pairs (icao) do
		if 1 < v then
			table.insert (icao_count_table, table.concat ({k, ' (', v, '×)'}))
		end
	end
	
	local iata_msg = '';														-- error messages go here
	local icao_msg = '';

	if 0 ~= #iata_count_table then
		iata_msg = make_err_msg (err_msg['extra_iata'], table.concat (iata_count_table, ', '))
--		iata_msg = table.concat ({'<span style=\"font-size:100%; font-style:normal;\" class=\"error\">error: more than one IATA code:<br />	', table.concat (iata_count_table, ', '), '</span>'})
	end
	if 0 ~= #icao_count_table then
		icao_msg = make_err_msg (err_msg['extra_iata'], table.concat (icao_count_table, ', '))
--		icao_msg = table.concat ({'<span style=\"font-size:100%; font-style:normal;\" class=\"error\">error: more than one ICAO code:<br />	', table.concat (icao_count_table, ', '), '</span>'})
	end
	
	if (0 ~= #iata_count_table) or (0 ~= #icao_count_table) then				-- TODO find a better way of doing this
		return table.concat ({iata_msg, '<br /><br />', icao_msg})
	end
	return 'ok';
end


return {
	main = main,
	duplicate_check = duplicate_check,
	};