-- Stadium switcher v1.1: assign the stadium for home team
-- Custom content is used, not LiveCPK/game: content\stadium-server is the root
-- author: zlac, 2017
-- originally posted on evo-web

local new_stadium_path
local stadiumroot = ".\\content\\stadium-server\\"
local stadium_switched = false
local random_num

local team_assignment_map = {}
local competition_assignment_map = {}

-- 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 0) 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 0 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 39 too (EPL id) in override_competitions
-- initially, all (probably?) Exhibition mode, League and League-Cup matches are included in competition overrides
-- BEGIN CUSTOMIZABLE LUA TABLE                         
local override_competitions = {0, 1, 2, 5, -- Exhibition matches - regular, CL, EL, AFC
								39, 40, 84, -- England 1st and 2nd div league and cup
								43, 44, 85, -- Spain 1st and 2nd div league and cup
								47, 48, 86, -- Italy 1st and 2nd div league and cup
								51, 52, 87, -- France 1st and 2nd div league and cup
								54, 89, -- Portugal league and cup
								53, 88, -- Netherlands league and cup
								60, 95, -- Argentina league and cup
								57, 92,  -- Brazil league and cup
								64, 96, -- Chile league (first stage) and cup
								72, 111, -- PEU league and cup
								74, 112, -- PLA league and cup
								77, 114, -- PAS league and cup
								}
-- END CUSTOMIZABLE LUA TABLE



-- 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



