-- Stadium server v1.30 for PES 2019 - assign the stadium for either home team or competition
-- Custom content is used, not LiveCPK/game: content\stadium-server is the root
-- author: zlac, 2018-2019
-- originally posted on evo-web

-- local new_stadium_path
local version = "1.30"
local stadiumroot = ".\\content\\stadium-server\\"
local stadium_switched = false
local stadium_name_switched = false
local last_choice
local settings

-- "minus 1" will be applied to all values > 0
local weather_TimeOfDay = 0 -- 0 (in-game selection), 1 (Day), 2 (Night)
local weather_TimeOfDay_Info = {["0"]="Default", ["1"]="Day", ["2"]="Night"}
local weather_Weather = 0 -- 0 (in-game selection), 1 (Fine/Sunny), 2 (Rainy), 3 (Snowy)
local weather_Weather_Info = {["0"]="Default", ["1"]="Fine/Sunny", ["2"]="Rainy", ["3"]="Snowy"}
local weather_WeatherEffects = 0 -- 0 (in-game selection), 3 (Force Rain/snow falling)
local weather_WeatherEffects_Info = {["0"]="Default", ["3"]="Forced"}
local weather_Season = 0 -- 0 (in-game selection), 1 (Summer), 2 (Winter)
local weather_Season_Info = {["0"]="Default", ["1"]="Summer", ["2"]="Winter"}

--[[
local replay_stad_id = nil
local replay_source_stadium_map = nil
local replay_source_stadium_key = nil
]]--

local random_num_comp -- which stadium to select randomly in competition modes from stadium server (depending on entries available per competition in map_competition.txt)
local random_num_exhib -- which stadium to select randomly in exhibition modes from stadium server
local rnd_server_or_cpk -- to serve random stadium from stadium server (depending on entries available per competition in map_competition.txt) or from default .cpk files (i.e. stadium server deactivates itself temporarily)

local team_assignment_map = {}
local competition_assignment_map = {}
local all_stadiums_map = {}
local konami_stadiums_map = {}

local info_text = ""
local weather_text = ""
local manual_stad_idx
local manual_stad_info = "Manually selected stadium: None"
local manual_selection_status = "Off"
local manual_selection_status_info = "Selection mode: automatic map assignments"
local total_stadiums

local _stadium_info = {}
local current_stadium_preview_path

local RELOAD_MAPS_KEY = 0x30 -- 0 key (not the NUMPAD zero!!)
local WEATHER_TIMEOFDAY_KEY = 0x33 -- 3 key (not the NUMPAD 7!!)
local WEATHER_WEATHER_KEY = 0x34 -- 4 key (not the NUMPAD 7!!)
local WEATHER_WEATHER_EFFECTS_KEY = 0x35 -- 5 key (not the NUMPAD 7!!)
local WEATHER_SEASON_KEY = 0x36 -- 6 key (not the NUMPAD 7!!)
local SET_AS_FAVORITE_STAD_KEY = 0x37 -- 7 key (not the NUMPAD 7!!)
local USE_FAVORITE_STAD_KEY = 0x38 -- 8 key (not the NUMPAD 8!!)
local SWITCH_SELECTION_MODE_KEY = 0x39 -- 9 key (not the NUMPAD 9!!)
local DEL_TEXT_KEY = 0x2E
local PREVIOUS_STAD_KEY = 0x21 -- Page Up
local NEXT_STAD_KEY = 0x22 -- Page Down

local stadium_config = {}

-- override_competitions contains comma-separated ID's of the competitions that allow for team-assigned stadiums to have precedence before competiton-assigned stadiums
-- .. e.g. you've assigned a home stadium for ALL exhibition mode matches (tid 65535) in map_competitions.txt, but you still want to use
-- .. custom home-team stadium for those teams that have it assigned in map_teams.txt -> add 65535 in override_competitions
-- .. OR: you have assigned multiple stadiums to be selected randomly (e.g. for EPL) for those teams that do not have their own stadiums, but you 
-- .. still want to use custom home-team stadium for those teams that have it assigned in map_teams.txt -> add 17 too (EPL id) in override_competitions
-- initially, all (at least, i hope so) Exhibition mode, League and League-Cup matches are included in competition overrides
-- BEGIN CUSTOMIZABLE LUA TABLE                         
local override_competitions = {65535,  -- Exhibition matches
								4, -- UCL knockout stage
								6, -- UEL knockout stage
								10, -- Copa Libertadores knockout stage
								16, -- ACL knockout stage 
								17, 79, 23, 83, -- England 1st and 2nd div and cup and play offs
								19, 25, 87, -- Spain 1st div league and cup and supercup (2-legged supercup, home&away matches)
								18, 24, -- Italy 1st div league and cup
								20, 81, 26, -- France 1st and 2nd div and cup
								22, 28, -- Portugal league and cup
								21, 27, -- Netherlands league and cup
								30, 59, -- Argentina league and cup
								29, 31, -- Brazil league and cup
								67, 13400, 13401, 68, -- Chile league (first and second stage) and cup
								50, 53, -- PEU league and cup
								51, 10200, 10201, 54, -- PLA league (first and second stage) and cup
								52, 55, -- PAS league and cup
                                120, 127, -- PEA (China) league and cup
                                115, 155, 156, 157, 158, 159, 122, -- Belgium 1st div (playoff groups 0 to 3, final knockout) and cup
                                116, 123, -- Russia 1st div and cup
                                117, 124, -- Switzerland 1st div and cup
                                118, 125, -- Turkey 1st div and cup
                                119, 23800, 23801, 160, 161, 126, -- Colombia 1st div (first and second stage, knockout 0 and 1) and cup
                                133, 134, 135, 136, 137, -- Scotland 1st div (playoff groups 0 to 2) and cup
                                141, 147, 148, 149, 150, 151, 142, -- Denmark 1st div (playoff groups 0 to 3, final knockout) and cup
                                161, -- Thailand 1st div
								}
-- END CUSTOMIZABLE LUA TABLE

