Module:Sports table/argcheck

local a = {}

local categories = {

ignored_parameters = 'Category:Pages using sports table with ignored parameters',

missing_results = 'Category:Pages using sports table with missing results',

missing_teams = 'Category:Pages using sports table with missing teams',

orphaned_match_notes = 'Category:Pages using sports table with orphaned match notes',

orphaned_names = 'Category:Pages using sports table with orphaned names',

orphaned_notes = 'Category:Pages using sports table with orphaned notes',

orphaned_results = 'Category:Pages using sports table with orphaned results',

possible_incorrect_winpoints = 'Category:Pages using sports table with possible incorrect winpoints',

possibly_ignored_parameters = 'Category:Pages using sports table with possibly ignored parameters',

unknown_parameters = 'Category:Pages using sports table with unknown parameters'

}

local good_args = {

['away_goals_header'] = 1,

['bonus_header'] = 1,

['class_rules'] = 1,

['draw_header'] = 1,

['drawpoints'] = 1,

['float'] = 1,

['for_against_style'] = 1,

['GB_team'] = 1,

['goalpoints'] = 1,

['group_header'] = 1,

['hide_footer'] = 1,

['hide_for_against_columns'] = 1,

['hide_played'] = 1,

['hide_results'] = 1,

['highest_pos'] = 1,

['legs'] = 1,

['loss_before_draw'] = 1,

['loss_before_tie'] = 1,

['losspoints'] = 1,

['lowest_pos'] = 1,

['matches_style'] = 1,

['matches_text'] = 1,

['match_col_width'] = 1,

['note_header_res'] = 1,

['only_pld_pts'] = 1,

['only_totals'] = 1,

['only_fa_totals'] = 1,

['pct_style'] = 1,

['pld_header'] = 1,

['postitle'] = 1,

['perc_first'] = 1,

['pts_first'] = 1,

['ranking_style'] = 1,

['res_col_header'] = 1,

['result_prefix'] = 1,

['rwpoints'] = 1,

['rw_header'] = 1,

['section'] = 1,

['short_style'] = 1,

['show_GB'] = 1,

['show_away_goals'] = 1,

['show_bonus_points'] = 1,

['show_class_rules'] = 1,

['show_draw'] = 1,

['show_groups'] = 1,

['show_limit'] = 1,

['show_matches'] = 1,

['show_positions'] = 1,

['show_rw'] = 1,

['show_status'] = 1,

['show_totals'] = 1,

['solid_cell'] = 1,

['sortable_table'] = 1,

['source'] = 1,

['start_date'] = 1,

['stack_footer'] = 1,

['status_order'] = 1,

['status_pos'] = 1,

['style'] = 1,

['table_header'] = 1,

['table_header_source'] = 1,

['team_header'] = 1,

['team_order'] = 1,

['team_order_start'] = 1,

['teamwidth'] = 1,

['title'] = 1,

['title_source'] = 1,

['transcludesection'] = 1,

['update'] = 1,

['use_against_percentage'] = 1,

['use_goal_average'] = 1,

['use_goal_diff'] = 1,

['use_goal_percentage'] = 1,

['use_goal_ratio'] = 1,

['use_goals_scored'] = 1,

['use_point_percentage'] = 1,

['use_goals_per_match'] = 1,

['use_points_per_match'] = 1,

['use_tie'] = 1,

['winpoints'] = 1,

}

local good_args_HA = {

['ha_side'] = 1,

['hdrawpoints'] = 1,

['adrawpoints'] = 1,

['hlosspoints'] = 1,

['alosspoints'] = 1,

['hwinpoints'] = 1,

['awinpoints'] = 1

}

local good_args_PKOT = {

['showOTloss'] = 1,

['showOTwin'] = 1,

['showPKloss'] = 1,

['showSOloss'] = 1,

['showPKwin'] = 1,

['showSOwin'] = 1,

['show_tiebr'] = 1,

['PKlosspoints'] = 1,

['SOlosspoints'] = 1,

['OTlosspoints'] = 1,

['PKwinpoints'] = 1,

['SOwinpoints'] = 1,

['OTwinpoints'] = 1,

['PKloss_after_loss'] = 1,

['SOloss_after_loss'] = 1,

['OTloss_after_loss'] = 1,

['tiebr_header'] = 1,

}

local good_args_BDT = {

['drawpoints'] = 0,

['game_for_against_style'] = 1,

['point_for_against_style'] = 1

}

