-- =======================================================================
--                   Territorial Lord Win condition
-- =======================================================================

include "scripting/coroutine.lua" -- for sleep
include "scripting/formatting.lua"
include "scripting/messages.lua"
include "scripting/table.lua"
include "scripting/win_conditions/win_condition_functions.lua"

set_textdomain("win_conditions")

include "scripting/win_conditions/win_condition_texts.lua"

local wc_name = "Territorial Lord"
-- This needs to be exactly like wc_name, but localized, because wc_name
-- will be used as the key to fetch the translation in C++
local wc_descname = _("Territorial Lord")
local wc_version = 2
local wc_desc = _ (
   "Each player or team tries to obtain more than half of the map’s " ..
   "area. The winner will be the player or the team that is able to keep " ..
   "that area for at least 20 minutes."
)
return {
   name = wc_name,
   description = wc_desc,
   func = function()
      local plrs = wl.Game().players

      -- set the objective with the game type for all players
      broadcast_objective("win_condition", wc_descname, wc_desc)

      -- Get all valueable fields of the map
      local fields = {}
      local map = wl.Game().map
      for x=0,map.width-1 do
         for y=0,map.height-1 do
            local f = map:get_field(x,y)
            if f then
               -- add this field to the list as long as it has not movecaps swim
               if not f:has_caps("swimmable") then
                  if f:has_caps("walkable") then
                     fields[#fields+1] = f
                  else
                     -- editor disallows placement of immovables on dead and acid fields
                     if f.immovable then
                        fields[#fields+1] = f
                     end
                  end
               end
            end
         end
      end

      -- these variables will be used once a player or team owns more than half
      -- of the map's area
      local currentcandidate = "" -- Name of Team or Player
      local candidateisteam = false
      local remaining_time = 10 -- (dummy) -- time in secs, if == 0 -> victory

      -- Find all valid teams
      local teamnumbers = {} -- array with team numbers
      for idx,p in ipairs(plrs) do
         local team = p.team
         if team > 0 then
            local found = false
            for idy,t in ipairs(teamnumbers) do
               if t == team then
                  found = true
                  break
               end
            end
            if not found then
               teamnumbers[#teamnumbers+1] = team
            end
         end
      end

      local _landsizes = {}
      local function _calc_current_landsizes()
         -- init the landsizes for each player
         for idx,plr in ipairs(plrs) do
            _landsizes[plr.number] = 0
         end

         for idx,f in ipairs(fields) do
            -- check if field is owned by a player
            local o = f.owner
            if o then
               local n = o.number
               _landsizes[n] = _landsizes[n] + 1
            end
         end
      end

      local function _calc_points()
         local teampoints = {}     -- points of teams
         local maxplayerpoints = 0 -- the highest points of a player without team
         local maxpointsplayer = 0 -- the player
         local foundcandidate = false

         _calc_current_landsizes()

         for idx, p in ipairs(plrs) do
            local team = p.team
            if team == 0 then
               if maxplayerpoints < _landsizes[p.number] then
                  maxplayerpoints = _landsizes[p.number]
                  maxpointsplayer = p
               end
            else
               if not teampoints[team] then -- init the value
                  teampoints[team] = 0
               end
               teampoints[team] = teampoints[team] + _landsizes[p.number]
            end
         end

         if maxplayerpoints > ( #fields / 2 ) then
            -- player owns more than half of the map's area
            foundcandidate = true
            if candidateisteam == false and currentcandidate == maxpointsplayer.name then
               remaining_time = remaining_time - 30
            else
               currentcandidate = maxpointsplayer.name
               candidateisteam = false
               remaining_time = 20 * 60 -- 20 minutes
            end
         else
            for idx, t in ipairs(teamnumbers) do
               if teampoints[t] > ( #fields / 2 ) then
                  -- this team owns more than half of the map's area
                  foundcandidate = true
                  if candidateisteam == true and currentcandidate == t then
                     remaining_time = remaining_time - 30
                  else
                     currentcandidate = t
                     candidateisteam = true
                     remaining_time = 20 * 60 -- 20 minutes
                  end
               end
            end
         end
         if not foundcandidate then
            currentcandidate = ""
            candidateisteam = false
            remaining_time = 10
         end
      end

      local function _send_state()
         set_textdomain("win_conditions")
         local candidate = currentcandidate
         if candidateisteam then
            candidate = (_"Team %i"):format(currentcandidate)
         end
         local msg1 = (_"%s owns more than half of the map’s area."):format(candidate)
         msg1 = msg1 .. "\n"
         msg1 = msg1 .. (ngettext("You’ve still got %i minute to prevent a victory.",
                   "You’ve still got %i minutes to prevent a victory.",
                   remaining_time / 60))
               :format(remaining_time / 60)

         local msg2 = _"You own more than half of the map’s area."
         msg2 = msg2 .. "\n"
         msg2 = msg2 .. (ngettext("Keep it for %i more minute to win the game.",
                   "Keep it for %i more minutes to win the game.",
                   remaining_time / 60))
               :format(remaining_time / 60)

         for idx, player in ipairs(plrs) do
            if candidateisteam and currentcandidate == player.team
               or not candidateisteam and currentcandidate == player.name then
               send_message(player, game_status.title, rt(p(msg2)), {popup = true})
            else
               send_message(player, game_status.title, rt(p(msg1)), {popup = true})
            end
         end
      end

      -- Start a new coroutine that checks for defeated players
      run(function()
         while remaining_time ~= 0 do
            sleep(5000)
            check_player_defeated(plrs, lost_game.title, lost_game.body, wc_descname, wc_version)
         end
      end)

      -- here is the main loop!!!
      while true do
         -- Sleep 30 seconds == STATISTICS_SAMPLE_TIME
         sleep(30000)

         -- Check if a player or team is a candidate and update variables
         _calc_points()

         -- Do this stuff, if the game is over
         if remaining_time == 0 then
            for idx, p in ipairs(plrs) do
               p.see_all = 1
               if candidateisteam and currentcandidate == p.team
                  or not candidateisteam and currentcandidate == p.name then
                  p:send_message(won_game_over.title, rt(won_game_over.body))
                  wl.game.report_result(p, 1, make_extra_data(p, wc_descname, wc_version, {score=_landsizes[p.number]}))
               else
                  p:send_message(lost_game_over.title, rt(lost_game_over.body))
                  wl.game.report_result(p, 0, make_extra_data(p, wc_descname, wc_version, {score=_landsizes[p.number]}))
               end
            end
            break
         end

         -- If there is a candidate, check whether we have to send an update
         if remaining_time % 300 == 0 then -- every 5 minutes (5 * 60 )
            _send_state()
         end
      end
   end
}
