-- ========= --
-- UTILITIES --
-- ========= --

local iPracticalNumCivs = (GameDefines.MAX_MAJOR_CIVS - 1)

function JFD_IsCivilisationActive(civilizationID)
	for iSlot = 0, iPracticalNumCivs, 1 do
		local slotStatus = PreGame.GetSlotStatus(iSlot)
		if (slotStatus == SlotStatus["SS_TAKEN"] or slotStatus == SlotStatus["SS_COMPUTER"]) then
			if PreGame.GetCivilization(iSlot) == civilizationID then
				return true
			end
		end
	end
	return false
end

function GetPrimaryReligion(pPlayer)
	if pPlayer:HasCreatedReligion() then
		return pPlayer:GetReligionCreatedByPlayer()
	elseif pPlayer:GetCapitalCity() then
		return pPlayer:GetCapitalCity():GetReligiousMajority()
	else
		return -1
	end
end

-- ======= --
-- DEFINES --
-- ======= --

include("FLuaVector.lua")

local iCiv = GameInfoTypes["CIVILIZATION_ZHQ_ELAM"]
local bIsActive = JFD_IsCivilisationActive(iCiv)

-- ====================================== --
-- CACHE UA-RELEVANT VALUES AT GAME START --
-- ====================================== --

local tUniqueUnits = {}
local tElamFriends = {}
local tReligionsInGame = {}

function Elam_TabulateInfoAtGameStart()
	for playerID, pPlayer in pairs(Players) do
		if pPlayer:IsEverAlive() and not (pPlayer:IsMinorCiv() or pPlayer:IsBarbarian()) then
			-- track unique unit(s)
			tUniqueUnits[playerID] = {}
			local iCheckedCiv = pPlayer:GetCivilizationType()
			local sCivTag = GameInfo.Civilizations[iCheckedCiv].Type
			-- C15 --
			for row in DB.Query("SELECT UnitType FROM Civilization_UnitClassOverrides WHERE CivilizationType = '" .. sCivTag .. "' AND UnitType IS NOT NULL") do -- On top of fixing the whole apostrophe thing, we have to make sure that UnitType isn't null before assuming that it's an actual Unit
			-- /C15 --
				local iNum = #tUniqueUnits[playerID] or 0
				tUniqueUnits[playerID][iNum + 1] = GameInfoTypes[row.UnitType]
			end
			
			-- track DOFs involving Elam
			if iCheckedCiv == iCiv then
				tElamFriends[playerID] = {}
				local pTeam = Teams[pPlayer:GetTeam()] -- C15
				for friendID, pFriend in pairs(Players) do
					if friendID ~= playerID then
						-- C15 --
						tElamFriends[playerID][friendID] = pPlayer:IsDoF(friendID) and pTeam:IsHasMet(pFriend:GetTeam()) -- As memory serves, IsDoF will return true if the Players haven't met
						-- /C15 --
					end
				end
			end
			
			-- track existing religions
			-- C15 --
			--if pPlayer:HasCreatedReligion() then
				local iRelig = pPlayer:GetReligionCreatedByPlayer()
				-- This is a cool one that Mr. Gazeebo forces you to do
				if Player.GetOriginalReligionCreatedByPlayer then
					iRelig = pPlayer:GetOriginalReligionCreatedByPlayer()
				end
				--local pCity = Game.GetHolyCityForReligion(iRelig)
				if iRelig > 0 then
					tReligionsInGame[iRelig] = Player.GetOriginalReligionCreatedByPlayer and -1 or playerID -- The CP's version of RelgionOverview passes -1 into GetHolyCityForReligion; BNW's passes the founder's playerID. This should cover that discrepancy.
				end
			--end
			-- /C15 --
		end
	end
end


if bIsActive then
	Events.SequenceGameInitComplete.Add(Elam_TabulateInfoAtGameStart)
end

-- ============================================== --
--    UA: RECEIVE FRIENDS' UUs WHEN MAKING DOF    --
-- UA: RECEIVE FRIENDS' UUs WHEN THEY RESEARCH IT --
-- ============================================== --