local good_args_VB = {

['winpoints'] = 0,

['losspoints'] = 0,

['drawpoints'] = 0,

['bwinpoints'] = 1,

['blosspoints'] = 1,

['swinpoints'] = 1,

['slosspoints'] = 1,

['win3points'] = 1,

['loss3points'] = 1,

['win4points'] = 1,

['loss4points'] = 1,

['win5points'] = 1,

['loss5points'] = 1,

['show_sets'] = 1,

['show_setpoints'] = 1,

['setpoints_before_sets'] = 1,

['best_of'] = 1

}

local ignored_args = {

['date'] = 1,

['ptsfirst'] = 1

}

local col_names = {

['adjust_points'] = 1,

['away_goals'] = 1,

['draw'] = 1,

['loss'] = 1,

['gf'] = 1,

['ga'] = 1,

['group'] = 1,

['pf'] = 1,

['pa'] = 1,

['matches'] = 1,

['pos'] = 1,

['rw'] = 1,

['short'] = 1,

['startpoints'] = 1,

['status'] = 1,

['win'] = 1,

}

local col_names_HA = {

['draw'] = 0,

['loss'] = 0,

['gf'] = 0,

['ga'] = 0,

['pf'] = 0,

['pa'] = 0,

['rw'] = 0,

['hdraw'] = 1,

['adraw'] = 1,

['hloss'] = 1,

['aloss'] = 1,

['hwin'] = 1,

['awin'] = 1,

['hga'] = 1,

['aga'] = 1,

['hgf'] = 1,

['agf'] = 1,

['hpa'] = 1,

['apa'] = 1,

['hpf'] = 1,

['apf'] = 1,

}

local col_names_PKOT = {

['PKloss'] = 1,

['SOloss'] = 1,

['OTloss'] = 1,

['PKwin'] = 1,

['SOwin'] = 1,

['OTwin'] = 1,

['tiebr'] = 1

}

local col_names_BDT = {

['win'] = 1,

['loss'] = 1,

['mf'] = 1,

['ma'] = 1,

['gf'] = 1,

['ga'] = 1,

['pf'] = 1,

['pa'] = 1

}

local col_names_VB = {

['win'] = 0,

['loss'] = 0,

['draw'] = 0,

['bwin'] = 1,

['swin'] = 1,

['bloss'] = 1,

['sloss'] = 1,

['sw'] = 1,

['sl'] = 1,

['spw'] = 1,

['spl'] = 1,

['win3s'] = 1,

['loss3s'] = 1,

['win4s'] = 1,

['loss4s'] = 1,

['win5s'] = 1,

['loss5s'] = 1,

}

local tracked_styles = {

['football'] = 'WDL',

['WDL'] = 'WDL',

['WL'] = 'WDL',

['WDLHA'] = 'HA',

['WDL OT'] = 'PKOT',

['WLHA'] = 'HA',

['WL OT'] = 'PKOT',

['WL PK'] = 'PKOT',

['WL OTL tiebreak'] = 'PKOT',

['Volleyball'] = 'VB',

['Badminton team'] = 'BDT'

}

local warn = {}

local track = {}

local function get_tracking_category(category, value)

return '' .. value .. ''

end

local function validate_table_values(args, category, bad_char, is_track)

for _, v in ipairs(args) do

v = mw.ustring.gsub(v, bad_char, '?')

if v == '' then

v = ' '

end

if is_track then

table.insert(track, get_tracking_category(category, v))

else

table.insert(warn, get_tracking_category(category, v))

end

end

end

function a.check(targs, pargs)

local teams = {}

local missing_teams = {}

local results = {}

local missing_results = {}

local orphaned_match_notes = {}

local orphaned_results = {}

local orphaned_names = {}

local orphaned_notes = {}

local ignored = {}

local possibly_ignored = {}

local unknown = {}

local mstyle = mw.ustring.gsub(targs['style'] or '', '[%s_][%s_]*', ' ')

mstyle = tracked_styles[mstyle]

if mstyle == nil then

return warn, track

end

if mstyle == 'HA' then

for k, v in pairs(good_args_HA) do

good_args[k] = v ~= 0 and v or nil

end

for k, v in pairs(col_names_HA) do

col_names[k] = v ~= 0 and v or nil

end

if targs['only_fa_totals'] then

col_names['pf'] = 1

col_names['gf'] = 1

col_names['pa'] = 1

col_names['ga'] = 1

end

end

if mstyle == 'PKOT' then

for k, v in pairs(good_args_PKOT) do

good_args[k] = v ~= 0 and v or nil

end

for k, v in pairs(col_names_PKOT) do

col_names[k] = v ~= 0 and v or nil

end

end