-- splits multi-line text to individual lines - bugged when there are empty lines between normal lines
--[[local function to_lines(s)
  local t = {}
  local function helper(line)
      line = trim(line)
      if line:len() > 0 and line:sub(1, 1) ~= "#" then
  	 	t[#t+1] = line 
      end
      return "" 
  end
  helper((s:gsub("(.-)\r?\n", helper)))
  return t
end
--]]

local function load_map_txt(filename)
    local delim = ","
    -- local file = assert(io.open(stadiumroot .. filename, "r"))
    -- local data = trim(file:read("*all"))
    -- data = string.gsub(data, "^\239\187\191", "")   -- removes UTF BOM bytes at the beginning of the .txt file
    
    local data = assert(io.lines(stadiumroot .. filename))
    log(filename .. " found in " .. stadiumroot .. filename)
    
        -- for i, line in pairs(to_lines(data)) do
    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
    -- file:close()
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 home_team_selected(ctx, team_id)
	--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)
	local tid = tonumber(ctx.tournament_id)
	random_num = nil
	if 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 = 1 
		else
			-- if there are more stadiums, select one's index rendomly
		    math.randomseed(os.time())
		    random_num = math.random(1, #competition_assignment_map[tid])
		end
		log("Selecting random stadium for competition ID " .. tostring(tid) .. ": Stadium no. " .. tostring(random_num) .. " (from " .. tostring(#competition_assignment_map[tid]) .. " stadium(s) available)")
	end
end


local function is_it_stadium_file(filename)	
    if 
       string.match(string.lower(filename), "common\\bg\\model\\bg\\ad") or
       string.match(string.lower(filename), "common\\bg\\model\\bg\\audi") or
       -- comment-out only the next line of code if you want to use only those adboards which were added and configured via .cpk files
       string.match(string.lower(filename), "common\\bg\\model\\bg\\bigflag") or -- ?? dt30.cpk
       string.match(string.lower(filename), "common\\bg\\model\\bg\\bill") or
       string.match(string.lower(filename), "common\\bg\\model\\bg\\cheer") or
       string.match(string.lower(filename), "common\\bg\\model\\bg\\cornerflag") or -- ?? dt30.cpk
       string.match(string.lower(filename), "common\\bg\\model\\bg\\effect") or
       string.match(string.lower(filename), "common\\bg\\model\\bg\\goal") or -- Villa park
       string.match(string.lower(filename), "common\\bg\\model\\bg\\pitch") or
       string.match(string.lower(filename), "common\\bg\\model\\bg\\scarecrow") or
       string.match(string.lower(filename), "common\\bg\\model\\bg\\sky") or
       string.match(string.lower(filename), "common\\bg\\model\\bg\\stadium") or
       string.match(string.lower(filename), "common\\bg\\model\\bg\\staff") or
       string.match(string.lower(filename), "common\\bg\\model\\bg\\tv") or
       string.match(string.lower(filename), "common\\character1\\model\\character") or -- Most of the italian stadiums
       string.match(string.lower(filename), "common\\demo\\anime\\behavior\\fixdemo\\animations") or -- Atleti Azzuri
       string.match(string.lower(filename), "common\\demo\\fixdemo\\change") or -- Villa park
       string.match(string.lower(filename), "common\\demo\\fixdemo\\end") or 
       string.match(string.lower(filename), "common\\demo\\fixdemo\\ent") or
       string.match(string.lower(filename), "common\\demo\\fixdemo\\goal") or -- Villa park
       string.match(string.lower(filename), "common\\demo\\fixdemo\\result") or -- Villa park
       string.match(string.lower(filename), "common\\demo\\fixdemoobj\\passage") or
       string.match(string.lower(filename), "common\\demo\\light") or -- Villa park, but dt12.cpk has only st029 files (only for Konami Stadium)
       string.match(string.lower(filename), "common\\demo\\mob\\mob_") or -- Renzo Barbera
       string.match(string.lower(filename), "common\\render\\model\\bg\\hit\\bill") or 
       string.match(string.lower(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_new_stadium_path(ctx)
	local tid = tonumber(ctx.tournament_id)
	local stadium_path
	local custom_st_id
	local konami_st_id
	local custom_name
	
	if tid then
	   if competition_assignment_map[tid] == nil and team_assignment_map[ctx.home_team] ~= nil 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
        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 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), 
        -- .. 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 competition_assignment_map[tid] ~= nil then
          if ctx.match_info == 53 and competition_assignment_map[tid][random_num][4] ~= "" and competition_assignment_map[tid][random_num][5] ~= "" and competition_assignment_map[tid][random_num][6] ~= "" then
              -- is this the final match of a competition (53)?
              stadium_path = competition_assignment_map[tid][random_num][6] -- use the stadium assigned for final match
              custom_name = competition_assignment_map[tid][random_num][5]
              custom_st_id = competition_assignment_map[tid][random_num][4]
          elseif competition_assignment_map[tid][random_num][1] ~= "" and competition_assignment_map[tid][random_num][2] ~= "" and competition_assignment_map[tid][random_num][3] ~= "" then
              stadium_path = competition_assignment_map[tid][random_num][3]  -- use the regular stadium assigned for this competition
              custom_name = competition_assignment_map[tid][random_num][2]
              custom_st_id = competition_assignment_map[tid][random_num][1]
          end
        end
	   end
	end
	return stadium_path, custom_st_id, custom_name
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 is_it_stadium_file(filename) then -- any stadium file, but preview
          -- log(string.format("it_is_stadium_file: %s", filename))
            new_stadium_path, custom_st_id, custom_name = get_new_stadium_path(ctx)
            if new_stadium_path then
                  -- log(string.format("new_stadium_path: %s", new_stadium_path .. "\\" .. 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
           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
	--[[	
	elseif ctx.is_edit_mode == nil and stadium_switched == false then 
      -- special case for exhibition modes ... repeat preview override procedure, because stadium is not determined in pre-match menu, therefore set_stadium event hasn't fired yet and preview would not be switched 
      local spt_fname = which_stadium_preview_tex(filename)
      if spt_fname then
           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 nil2str(value)
	if value ~= nil then
		return value
	else
		return "N/A"
	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 new_stadium_path then
	        -- 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

-- since sider 3.3.4 this event allows only stadium_id to be changed in options!! other params are read-only (day/weather/season)
function set_stadium(ctx, options)
    if ctx.is_edit_mode == nil and ctx.tournament_id then
        stadium_switched = false
        local tid = tonumber(ctx.tournament_id)
        local custom_st_id
    	
    	if 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]
	        stadium_switched = true
          log("Switching to stadium with ID " .. custom_st_id .. " (basic home team assignment)")
	        -- return the stadium id to indicate that this change is final. This stops processing
	        -- of the event and modules further down the list will not receive this event.
	        return { stadium = tonumber(custom_st_id) } -- Stadium id of the served stadium
	    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) then
          -- comptition assignment will be overriden by team assignment
          custom_st_id = team_assignment_map[ctx.home_team][1]
	        stadium_switched = true
          log("Switching to stadium with ID " .. custom_st_id .. " (team overrides competition)")
	        return { stadium = tonumber(custom_st_id) }
	    elseif competition_assignment_map[tid] ~= nil then
	    	if ctx.match_info == 53 and competition_assignment_map[tid][random_num][4] ~= "" and competition_assignment_map[tid][random_num][5] ~= "" and competition_assignment_map[tid][random_num][6] ~= "" then
            -- is this the final match of a competition (53)?
            custom_st_id = competition_assignment_map[tid][random_num][4]
            stadium_switched = true
            log("Switching to stadium with ID " .. custom_st_id .. " (final match of the competition)")
            return { stadium = tonumber(custom_st_id) }
		  	elseif competition_assignment_map[tid][random_num][1] ~= "" and competition_assignment_map[tid][random_num][2] ~= "" and competition_assignment_map[tid][random_num][3] ~= "" then
            custom_st_id = competition_assignment_map[tid][random_num][1]
		        stadium_switched = true
            log("Switching to stadium with ID " .. custom_st_id .. " (pre-finals stage of the competition)")
		        return { stadium = tonumber(custom_st_id) }
		  	end 
		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
		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_switched = true
        return new_stadium_name
		end
	end
end

local function init(ctx)
    if stadiumroot:sub(1,1)=='.' then
        stadiumroot = ctx.sider_dir .. stadiumroot
    end
    load_map_txt("map_teams.txt")
    load_map_txt("map_competitions.txt")
    ctx.register("set_stadium", set_stadium)
    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_home_team", home_team_selected)
end

return { init = init }