function Elam_CheckDOFs(playerID)
	local pPlayer = Players[playerID]
	if pPlayer:GetCivilizationType() == iCiv then
		local pTeam = Teams[pPlayer:GetTeam()] -- C15
		local tNewFriends = {}
		local bNewFriends = false -- C15
		for friendID, pFriend in pairs(Players) do
			if (not pPlayer:IsMinorCiv() and not pPlayer:IsBarbarian()) then
				local bCachedFriendStatus = tElamFriends[playerID][friendID]
				-- C15 --
				local bCurrentFriendStatus = pPlayer:IsDoF(friendID) and pTeam:IsHasMet(pFriend:GetTeam()) -- As before
				-- /C15 --
				tElamFriends[playerID][friendID] = bCurrentFriendStatus
				
				if bCurrentFriendStatus and not bCachedFriendStatus then
					tNewFriends[friendID] = true
					bNewFriends = true -- C15
				end
			end
		end
		
		-- C15 --
		--if #tNewFriends > 0 then -- This doesn't work, because # doesn't get the length of tables w/o linearly ordered integer keys starting from 1
		if bNewFriends then
		-- /C15 --
			local iElamReligion = GetPrimaryReligion(pPlayer)
			if iElamReligion < 1 then return end -- don't do this iteration unless elam has a religion, not just a pantheon
			local pCap = pPlayer:GetCapitalCity() -- this won't be nil b/c of the prev. two lines
			for friendID, _ in pairs(tNewFriends) do
				local pFriend = Players[friendID]
				local iFriendReligion = GetPrimaryReligion(pFriend)
				if iFriendReligion == iElamReligion then
					for k, iUU in pairs(tUniqueUnits[friendID]) do -- C15 - This table apparently can be nil, but I can't tell why, so will have to test another time I guess -- Okay so technically idk about this one because this line of code has never been executed, but the other one is broken so y'know
						if pFriend:CanTrain(iUU, true, true, true, false) then
							pPlayer:InitUnit(iUU, pCap:GetX(), pCap:GetY())
							-- C15 --
							--if pPlayer:IsHuman() then
							if Game.GetActivePlayer() == playerID then
							-- /C15 --
								local sFriendName = pFriend:GetName()
								local sUnitName = Locale.ConvertTextKey(GameInfo.Units[iUU].Description)
								Events.GameplayAlertMessage("Befriending " .. sFriendName .. " has provided you with a free " .. sUnitName .. "!")
							end
						end
					end
				end
			end
		end
	end
end

function Elam_FriendResearchesTech(teamID, techID)
	local tFriendsOnTeam = {}
	for elamID, tThisPlayerFriends in pairs(tElamFriends) do
		local iElamReligion = GetPrimaryReligion(Players[elamID])
		if iElamReligion > 0 then -- only continue if elam has founded a religion
			tFriendsOnTeam[elamID] = {}
			for friendID, _ in pairs(tThisPlayerFriends) do
				local pFriend = Players[friendID]
				-- C15
				--if GetPrimaryReligion(pFriend) then
				if GetPrimaryReligion(pFriend) == iElamReligion then
				-- /C15 --
					local iTeam = pFriend:GetTeam()
					tFriendsOnTeam[elamID][friendID] = (iTeam == teamID)
				end
			end
		end
	end
	
	for elamID, tRelevantFriends in pairs(tFriendsOnTeam) do
		local pElam = Players[elamID]
		local pCap = pElam:GetCapitalCity() -- this won't be nil, b/c if so, there will be no content in the tFriendsOnTeam table
		for friendID, _ in pairs(tRelevantFriends) do
			for k, iUU in pairs(tUniqueUnits[friendID]) do -- C15 -- This table has been found to be nil, and I don't know why - will have to be tested in the future
				local iNeededTech = GameInfoTypes[GameInfo.Units[iUU].PrereqTech]
				if (iNeededTech == techID) then
					pElam:InitUnit(iUU, pCap:GetX(), pCap:GetY())
					-- C15 --
					--if pElam:IsHuman() then
					if Game.GetActivePlayer() == elamID then
					-- /C15 --
						local sFriendName = Players[friendID]:GetName()
						local sUnitName = Locale.ConvertTextKey(GameInfo.Units[iUU].Description)
						Events.GameplayAlertMessage("Your friend, " .. sFriendName .. ", has researched their unique " .. sUnitName .. " and given you a copy!")
					end
				end
			end
		end
	end
end

if bIsActive then
	GameEvents.PlayerDoTurn.Add(Elam_CheckDOFs)
	GameEvents.TeamSetHasTech.Add(Elam_FriendResearchesTech)
end

-- ============================================ --
-- UA: GET 10% OF HOLY CITIES' FAITH AS CULTURE --
-- ============================================ --

local iFaithYield = GameInfoTypes["YIELD_FAITH"]

function Elam_UpdateReligionTable(playerID, cityID, religionID)
	tReligionsInGame[religionID] = true
end