-- specify the IDs of the teams which already have their real homegrounds assigned via .cpk + EDIT00000000
-- if not listed here, their .cpk homeground may be overriden by map_competition.txt assignment ...
-- ... e.g. Barcelona and Camp Nou: if you assign generic stadiums to La Liga in map_competition.txt and DO NOT assign external Camp Nou to Barca via map_teams.txt, then ...
-- ... Barcelona would never use Camp Nou from .cpk in La Liga-related competition modes - it would use one of the random generics for La Liga
-- Only the teams with original Konami stadiums are listed initially (again, hopefully all of them)!
-- ADD YOUR OWN TEAM ID'S, BASED ON YOUR EDIT00000000's STADIUM ASSIGNMENTS FROM THE .CPK PACK THAT YOU USE!!
-- BEGIN CUSTOMIZABLE LUA TABLE 
local teams_with_cpk_homegrounds = {
		10,   -- Netherlands (Johan Cruijff Arena)
		12,   -- Italy (Stadio Olimipco)
		45,   -- Brazil (Estadio do Maracana)
		47,   -- Chile (Estadio Nacional de Chile)
		50,	-- Argentina (El Monumental)
		101,  -- Arsenal (Emirates)
		103,  -- Liverpool (Anfield)
		108,	-- Barcelona (Camp Nou)
		112,  -- Monaco (Stade Louis II)
		116,  -- Ajax (Johan Cruijff Arena)
		119,	-- Internazionale (Giuseppe Meazza)
		121,	-- Milan (San Siro)
		122,  -- Lazio (Stadio Olimpico)
		125,  -- Roma (Stadio Olimpico)
		136,  -- Vasco da Gama (Estadio Sao Januario)
		137,  -- Palmeiras (Allianz Parque)
		138,	-- River Plate (El Monumental)
		139,	-- Boca Juniors (Estadio Alberto J. Armando)
		147,	-- Urawa Red Diamonds (Saitama Stadium 2002)
		184,  -- Schalke 04 (Veltins Arena)
		193,  -- Sporting CP (Jose Alvalade)
		197,  -- Fenerbahce (Ülker stadium)
		274,  -- Cruzeiro (Toca da Raposa III)
		1706,	-- Basel (St. Jakob Park)
		1247, -- Corinthians (Arena Corinthians)
		1248, -- Flamengo (Estadio do Maracana)
		1249, -- Fluminense (Estadio do Maracana)
		1252, -- SC Internacional (Estadio Beira-Rio)
		1254,	-- Santos (Estadio Urbano Caldeira)
		1255,	-- Sao Paulo (Estadio do Morumbi)
		1256, -- Colo Colo (Estadio Monumental)
		2209, -- Universidad Chile (Estadio Nacional de Chile)
		2287, -- Alianza Lima (Estadio Alejandro Villanueva)
      }
-- END CUSTOMIZABLE LUA TABLE


local function nil2str(value)
    if value ~= nil then
        return value
    else
        return "N/A"
    end
end

-- log only if detailed logging is required in config.ini
local function _log(msg)
	-- are settings available & configured?
	if settings and settings["detailed_logging"] then
		if settings["detailed_logging"] == 1 then
			log(msg)
		end
	-- fallback to default logging, if not
	else
		log(msg)
	end
end

local function load_ini(filename)
    local t = {}
    local data = assert(io.lines(stadiumroot .. filename))
    _log(filename .. " found in " .. stadiumroot)

    for line in data do
        local name, value = string.match(line, "^([%w_]+)%s*=%s*([-%w%d.]+)")
        if name and value then
            value = tonumber(value) or value
            t[name] = value
            _log(string.format("Using setting: %s = %s", name, value))
        end
    end
    return t
end

local function load_addon_ini(filename)
    local t = {}
    local data = assert(io.lines(stadiumroot .. filename))
    _log(filename .. " found in " .. stadiumroot)

    for line in data do
        local name, value = string.match(line, "^([%w_]+)%s*=%s*([-%w%d_ .]+)")
        if name and value then
            value = tonumber(value) or value
            t[name] = value
            _log(string.format("Using add-on mod: %s = %s", name, value))
        end
    end
    return t
end