if mstyle == 'BDT' then

for k, v in pairs(good_args_BDT) do

good_args[k] = v ~= 0 and v or nil

end

for k, v in pairs(col_names_BDT) do

col_names[k] = v ~= 0 and v or nil

end

end

if mstyle == 'VB' then

for k, v in pairs(good_args_VB) do

good_args[k] = v ~= 0 and v or nil

end

for k, v in pairs(col_names_VB) do

col_names[k] = v ~= 0 and v or nil

end

end

-- Alternative syntax for team list

if targs['team_order'] and targs['team_order'] ~= '' then

local tlist = mw.text.split(targs['team_order'], '%s*[;,]%s*')

for k, tname in ipairs(tlist) do

if tname ~= '' then

targs['team' .. k] = tname

end

end

end

-- Limited tracking if we are only showing part of the table

if targs['showteam'] then

local top_pos = tonumber(targs['highest_pos']) or 1

local bottom_pos = tonumber(targs['lowest_pos']) or 0

local N = top_pos - 1

while targs['team' .. N + 1] ~= nil and (bottom_pos < top_pos or N < bottom_pos) do

N = N + 1

teams[targs['team' .. N]] = 1

if teams[targs['showteam']] then

return warn, track

end

end

end

-- Step 1: Generate a team and result list

for k,v in pairs(targs) do

if type(k) == 'string' then

if k:find('^team%d%d*$') then

teams[v] = 1

targs[k] = ''

if targs['name_' .. v] then

-- Great!

targs['name_' .. v] = ''

else

table.insert(missing_teams, v)

end

if targs['note_' .. v] then

targs['note_' .. v] = ''

end

if targs['hth_' .. v] then

local multiref = 1

local hth_local_table = mw.text.split(targs['hth_' .. v], '%s*,%s*')