function Elam_CultureFromHolyCityFaith(playerID)
	local pPlayer = Players[playerID]
	if pPlayer:GetCivilizationType() == iCiv then
		local pCap = pPlayer:GetCapitalCity()
		if pCap then
			local iCultureAmount = 0
			for religionID, v in pairs(tReligionsInGame) do
				if pCap:GetNumFollowers(religionID) > 0 then
					-- C15 --
					--local pHolyCity = Game.GetHolyCityForReligion(religionID)
					local pHolyCity = Game.GetHolyCityForReligion(religionID, v)
					-- /C15 --
					local iFaithAmt = pHolyCity:GetYieldRate(iFaithYield)
					iCultureAmount = iCultureAmount + (iFaithAmt / 10)
				end
			end
			
			pPlayer:ChangeJONSCulture(iCultureAmount)
			if (Game.GetActivePlayer() == playerID) and (iCultureAmount > 0) then
				local iX, iY = pCap:GetX(), pCap:GetY()
				local sMessage = "[COLOR_MAGENTA +" .. iCultureAmount .. "[ENDCOLOR] [ICON_CULTURE]"
				Events.AddPopupTextEvent(HexToWorld(ToHexFromGrid(Vector2(iX, iY))), sMessage, 0)
			end
		end
	end
end

if bIsActive then
	GameEvents.ReligionFounded.Add(Elam_UpdateReligionTable)
	GameEvents.PlayerDoTurn.Add(Elam_CultureFromHolyCityFaith)
end

-- ============================================================ --
-- UU: +20% STRENGTH IN RANGE OF CITIES THAT LACK YOUR RELIGION --
-- ============================================================ --

local classArcher = GameInfoTypes["UNITCLASS_ARCHER"]
local iElamBowman = GameInfoTypes["UNIT_ZHQ_HALTAMI_BOWMAN"]
local iBowPromo = GameInfoTypes["PROMOTION_ZHQ_HALTAMI_BOWMAN_STRENGTH"]

function Elam_ProcessHaltamiBonus(playerID)
	local pPlayer = Players[playerID]
	if pPlayer:HasUnitOfClassType(classArcher) then
		for pUnit in pPlayer:Units() do
			if pUnit:GetUnitType() == iElamBowman then
				local bDeservesPromo = false
				local pPlot = pUnit:GetPlot()
				local iOwner = pPlot:GetOwner()
				if (iOwner > -1) and (iOwner ~= playerID) then
					local iX, iY = pPlot:GetX(), pPlot:GetY()
					local pOwner = Players[iOwner]
					for pCity in pOwner:Cities() do
						local iDist = Map.PlotDistance(iX, iY, pCity:GetX(), pCity:GetY())
						if (iDist <= 3) then
							bDeservesPromo = true
							break
						end
					end
				end
				pUnit:SetHasPromotion(iBowPromo, bDeservesPromo)
			end
		end
	end
end

if bIsActive then
	GameEvents.PlayerDoTurn.Add(Elam_ProcessHaltamiBonus)
end

-- ======================================= --
-- UB: +1 FAITH FOR EVERY CULTURE BUILDING --
-- ======================================= --

local iDurUntash = GameInfoTypes["BUILDING_ZHQ_DUR_UNTASH"]
local iFaithDummy = GameInfoTypes["BUILDING_ZHQ_ELAM_FAITH"]

local tCultureBuildings = {}
for row in DB.Query("SELECT * FROM Building_YieldChanges WHERE YieldType = 'YIELD_CULTURE' UNION SELECT * FROM Building_YieldModifiers WHERE YieldType = 'YIELD_CULTURE'") do
	tCultureBuildings[GameInfoTypes[row.BuildingType]] = true
end

function Elam_ShrineFaith(playerID)
	local pPlayer = Players[playerID]
	if pPlayer:CountNumBuildings(iDurUntash) > 0 then
		for pCity in pPlayer:Cities() do
			if pCity:IsHasBuilding(iDurUntash) then
				local iNumDummies = 0
				for k, _ in pairs(tCultureBuildings) do
					if pCity:IsHasBuilding(k) then
						iNumDummies = iNumDummies + 1
					end
				end
				pCity:SetNumRealBuilding(iFaithDummy, iNumDummies)
			else
				pCity:SetNumRealBuilding(iFaithDummy, 0)
			end
		end
	elseif pPlayer:CountNumBuildings(iFaithDummy) > 0 then
		for pCity in pPlayer:Cities() do
			pCity:SetNumRealBuilding(iFaithDummy, 0)
		end
	end
end

if bIsActive then
	GameEvents.PlayerDoTurn.Add(Elam_ShrineFaith)
end