local function save_ini(filename)
    local f = io.open(stadiumroot .. filename, "wt")
    f:write(string.format("# StadiumServer settings. Generated by StadiumServer.lua\n"))
	f:write(string.format("# detailed_logging: 1 = more extensive logging; 0 = bare-bones logging\n"))
    f:write("\n")
    local keys = {}
    for name,value in pairs(settings) do
        keys[#keys + 1] = name
    end
    table.sort(keys)
    for i,name in ipairs(keys) do
        local value = settings[name]
        f:write(string.format("%s = %s\n", name, value))
    end
    f:write("\n")
    f:close()
end


local function file_exists(name)
	local f=io.open(name,"r")
	if f~=nil then 
		io.close(f) 
		return true 
	else 
		return false 
	end
end

-- remove trailing and leading whitespace from string
local function trim(s)
    return s:gsub("^%s*(.-)%s*$", "%1")
end


local function split(s, inSplitPattern)
	local outResults = {}
	-- chop off the trailing comment, if present
	local theCommentStart = string.find( s, "#", 1 )
	local data = s
	if theCommentStart ~= nil then
		data = string.sub(s, 1, theCommentStart-1)
	end

	-- now do the splits by main separator (inSplitPattern)
	local theStart = 1
	local theSplitStart, theSplitEnd = string.find( data, inSplitPattern, theStart )
	while theSplitStart do
		outResults[#outResults+1] = trim(string.sub( data, theStart, theSplitStart-1 ))
		theStart = theSplitEnd + 1
		theSplitStart, theSplitEnd = string.find( data, inSplitPattern, theStart )
	end
	outResults[#outResults+1] = trim(string.sub( data, theStart ))
	return outResults
end

local function clear_table(t)
    for k,v in pairs(t) do
        t[k]=nil
    end
end

local function dump_table(o)
	if type(o) == 'table' then
		local s = '{ '
		for k,v in pairs(o) do
			if type(k) ~= 'number' then k = '"'..k..'"' end
			s = s .. '['..k..'] = ' .. dump_table(v) .. ','
		end
		return s .. '} '
	else
		return tostring(o)
	end
end

local function print_arr(tbl)
    for index, value in ipairs(tbl) do
        log("     " .. value)
    end
end

local function tableLength(T)
    local count = 0
    for _ in pairs(T) do 
        count = count + 1
    end
    return count
end

local function valueArrayExistsInTable(tbl, val, startAt)
    for key, value in pairs(tbl) do
        if val[startAt] == value[1] and val[startAt+1] == value[2] then
            return true
        end
    end
    return false
end

local function compare_stadium_names(a,b)
	return string.lower(a[2]) < string.lower(b[2]) -- {stadium_ID, stadium_name, stadium_path} triplets, compare names
end

local function merge_maps()
    local idx = 1
    local idx_konami = 1
    clear_table(all_stadiums_map)
    clear_table(konami_stadiums_map)

    for key, row in pairs(team_assignment_map) do
        if row[1] ~= nil and row[1] ~= "" and row[2] ~= nil and row[2] ~= "" and row[3] ~= nil and row[3] ~= "" and not valueArrayExistsInTable(all_stadiums_map, row, 1) then
            all_stadiums_map[idx] = {row[1], row[2], row[3]}
            idx = idx + 1
        end
    end

    for key, value in pairs(competition_assignment_map) do
        for index, row in ipairs(value) do
            if row[1] ~= nil and row[1] ~= "" and row[2] ~= nil and row[2] ~= "" and row[3] ~= nil and row[3] ~= "" and not valueArrayExistsInTable(all_stadiums_map, row, 1) then
                all_stadiums_map[idx] = {row[1], row[2], row[3]}
                idx = idx + 1
                if string.match(string.lower(row[3]), "^konami") then -- stadium path begins with Konami ... should be one of the .cpk stadiums
                    konami_stadiums_map[idx_konami] = {row[1], row[2], row[3] }
                    idx_konami = idx_konami + 1
                end
            end
            -- see if the stadium for final match is already included ...
            if row[4] ~= nil and row[4] ~= "" and row[5] ~= nil and row[5] ~= "" and row[6] ~= nil and row[6] ~= "" and not valueArrayExistsInTable(all_stadiums_map, row, 4) then
                all_stadiums_map[idx] = {row[4], row[5], row[6]}
                idx = idx + 1
                if string.match(string.lower(row[6]), "^konami") then -- stadium path begins with Konami ... should be one of the .cpk stadiums
                    konami_stadiums_map[idx_konami] = {row[4], row[5], row[6] }
                    idx_konami = idx_konami + 1
                end
            end
        end
    end

    -- dump_table(konami_stadiums_map)

    total_stadiums = tableLength(all_stadiums_map)
    if total_stadiums > 0 then
        manual_stad_idx = 1
    end
    log(string.format("%s unique stadiums available for random selection in exhibition modes.", total_stadiums))
    table.sort(all_stadiums_map, compare_stadium_names)
    table.sort(konami_stadiums_map, compare_stadium_names)
end

local function load_map_txt(filename)
    local delim = ","
    
    local data = assert(io.lines(stadiumroot .. filename))
    log(filename .. " found in " .. stadiumroot .. filename)

    if filename == "map_teams.txt" then
        clear_table(team_assignment_map)
    end
    if filename == "map_competitions.txt" then
        clear_table(competition_assignment_map)
    end
    
    for line in data do
        line = trim(string.gsub(line, "^\239\187\191", "")) -- removes UTF BOM bytes at the beginning of the first line in .txt file and leading/trailing whitespaces in every line
        local fields = split(line, delim)
        if #fields > 1 then
            for i=1,#fields do
                fields[i] = trim(fields[i])
            end
            if fields[1] ~= nil and fields[1] ~= "" then
                if filename == "map_teams.txt" and fields[2] ~= nil and fields[3] ~= nil and fields[4] ~= nil then
                    team_assignment_map[tonumber(fields[1])] = {fields[2], fields[3], fields[4]}
                    _log(string.format(" ==> %s stadium assignment::  team_id: %s -> stadium_id: %s, stadium: %s (%s)", filename, fields[1], fields[2], fields[4], fields[3]))
                end
                if filename == "map_competitions.txt" and fields[2] ~= nil and fields[3] ~= nil and fields[4] ~= nil and fields[5] ~= nil and fields[6] ~= nil and fields[7] ~= nil then
                    -- competition_assignment_map[tonumber(fields[1])] = {fields[2], fields[3], fields[4], fields[5], fields[6], fields[7]}
                    if competition_assignment_map[tonumber(fields[1])] ~= nil then
                        table.insert(competition_assignment_map[tonumber(fields[1])], {fields[2], fields[3], fields[4], fields[5], fields[6], fields[7]})
                    else
                        competition_assignment_map[tonumber(fields[1])] = { {fields[2], fields[3], fields[4], fields[5], fields[6], fields[7]} }
                    end
                    _log(string.format(" ==> %s stadium assignment::  competition: %s -> stadium_id: %s, stadium: %s (%s) (finals: %s %s (%s))", filename, fields[1], fields[2], fields[4], fields[3], fields[5], fields[7], fields[6]))
                end
            end
        end
    end
end

local function has_value(tab, val)
    for index, value in ipairs(tab) do
        if value == val then
            return true
        end
    end
    return false
end

local function get_random_stad(n)
    log("last_choice was: " .. tostring(last_choice))
    last_choice = last_choice or math.random(1,n)
    log("last_choice now: " .. tostring(last_choice))
    return last_choice
end

local function select_random_stadium_source(ctx)
    local tid = tonumber(ctx.tournament_id)
    
    --select random stadium for exhibition mode
    random_num_exhib = nil
    if tid == 65535 and rnd_server_or_cpk == 1 then
    -- if tid == 65535 and ( rnd_server_or_cpk == 1 or rnd_server_or_cpk == 2) then
        local tblLen = tableLength(all_stadiums_map)
        if tblLen == 1 then
            random_num_exhib = 1
        else
            -- math.randomseed(os.time())
            random_num_exhib = get_random_stad(tblLen) -- math.random(1, tblLen)
            _log(string.format("Selecting random stadium from stadium server for exhibition mode: %s (%s) ", all_stadiums_map[random_num_exhib][1], all_stadiums_map[random_num_exhib][2]))
        end
    end
  
    --now for competiton modes ... whenever game selects new home_team, pick a random index of a stadium to be used on competition level (e.g. if multiple stadiums are assigned to one competition_ID)
    random_num_comp = nil
    if tid < 65535 and competition_assignment_map[tid] ~= nil then
        if #competition_assignment_map[tid] == 1 then
            -- if there's only one stadium assigned to competition, set "random" number to 1
            random_num_comp = 1 
        else
            -- if there are more stadiums, select one index rendomly
            -- math.randomseed(os.time())
            random_num_comp = get_random_stad(#competition_assignment_map[tid]) -- math.random(1, #competition_assignment_map[tid])
            _log("Selecting random stadium for competition ID " .. tostring(tid) .. ": Stadium no. " .. tostring(random_num_comp) .. " (from " .. tostring(#competition_assignment_map[tid]) .. " stadium(s) available)")
        end
    end

end



local function teams_selected(ctx, team_id)
    local tid = tonumber(ctx.tournament_id)

    -- set_stadium event is called multiple times ... stadium_switched = false would be better initialized when both team ID's are known???
	stadium_switched = false
	stadium_name_switched = false
    -- first_pass_done = false
	last_choice = nil
	
	if manual_selection_status == "off" then
		manual_selection_status_info = "Selection mode: automatic map assignments"
		manual_stad_info = string.format("Manually selected stadium: None")
		current_stadium_preview_path = nil
	end

    -- if in-game stadium settings for exhibition modes are set to 'Random', then decide where to choose the stadium from - stadium server or .cpk
    --[[
    math.randomseed(os.time())
    rnd_server_or_cpk = math.random(1, 100)
    if rnd_server_or_cpk % 2 == 0 then
        rnd_server_or_cpk = 1 -- if even number, use stadium from stadium server
    else
        rnd_server_or_cpk = 2 -- otherwise if odd, use stadium from .cpk
    end
    ]]--
    -- newer approach, sider 5.1.4 - easier for getting Konami stadium previews, all Konami stadiums must be assigned in map_competitions.txt to ID 0
    rnd_server_or_cpk = 1 -- always use stadium server as a source, Konami's stadiums are listed too
    _log("If 'Random' in-game setting will be used in exhibition modes:: Source of random stadiums - either stadium server (1) or from .cpk (2): " .. tostring(rnd_server_or_cpk) )
  
end


local function is_it_stadium_file(filename)
    filename = string.lower(filename)

    if
        string.match(filename, "asset\\model\\bg\\common") or -- sweeping match of every gfx-related common asset for stadiums (too generic, perhaps??)
        string.match(filename, "asset\\model\\bg\\st%d%d%d") or -- every stadium-specific asset (stXXX)

        -- adboards? better to avoid them ... only allow custom config.xml database, for stadiums that want to remove adboards completely via blank template
		string.match(filename, "common\\bg\\model\\bg\\bill\\config\\config%.xml") or -- adboards config database

        string.match(filename, "common\\bg\\model\\bg\\draw_parameter") or
        string.match(filename, "common\\bg\\model\\bg\\tv") or

        -- stadium names mentioned in commentary
        string.match(filename, "%a%a%a\\sound\\awb\\50_main%.awb") or

        string.match(filename, "common\\demo\\fixdemo") or
        string.match(filename, "common\\demo\\fixdemoobj") or
        string.match(filename, "common\\demo\\light") or
        string.match(filename, "common\\demo\\mob") or
        string.match(filename, "common\\demo\\prop") or

        string.match(filename, "common\\render\\model\\bg\\hit\\stadium")
    then
        return true
    else
        return false
    end
end

local function which_stadium_preview_tex(filename)
    return string.match(string.lower(filename), "common\\render\\thumbnail\\stadium\\(st%d+%.dds)")
end

local function get_stadium_preview_path(stadium_info)
    if stadium_info then
        local stadium_id = stadium_info[1]
        local stadium_path = stadium_info[3]
		-- log("Overlay preview path: " .. string.format("%s%s\\common\\render\\thumbnail\\stadium\\st%03d.dds", stadiumroot, stadium_path, stadium_id))
        return string.format("%s%s\\common\\render\\thumbnail\\stadium\\st%03d.dds", stadiumroot, stadium_path, stadium_id)
    end
end

local function get_new_stadium_path(ctx)
    local tid = tonumber(ctx.tournament_id)
    local stadium_path
    local custom_st_id
    local custom_name
    
    -- if tid and not ctx.is_replay_gallery then
    if tid then
		if tid == 65535 then
			if manual_selection_status == "On" and manual_stad_idx then
				-- manual selection from overlay trumps everything
				stadium_path = all_stadiums_map[manual_stad_idx][3]
				custom_name = all_stadiums_map[manual_stad_idx][2]
				custom_st_id = all_stadiums_map[manual_stad_idx][1]
			elseif rnd_server_or_cpk and rnd_server_or_cpk == 1 and ctx.stadium_choice == 254 and random_num_exhib ~= nil then
				-- special case for exhibition mode with random stadium selection enabled (stadium from stadium server (rnd_server_or_cpk == 1) ...
				stadium_path = all_stadiums_map[random_num_exhib][3]
				custom_name = all_stadiums_map[random_num_exhib][2]
				custom_st_id = all_stadiums_map[random_num_exhib][1]
			elseif rnd_server_or_cpk and rnd_server_or_cpk == 2 and ctx.stadium_choice == 254 then
                return -- just leave, random .cpk stadium has been selected in exhibition mode
			elseif ctx.stadium_choice == 253 then
				if ctx.home_team ~= nil and team_assignment_map[ctx.home_team] ~= nil then 
					-- individual home team assignments from map_teams.txt will be used here
					stadium_path = team_assignment_map[ctx.home_team][3]
					custom_name = team_assignment_map[ctx.home_team][2]
					custom_st_id = team_assignment_map[ctx.home_team][1]
				end
			end
		else
			if manual_selection_status == "On" and manual_stad_idx then
				-- manual selection from overlay trumps everything
				stadium_path = all_stadiums_map[manual_stad_idx][3]
				custom_name = all_stadiums_map[manual_stad_idx][2]
				custom_st_id = all_stadiums_map[manual_stad_idx][1]
			
			elseif competition_assignment_map[tid] == nil and team_assignment_map[ctx.home_team] ~= nil and has_value(teams_with_cpk_homegrounds, ctx.home_team) == false then
				-- this particular competiton mode does not have the stadium assigned via map_competitions.txt
				-- .. individual home team assignments from map_teams.txt will be used here, if the team does not already ...
                -- .. have exclusive .cpk stadium homeground
				stadium_path = team_assignment_map[ctx.home_team][3]
				custom_name = team_assignment_map[ctx.home_team][2]
				custom_st_id = team_assignment_map[ctx.home_team][1]
			elseif competition_assignment_map[tid] ~= nil and team_assignment_map[ctx.home_team] ~= nil and has_value(override_competitions, tid)
                    and has_value(teams_with_cpk_homegrounds, ctx.home_team) == false and ctx.match_info ~= 53 then
				-- this particular competiton mode HAS the stadium assigned via map_competitions.txt,
				-- .. but it is also listed in override_competitions, 
				-- .. AND it is not FINAL match (e.g. in league cup, which may possibly be held at neutral ground - and having stadium assigned already in map_competitions.txt), 
				-- .. AND the team DOES NOT have .cpk exclusive homeground,
                -- .. therefore, individual home team assignments from map_teams.txt will be used here again
				stadium_path = team_assignment_map[ctx.home_team][3]
				custom_name = team_assignment_map[ctx.home_team][2]
				custom_st_id = team_assignment_map[ctx.home_team][1]
			else
				-- nothing else but possible competition assignment in map_competitions.txt
				-- .. stadium from assignment from map_competitions.txt will be used, if there is any
				if tid < 65535 and competition_assignment_map[tid] ~= nil then
					if ctx.match_info == 53 and competition_assignment_map[tid][random_num_comp][4] ~= "" and competition_assignment_map[tid][random_num_comp][5] ~= "" and competition_assignment_map[tid][random_num_comp][6] ~= "" then
						-- is this the final match of a competition (53)?
						stadium_path = competition_assignment_map[tid][random_num_comp][6] -- use the stadium assigned for final match
						custom_name = competition_assignment_map[tid][random_num_comp][5]
						custom_st_id = competition_assignment_map[tid][random_num_comp][4]
					elseif has_value(teams_with_cpk_homegrounds, ctx.home_team) == false and
                            competition_assignment_map[tid][random_num_comp][1] ~= "" and competition_assignment_map[tid][random_num_comp][2] ~= "" and
                            competition_assignment_map[tid][random_num_comp][3] ~= "" then
						stadium_path = competition_assignment_map[tid][random_num_comp][3]  -- use the regular stadium assigned for this competition
						custom_name = competition_assignment_map[tid][random_num_comp][2]
						custom_st_id = competition_assignment_map[tid][random_num_comp][1]
					end
				end
			end
		end
    --[[
    elseif ctx.is_replay_gallery and ctx.is_replay_gallery == true then
        if replay_source_stadium_map == "all_stadiums_map" then
            stadium_path = all_stadiums_map[replay_source_stadium_key][3]
            custom_name = all_stadiums_map[replay_source_stadium_key][2]
            custom_st_id = all_stadiums_map[replay_source_stadium_key][1]
        elseif replay_source_stadium_map == "team_assignment_map" then
            stadium_path = team_assignment_map[replay_source_stadium_key][3]
            custom_name = team_assignment_map[replay_source_stadium_key][2]
            custom_st_id = team_assignment_map[replay_source_stadium_key][1]
        end
    ]]--
    end
	
    return stadium_path, custom_st_id, custom_name
end

local function get_stadium_addon_config(ctx, stadium_path)
    local t = {}
    if file_exists(stadiumroot .. stadium_path .. "\\AddOn\\addon_config.ini") then
        t = load_addon_ini(stadium_path .. "\\AddOn\\addon_config.ini")
        return t
    end
end

local function check_for_addon_override(ctx, stadium_path, st_id, filename)
	if stadium_path and st_id and filename then
        local override_found = false
		local weatherPrefix = nil
		if ctx.season == 0 and ctx.timeofday == 0 then
			weatherPrefix = "Summer_Day"
		elseif ctx.season == 0 and ctx.timeofday == 1 then
			weatherPrefix = "Summer_Night"
		elseif ctx.season == 1 and ctx.timeofday == 0 then
			weatherPrefix = "Winter_Day"
		elseif ctx.season == 1 and ctx.timeofday == 1 then
			weatherPrefix = "Winter_Night"
        end

        if ctx.stadserv_addons_list then
            -- weather-specific files for a specific stadium have priority ...
            if override_found == false and weatherPrefix then
                for idx_key, mod_name in pairs(ctx.stadserv_addons_list) do
                    if file_exists(stadiumroot .. stadium_path .. "\\AddOn\\" .. mod_name .. "\\" .. st_id .. "\\" .. weatherPrefix .. "\\" .. filename) then
                        _log("Weather-specific, fixed-stadium AddOn file found: " .. stadium_path .. "\\AddOn\\" .. mod_name .. "\\".. st_id .. "\\" .. weatherPrefix .. "\\" .. filename )
			            stadium_path = stadium_path .. "\\AddOn\\" .. mod_name .. "\\".. st_id .. "\\" .. weatherPrefix
						-- _log("stadium_path (weather-specific): " .. stadium_path)
                        override_found = true
                        break
                    end
                end
                -- if not weather-specific, then perhaps there is a non weather-specific version of a file for a specific stadium id?
                if override_found == false then
                    for idx_key, mod_name in pairs(ctx.stadserv_addons_list) do
                        if file_exists(stadiumroot .. stadium_path .. "\\AddOn\\" .. mod_name .. "\\".. st_id .. "\\Any_Weather\\" .. filename) then
                            _log("Non-weather specific, fixed-stadium AddOn file found: " .. stadium_path .. "\\AddOn\\" .. mod_name .. "\\".. st_id .. "\\Any_Weather\\" .. filename )
                            stadium_path = stadium_path .. "\\AddOn\\" .. mod_name .. "\\".. st_id.. "\\Any_Weather"
							-- _log("stadium_path (non-weather specific): " .. stadium_path)
                            override_found = true
                            break
                        end
                    end

                    -- if not non-weather fixed-stadium file too, then perhaps there is a generic version of a file for any weather and any stadium id?
                    if override_found == false then
                        for idx_key, mod_name in pairs(ctx.stadserv_addons_list) do
                            if file_exists(stadiumroot .. stadium_path .. "\\AddOn\\" .. mod_name .. "\\Global\\" .. filename) then
                                _log("Global AddOn file found: " .. stadium_path .. "\\AddOn\\" .. mod_name .. "\\Global\\" .. filename )
                                stadium_path = stadium_path .. "\\AddOn\\" .. mod_name .. "\\Global"
								-- _log("stadium_path (global): " .. stadium_path)
                                break
                            end
                        end

                        -- if not stadium/pack-global file too, then perhaps there is a uber-generic version of a file for an entire stadium server?
                        if override_found == false then
                            if file_exists(stadiumroot ..  "\\Super-Global\\" .. filename) then
                                _log("StadiumServer-Global AddOn file found: " .. "Super-Global\\" .. filename )
                                stadium_path = "\\Super-Global"
                                -- _log("stadium_path (super-global): " .. stadium_path)
                            end
                        end
                    end
                end
            end
        end

	end
	
	return stadium_path

end

local function make_key(ctx, filename)
    local custom_st_id
    local custom_name
    -- if ctx.is_edit_mode == nil and stadium_switched == true then -- do something only if edit mode is NOT active
    if stadium_switched == true then
        if is_it_stadium_file(filename) then -- any stadium file, but preview
            local new_stadium_path
            local custom_st_id
            local custom_name
            new_stadium_path, custom_st_id, custom_name = get_new_stadium_path(ctx)
			if new_stadium_path and custom_st_id then
            -- if new_stadium_path and custom_st_id and file_exists(stadiumroot .. new_stadium_path .. "\\" .. filename) then
				-- log(string.format("new_stadium_path: %s", new_stadium_path .. "\\" .. filename))
				if string.match(string.lower(filename), "common\\bg\\model\\bg\\bill\\config\\config.xml") then
					if file_exists(stadiumroot .. new_stadium_path .. "\\" .. filename) then
						log("Custom adboards config.xml found: " .. new_stadium_path .. "\\" .. filename)
					end
				end
				-- let's check for possible AddOn files ...
				new_stadium_path = check_for_addon_override(ctx, new_stadium_path, custom_st_id, filename)
			
				return new_stadium_path .. "\\" .. filename
            end
        end
        -- now override the preview, if the stadium has already been predetermined by the game
        local spt_fname = which_stadium_preview_tex(filename)
        if spt_fname then
            local new_stadium_path
            local custom_st_id
            local custom_name
            new_stadium_path, custom_st_id, custom_name = get_new_stadium_path(ctx)
            if new_stadium_path then
                return string.gsub(new_stadium_path .. "\\" .. filename, "\\st%d%d%d%.dds", string.format("\\st%s.dds", custom_st_id))
            end
        end
    end
end

local function get_filepath(ctx, filename, key)
    -- if ctx.is_edit_mode == nil then -- do something only if edit mode is NOT active

        if key and filename and filename ~= key then -- filename ~= key shoud ensure that it really is a file from custom repository, with modified path prefix???
            -- log(string.format("Stadium file assignment for team ID %s (competition ID %s) - %s\\%s", nil2str(ctx.home_team), nil2str(ctx.tournament_id), stadiumroot, key))
            return string.format("%s\\%s", stadiumroot, key)
        end
    -- end
end


local function get_stadium_data_from_konami_stadiums_map(stadium_id)
    if stadium_id then
        for key, value in pairs(konami_stadiums_map) do
            if value[1] == string.format("%03d", stadium_id) then
                return value[2], value[3]
            end
        end
    end
end

-- this event allows only stadium_id to be changed in options!! other params are read-only (time of day/weather/weather effects/season)
local function set_stadium(ctx, options)
    random_num_exhib = nil
    random_num_comp = nil

    -- if ctx.is_edit_mode == nil and ctx.tournament_id then
	-- if ctx.tournament_id and first_pass_done == true then
	if ctx.tournament_id then
        local tid = tonumber(ctx.tournament_id)
        local custom_st_id
        local custom_name
        local custom_path
        local map_source
        
		if tid == 65535 then
			if manual_selection_status == "On" and manual_stad_idx then
				-- manual selection from overlay trumps everything
				custom_st_id = all_stadiums_map[manual_stad_idx][1]
				custom_name = all_stadiums_map[manual_stad_idx][2]
                custom_path = all_stadiums_map[manual_stad_idx][3]
				stadium_switched = true
				log("Switching to stadium with ID " .. custom_st_id .. " (exhibition mode, manual selection via overlay)")
            elseif ctx.stadium_choice and ctx.stadium_choice ~= 253 and ctx.stadium_choice ~= 254 then
				-- exhibition modes, and the choice is neither "Home stadium" nor "Random" (i.e. - the choice is fixed stadium)
				-- therefore, do not change the stadium
				return
			elseif ctx.stadium_choice and ctx.stadium_choice == 253 and has_value(teams_with_cpk_homegrounds, ctx.home_team) then
				-- exhibition modes, the choice is "Home", but the team is listed to use exclusive .cpk home ground
				-- therefore, do not change the stadium
				return
			elseif ctx.stadium_choice and ctx.stadium_choice == 253 then
				-- handle home team assignment via map_teams.txt
				if manual_selection_status == "On" and manual_stad_idx then
					-- manual selection from overlay trumps everything
					custom_st_id = all_stadiums_map[manual_stad_idx][1]
					custom_name = all_stadiums_map[manual_stad_idx][2]
                    custom_path = all_stadiums_map[manual_stad_idx][3]
					stadium_switched = true
					log("Switching to stadium with ID " .. custom_st_id .. " (exhibition mode, manual selection via overlay)")
				elseif ctx.home_team ~= nil and team_assignment_map[ctx.home_team] ~= nil then
					custom_st_id = team_assignment_map[ctx.home_team][1]
					custom_name = team_assignment_map[ctx.home_team][2]
                    custom_path = team_assignment_map[ctx.home_team][3]
					stadium_switched = true
					map_source = "exhibition mode, team-level assignment"
					log("Switching to stadium with ID " .. custom_st_id .. " (exhibition mode, team-level assignment)")
				end
			elseif ctx.stadium_choice and ctx.stadium_choice == 254 then
				-- exhibition modes, the choice is "Random"
				-- change the stadium depending on the value of rnd_server_or_cpk
                -- select_random_stadium_source(ctx)
				if rnd_server_or_cpk then
					if rnd_server_or_cpk == 2 then
						-- if .cpk is the source (rnd_server_or_cpk == 2), do not change the stadium
                        select_random_stadium_source(ctx)
						map_source = "exhibition mode, random assignment (stadium from .cpk selected)"
						manual_selection_status_info = string.format("Selection mode: %s)", map_source)
                        return
					else
						-- Random setting in exhibition modes, stadium server is the source - always allow for random selection, even if the team has exclusive .cpk home ground
						select_random_stadium_source(ctx)
                        custom_st_id = all_stadiums_map[random_num_exhib][1]
                        custom_name = all_stadiums_map[random_num_exhib][2]
                        custom_path = all_stadiums_map[random_num_exhib][3]
                        stadium_switched = true
                        -- map_source = "exhibition mode, random assignment (stadium from stadium-server selected)"
                        map_source = "exhibition mode, random assignment"
                        -- log("Switching to stadium with ID " .. custom_st_id .. " (" .. custom_name .. ")" .. " exhibition mode, random assignment (stadium from stadium-server selected)")
                        log("Switching to stadium with ID " .. custom_st_id .. " (" .. custom_name .. ")" .. " exhibition mode, random assignment")
					end
				end
			end
        else			
			if manual_selection_status == "On" and manual_stad_idx then
				-- manual selection from overlay trumps everything
				custom_st_id = all_stadiums_map[manual_stad_idx][1]
				custom_name = all_stadiums_map[manual_stad_idx][2]
                custom_path = all_stadiums_map[manual_stad_idx][3]
				stadium_switched = true
				log("Switching to stadium with ID " .. custom_st_id .. " (competition mode, manual selection via overlay)")
			elseif ctx.home_team ~= nil and competition_assignment_map[tid] == nil and team_assignment_map[ctx.home_team] ~= nil then
				custom_st_id = team_assignment_map[ctx.home_team][1]
				custom_name = team_assignment_map[ctx.home_team][2]
                custom_path = team_assignment_map[ctx.home_team][3]
				stadium_switched = true
				map_source = "competition mode, team-level assignment"
				log("Switching to stadium with ID " .. custom_st_id .. " (competition mode, team-level assignment)")
			elseif ctx.home_team ~= nil and competition_assignment_map[tid] ~= nil and team_assignment_map[ctx.home_team] ~= nil and has_value(override_competitions, tid) == true and ctx.match_info ~= 53 then
				-- comptition assignment will be overriden by team assignment
				custom_st_id = team_assignment_map[ctx.home_team][1]
				custom_name = team_assignment_map[ctx.home_team][2]
                custom_path = team_assignment_map[ctx.home_team][3]
				stadium_switched = true
				map_source = "competition mode, team-level assignment (overrides competition-level assignment)"
				log("Switching to stadium with ID " .. custom_st_id .. " (competition mode, team-level assignment (overrides competition-level assignment))")
			elseif tid < 65535 and competition_assignment_map[tid] ~= nil then
				select_random_stadium_source(ctx)
				if ctx.match_info == 53 and competition_assignment_map[tid][random_num_comp][4] ~= "" and competition_assignment_map[tid][random_num_comp][5] ~= "" and competition_assignment_map[tid][random_num_comp][6] ~= "" then
					-- is this the final match of a competition (53)?
					custom_st_id = competition_assignment_map[tid][random_num_comp][4]
					custom_name = competition_assignment_map[tid][random_num_comp][5]
                    custom_path = competition_assignment_map[tid][random_num_comp][6]
					stadium_switched = true
					map_source = "competition mode (final match), competition-level assignment"
					log("Switching to stadium with ID " .. custom_st_id .. " (competition mode (final match of the competition), competition-level assignment)")
				else 
					if has_value(teams_with_cpk_homegrounds, ctx.home_team) == false and competition_assignment_map[tid][random_num_comp][1] ~= "" and competition_assignment_map[tid][random_num_comp][2] ~= "" and competition_assignment_map[tid][random_num_comp][3] ~= "" then
						-- competition mode, pre-finals, no exclusive .cpk home ground -> change the stadium
						custom_st_id = competition_assignment_map[tid][random_num_comp][1]
						custom_name = competition_assignment_map[tid][random_num_comp][2]
                        custom_path = competition_assignment_map[tid][random_num_comp][3]
						stadium_switched = true
						map_source = "competition mode, competition-level assignment"
						log("Switching to stadium with ID " .. custom_st_id .. " (competition mode (pre-finals stage of the competition), competition-level assignment)")
					end
                end
            end
		
		end

        if stadium_switched == true then
            -- get_stadium_config(ctx)
            ctx.stadserv_addons_list = get_stadium_addon_config(ctx, custom_path) or {}
            --log("After get_stadium_addon_config - addons_list dump: ")
            --for k, v in pairs(ctx.stadserv_addons_list) do
            --    log(k.. ": " .. v)
            --end
            if manual_selection_status == "Off" then
				if custom_name then
					manual_selection_status_info = string.format("Selection mode: automatic map assignments (using stadium %s, %s)", custom_name, map_source)
				elseif not custom_name then
					manual_selection_status_info = string.format("Selection mode: %s)", map_source)
				end
            end
			if custom_st_id and custom_path then
				_stadium_info[1] = custom_st_id
				_stadium_info[2] = custom_name
				_stadium_info[3] = custom_path
				current_stadium_preview_path = get_stadium_preview_path(_stadium_info)
				_log("current_stadium_preview_path: " .. current_stadium_preview_path)
			end
            return { stadium = tonumber(custom_st_id) } -- Stadium id of the served stadium
        else
			current_stadium_preview_path = nil
            if manual_selection_status == "Off" then
				if ctx.stadium_choice and ctx.stadium_choice == 254 and rnd_server_or_cpk and rnd_server_or_cpk == 2 then
					manual_selection_status_info = string.format("Selection mode: %s)", map_source)
				else
					manual_selection_status_info = string.format("Selection mode: automatic map assignments (using stadium: %s)", "Custom stadium not assigned, reverting to default")
				end
			end
        end
    -- elseif ctx.tournament_id and first_pass_done == false then
    --    first_pass_done = true
    end
end


local function change_gfx_preview_fallback(ctx)
    -- bound to after_set_conditions event -- use it only for matches where .cpk stadiums are used, to override potentialy old data
    local custom_name
    local custom_path
    local tid = ctx.tournament_id

    if tid == 65535 and ctx.stadium_choice and ctx.stadium_choice ~= 253 and ctx.stadium_choice ~= 254 then
        -- exhibition modes, and the choice is neither "Home stadium" nor "Random" (i.e. - the choice is fixed stadium)
        custom_name, custom_path = get_stadium_data_from_konami_stadiums_map(ctx.stadium_choice)
        if custom_name and custom_path then
            current_stadium_preview_path = string.format("%s%s\\common\\render\\thumbnail\\stadium\\st%03d.dds", stadiumroot, custom_path, ctx.stadium_choice)
            manual_selection_status_info = string.format("Selection mode: exhibition mode (%s: %s)", "Fixed stadium from in-game menu", custom_name)
        else
            manual_selection_status_info = string.format("Selection mode: exhibition mode (using stadium: %s)", "Fixed stadium from in-game menu")
            current_stadium_preview_path = nil
        end
    elseif tid == 65535 and ctx.stadium_choice and ctx.stadium_choice == 253 and has_value(teams_with_cpk_homegrounds, ctx.home_team) then
        -- exhibition modes, the choice is "Home", but the team is listed to use exclusive .cpk home ground
        custom_name, custom_path = get_stadium_data_from_konami_stadiums_map(ctx.stadium)
        if custom_name and custom_path then
            current_stadium_preview_path = string.format("%s%s\\common\\render\\thumbnail\\stadium\\st%03d.dds", stadiumroot, custom_path, ctx.stadium)
            manual_selection_status_info = string.format("Selection mode: exhibition mode (%s: %s)", "Exclusive .cpk homeground", custom_name)
        else
            manual_selection_status_info = string.format("Selection mode: exhibition mode (using stadium: %s)", "Exclusive .cpk homeground")
            current_stadium_preview_path = nil
        end
    elseif tid < 65535 and competition_assignment_map[tid] == nil then
        -- no assignment for home team, no assignment to competition ... one of the default .cpk stadiums was probably selected
        -- just handle the preview and name on overlay
        custom_name, custom_path = get_stadium_data_from_konami_stadiums_map(ctx.stadium)
        if custom_name and custom_path then
            current_stadium_preview_path = string.format("%s%s\\common\\render\\thumbnail\\stadium\\st%03d.dds", stadiumroot, custom_path, ctx.stadium)
            manual_selection_status_info = string.format("Selection mode: competition mode (%s: %s)", ".cpk stadium", custom_name)
        else
            manual_selection_status_info = string.format("Selection mode: competition mode (using stadium: %s)", ".cpk stadium")
            current_stadium_preview_path = nil
        end
	elseif tid < 65535 and competition_assignment_map[tid] ~= nil and has_value(teams_with_cpk_homegrounds, ctx.home_team) and ctx.match_info ~= 53 then
        -- competition has assignments, but home team uses exclusive .cpk home ground ... one of the default .cpk stadiums is selected
        -- just handle the preview and name on overlay
        custom_name, custom_path = get_stadium_data_from_konami_stadiums_map(ctx.stadium)
        if custom_name and custom_path then
            current_stadium_preview_path = string.format("%s%s\\common\\render\\thumbnail\\stadium\\st%03d.dds", stadiumroot, custom_path, ctx.stadium)
            manual_selection_status_info = string.format("Selection mode: competition mode (%s: %s)", "Exclusive .cpk homeground", custom_name)
        else
            manual_selection_status_info = string.format("Selection mode: competition mode (using stadium: %s)", "Exclusive .cpk homeground")
            current_stadium_preview_path = nil
        end

    end

end


local function change_stadium_name(ctx, stadium_name, stadium_id)
    -- if ctx.is_edit_mode == nil then -- do something only if edit mode is NOT active
    if ctx.tournament_id then -- ctx.tournament_id should not be available in EDIT mode ...
		if ctx.stadium_choice and ctx.tournament_id == 65535 and not stadium_switched then
            -- if it is exhibition mode and stadium selection has not been finalized yet ==> then do nothing.
            return
        end

        local new_stadium_path
        local custom_st_id
        local new_stadium_name
        
        new_stadium_path, custom_st_id, new_stadium_name = get_new_stadium_path(ctx)
        if new_stadium_name ~= nil and new_stadium_name ~= "" then
            _log(string.format("switching stadium-name: %s --> %s", stadium_name, new_stadium_name))
            stadium_name_switched = true
            return new_stadium_name
        end
    end
end

local function set_weather_conditions(ctx, options)
    local changed = false
	local external_opts = nil
	
	-- initial check if season is set via overlay - WeatherConditions.lua makes decisions based on season
	if weather_Season > 0 then
        options.season = weather_Season - 1
    end

	-- delegate weather decisions to WeatherConditions module
	if file_exists(ctx.sider_dir .. "\\modules\\WeatherConditions.lua") and ctx.weather_conditions then
		_log("StadiumServer calling WeatherConditions ... ")
		external_opts = ctx.weather_conditions.set_conditions(ctx, options, "StadiumServer")
		if external_opts then
			changed = true
			options = external_opts
		end
		_log("StadiumServer finished calling WeatherConditions.")
	else
		log("WeatherConditions.lua script not found or its' weather_conditions context is not available ...")
		log("Script path: " .. ctx.sider_dir .. "\\modules\\WeatherConditions.lua")
		log("ctx.weather_conditions status: " .. nil2str(ctx.weather_conditions))
	end
	
	-- and now override options returned from WeatherConditions.lua, if non-default settings are selected via stadium-server's overlay
    if weather_TimeOfDay > 0 then
        options.timeofday = weather_TimeOfDay - 1
        changed = true
    end
    if weather_Weather > 0 then
        options.weather = weather_Weather - 1
        changed = true
    end
    if weather_WeatherEffects > 0 then
        options.weather_effects = weather_WeatherEffects - 1
        changed = true
    end
    if weather_Season > 0 then
        options.season = weather_Season - 1
        changed = true
    end

    if changed then
        return options
    end

end

local opts = { image_width = 0.3, image_aspect_ratio = 1.777778 }
local function overlay_on(ctx)
    weather_text = string.format("Weather settings: Time of day (%s), Type of weather (%s), Force rain/snow (%s), Season (%s)\n",
            weather_TimeOfDay_Info[tostring(weather_TimeOfDay)],
            weather_Weather_Info[tostring(weather_Weather)],
            weather_WeatherEffects_Info[tostring(weather_WeatherEffects)],
            weather_Season_Info[tostring(weather_Season)]
    )
    
	local text = string.format("version %s\nStadiumServer commands:\nPress [0] to reload map .txt files\nPress [DEL] to clear info messages\n\nWeather options (always active, unless set to 'Default'):\n       [3] To select time of day\n       [4] To select type of weather\n       [5] To enforce rain/snow\n       [6] To select season of the year\n       %s\nPress [9] to switch between using map assignments/manual selection\n     Manual selection mode subcommands:\n       [PageUp][PageDn] to manually select previous/next stadium\n       [7] to set current manual selection as favorite stadium\n       [8] to use your favorite stadium \n\n%s\n%s\n\n%s", version, weather_text, manual_selection_status_info, manual_stad_info, info_text)
	local image = current_stadium_preview_path
    -- if image and ctx.stadium and not file_exists(current_stadium_preview_path) then
        -- let's try with super-global folder, for Konami's .cpk stadium previews
    --    current_stadium_preview_path = string.format("%s\\Super-Global\\common\\render\\thumbnail\\stadium\\st%03d.dds", stadiumroot, ctx.stadium)
    -- end
	
	return text, image, opts
end

local function key_down(ctx, vkey)
    if vkey == RELOAD_MAPS_KEY then
        _log("Starting manual map files reload ... ")
        load_map_txt("map_teams.txt")
        load_map_txt("map_competitions.txt")
        merge_maps()
        manual_stad_idx = nil
        manual_stad_info = "Manually selected stadium: None"
        if total_stadiums > 0 then
            manual_stad_idx = 1
        end
        info_text = info_text .. "map_teams.txt and map_competitions.txt reloaded\n"
        _log("Manual map files reloading finished.")
    elseif vkey == DEL_TEXT_KEY then
        info_text = ""
    elseif vkey == SWITCH_SELECTION_MODE_KEY then
        if manual_selection_status == "Off" then
            manual_selection_status = "On"
            manual_selection_status_info = "Selection mode: manual selection [PageUp]/[PageDn]"
            manual_stad_info = string.format("Manually selected stadium: %s\n", all_stadiums_map[manual_stad_idx][2])
			current_stadium_preview_path = get_stadium_preview_path(all_stadiums_map[manual_stad_idx])
        else
            manual_selection_status = "Off"
            manual_selection_status_info = "Selection mode: automatic map assignments"
            manual_stad_info = string.format("Manually selected stadium: None")
            info_text = ""
			current_stadium_preview_path = nil
        end
    elseif vkey == PREVIOUS_STAD_KEY then
        if manual_selection_status == "On" and total_stadiums > 0 and manual_stad_idx then
            manual_stad_idx = manual_stad_idx - 1
            if manual_stad_idx < 1 then
                manual_stad_idx = total_stadiums
            end
            manual_stad_info = string.format("Manually selected stadium: %s\n", all_stadiums_map[manual_stad_idx][2])
			current_stadium_preview_path = get_stadium_preview_path(all_stadiums_map[manual_stad_idx])
        end
    elseif vkey == NEXT_STAD_KEY then
        if manual_selection_status == "On" and total_stadiums > 0 and manual_stad_idx then
            manual_stad_idx = manual_stad_idx + 1
            if manual_stad_idx > total_stadiums then
                manual_stad_idx = 1
            end
            manual_stad_info = string.format("Manually selected stadium: %s\n", all_stadiums_map[manual_stad_idx][2])
			current_stadium_preview_path = get_stadium_preview_path(all_stadiums_map[manual_stad_idx])
        end
    elseif vkey == SET_AS_FAVORITE_STAD_KEY then
        if manual_selection_status == "On" and manual_stad_idx then
            if all_stadiums_map[manual_stad_idx] then
                settings["favorite_stadium"] = manual_stad_idx
                save_ini("config.ini")
                info_text = info_text .. string.format("Stadium %s saved as favorite\n", all_stadiums_map[manual_stad_idx][2])
            else
                info_text = info_text .. "Could not save favorite stadium\n"
            end
        end
    elseif vkey == USE_FAVORITE_STAD_KEY then
        if manual_selection_status == "On" and settings["favorite_stadium"] then
            if all_stadiums_map[tonumber(settings["favorite_stadium"])] then
                manual_stad_idx = settings["favorite_stadium"]
                manual_stad_info = string.format("Manually selected stadium: %s\n", all_stadiums_map[manual_stad_idx][2])
                info_text = info_text .. string.format("Favorite stadium %s set as active\n", all_stadiums_map[manual_stad_idx][2])
				current_stadium_preview_path = get_stadium_preview_path(all_stadiums_map[manual_stad_idx])
            else
                info_text = info_text .. string.format("Could not find favorite stadium (idx: %s)\n", settings["favorite_stadium"])
            end
        end
    elseif vkey == WEATHER_TIMEOFDAY_KEY then
        weather_TimeOfDay = weather_TimeOfDay + 1
        if weather_TimeOfDay > 2 then
            weather_TimeOfDay = 0
        end
    elseif vkey == WEATHER_WEATHER_KEY then
        weather_Weather = weather_Weather + 1
        if weather_Weather > 3 then
            weather_Weather = 0
        end
    elseif vkey == WEATHER_WEATHER_EFFECTS_KEY then
        if weather_WeatherEffects == 0 then
            weather_WeatherEffects = 3
        else
            weather_WeatherEffects = 0
        end
    elseif vkey == WEATHER_SEASON_KEY then
        weather_Season = weather_Season + 1
        if weather_Season > 2 then
            weather_Season = 0
        end
    end

end

local function init(ctx)
    if stadiumroot:sub(1,1)=='.' then
        stadiumroot = ctx.sider_dir .. stadiumroot
    end
	math.randomseed(os.time())
	settings = load_ini("config.ini")
    load_map_txt("map_teams.txt")
    load_map_txt("map_competitions.txt")
    merge_maps() -- create one master-table, which is going to have one entry for every stadium assigned - either via teams or competitions
    
    ctx.register("set_stadium", set_stadium)
    ctx.register("set_conditions", set_weather_conditions)
    ctx.register("get_stadium_name", change_stadium_name)
    ctx.register("livecpk_make_key", make_key)
    ctx.register("livecpk_get_filepath", get_filepath)
    ctx.register("set_teams", teams_selected)
    ctx.register("overlay_on", overlay_on)
    ctx.register("key_down", key_down)
    ctx.register("after_set_conditions", change_gfx_preview_fallback)
end

return { init = init }