if (#hth_local_table > 1) then

for _, hth_loc in ipairs(hth_local_table) do

multiref = multiref * (targs['hth_' .. hth_loc] and 1 or 0)

end

else

multiref = 0

end

if multiref > 0 then

for _, hth_loc in ipairs(hth_local_table) do

targs['hth_' .. hth_loc] = ''

end

elseif targs['hth_' .. targs['hth_' .. v]] then

targs['hth_' .. targs['hth_' .. v]] = ''

end

targs['hth_' .. v] = ''

end

elseif k:find('^result%d%d*$') or k:find('^.*_result%d%d*$') then

local pre = mw.ustring.gsub(k, '^(.*)result%d%d*$', '%1')

results[v] = 1

targs[k] = ''

if targs[pre .. 'col_' .. v] or targs[pre .. 'text_' .. v] or targs[pre .. 'note_res_' .. v] then

-- Great!

if targs[pre .. 'col_' .. v] then

targs[pre .. 'col_' .. v] = ''

end

if targs[pre .. 'text_' .. v] then

targs[pre .. 'text_' .. v] = ''

end

if targs[pre .. 'note_res_' .. v] then

local multiref = 1

local note_res_local_table = mw.text.split(targs[pre .. 'note_res_' .. v], '%s*,%s*')

if (#note_res_local_table > 1) then

for _, note_res_loc in ipairs(note_res_local_table) do

multiref = multiref * (targs[pre .. 'note_res_' .. note_res_loc] and 1 or 0)

end

else

multiref = 0

end

if multiref > 0 then

for _, note_res_loc in ipairs(note_res_local_table) do

targs[pre .. 'note_res_' .. note_res_loc] = ''

end

elseif targs[pre .. 'note_res_' .. targs[pre .. 'note_res_' .. v]] then

targs[pre .. 'note_res_' .. targs[pre .. 'note_res_' .. v]] = ''

end

targs[pre .. 'note_res_' .. v] = ''

end

if targs[pre .. 'res_col_header'] then

targs[pre .. 'res_col_header'] = ''

end

else

table.insert(missing_results, v)

end

elseif k:find('^match[%d]*_.*_.*_note$') then

local m = mw.ustring.gsub(k, '^(match[%d]*_.*_.*)_note$', '%1')

targs[k] = ''

if targs[m] then

if targs['note_' .. v] then

targs['note_' .. v] = ''

end

-- Great!

else

table.insert(orphaned_match_notes, m)

end

end

end

end

local possible_missing_winpoints = 0

for k,v in pairs(targs) do

if v and v ~= '' then

local found_arg = 0

if type(k) == 'string' then

if k:find('^adjust_points_') then

local p = mw.ustring.gsub(k, '^adjust_points_', '')

if (tonumber(v) or 0) ~= 0 then

local pdiff = (tonumber(targs['win_' .. p] or 0) or 0) + tonumber(v)

if pdiff == 0 then

possible_missing_winpoints = possible_missing_winpoints + 1

else

possible_missing_winpoints = possible_missing_winpoints - 1

end

end

end

if found_arg == 0 and (good_args[k] or k:find('^split[%d][%d]*$')) then

-- Great!

found_arg = 1

end

if found_arg == 0 and k == 'showteam' then

-- Great!

found_arg = 1

if teams[v] ~= 1 then

table.insert(missing_teams, v)

end

end

if found_arg == 0 and (ignored_args[k] or k:find('^att_')) then

found_arg = 1

table.insert(ignored, k)

end

if found_arg == 0 and k:find('^[A-Za-z3-5]*_.*$') then

local p = mw.ustring.gsub(k, '^([A-Za-z3-5]*)_.*$', '%1')

if col_names[p] then

-- Great!

found_arg = 1

end

end

if found_arg == 0 and k:find('^[A-Za-z]*_[A-Za-z]*_.*$') then

local p = mw.ustring.gsub(k, '^([A-Za-z]*_[A-Za-z]*)_.*$', '%1')

if col_names[p] then

-- Great!

found_arg = 1

end

end

if found_arg == 0 and k:find('^match[%d]*_.*_.*$') then

local t1 = mw.ustring.gsub(k, '^match[%d]*_(.*)_(.*)$', '%1')

local t2 = mw.ustring.gsub(k, '^match[%d]*_(.*)_(.*)$', '%2')

found_arg = 1

if teams[t1] == nil or teams[t2] == nil then

if teams[t1] == nil then

table.insert(missing_teams, t1)

end

if teams[t2] == nil then

table.insert(missing_teams, t2)

end

end

end

if found_arg == 0 and k:find('^result_.*_.*$') then

local t1 = mw.ustring.gsub(k, '^result[%d]*_(.*)_(.*)$', '%1')

local t2 = mw.ustring.gsub(k, '^result[%d]*_(.*)_(.*)$', '%2')

found_arg = 1

if teams[t1] == nil or teams[t2] == nil then

if teams[t1] == nil then

table.insert(missing_teams, t1)

end

if teams[t2] == nil then

table.insert(missing_teams, t2)

end

end

end

if found_arg == 0 and (k:find('^name_') or k:find('^short_')) then

found_arg = 1

table.insert(orphaned_names, k)

end

if found_arg == 0 and (k:find('^note_') or k:find('^hth_')) then

found_arg = 1

if (k == 'hth_ABC' and v == 'H2H note') then

table.insert(warn, get_tracking_category(categories.ignored_parameters , 'hth_ABC'))

elseif (k == 'note_ABC' and v == 'Team note') then

table.insert(warn, get_tracking_category(categories.ignored_parameters , 'note_ABC'))

elseif (k == 'note_res_AAA' and v == 'Result note') then

table.insert(warn, get_tracking_category(categories.ignored_parameters , 'note_res_AAA'))

else

table.insert(orphaned_notes, k)

end

end

if found_arg == 0 and (k:find('^col_') or k:find('^text_')) then

found_arg = 1

table.insert(orphaned_results, k)

end

end

if found_arg == 0 then

if pargs[k] and pargs[k] ~= '' then

if tonumber(k) then

k = k .. ' = ' .. v

end

table.insert(possibly_ignored, k)

else

if tonumber(k) then

k = k .. ' = ' .. v

end

table.insert(unknown, k)

end

end

end

end

local bad_char = '[^A-Za-z0-9_%(%)%- ]'

validate_table_values(unknown, categories.unknown_parameters, bad_char, false)

validate_table_values(missing_teams, categories.missing_teams, bad_char, false)

validate_table_values(missing_results, categories.missing_results, bad_char, false)

validate_table_values(orphaned_results, categories.orphaned_results, bad_char, false)

validate_table_values(orphaned_names, categories.orphaned_names, '[^A-Za-z0-9_ ]', false)

validate_table_values(orphaned_notes, categories.orphaned_notes, bad_char, false)

validate_table_values(orphaned_match_notes, categories.orphaned_match_notes, bad_char, false)

validate_table_values(ignored, categories.ignored_parameters, bad_char, false)

validate_table_values(possibly_ignored, categories.possibly_ignored_parameters, bad_char, true)

if possible_missing_winpoints > 1 then

table.insert(track, get_tracking_category(categories.possible_incorrect_winpoints, possible_missing_winpoints))

end

return warn, track

end

return a