------------------------------------------------------------------------------
--	Shared logic for discovering what techs and civics unlock.
------------------------------------------------------------------------------

-- ===========================================================================
--	Filter out base items from the list that also contain a replacement,
--  or which are excluded entirely (with no replacement) by a player trait.
--  This method does NOT maintain ordering.
-- ===========================================================================
function RemoveReplacedUnlockables(unlockables, playerId) 
	local has_trait = GetTraitMapForPlayer(playerId);
	
	local unlock_map = {};
	for i,v in ipairs(unlockables) do
		unlock_map[v[2]] = v;
	end

	for row in GameInfo.BuildingReplaces() do
		if(unlock_map[row.CivUniqueBuildingType]) then
			unlock_map[row.ReplacesBuildingType] = nil;
		end
	end

	for row in GameInfo.DistrictReplaces() do
		if(unlock_map[row.CivUniqueDistrictType]) then
			unlock_map[row.ReplacesDistrictType] = nil;
		end
	end

	for row in GameInfo.ExcludedDistricts() do
		if(has_trait[row.TraitType]) then
			unlock_map[row.DistrictType] = nil;
		end
	end

	for row in GameInfo.UnitReplaces() do
		if(unlock_map[row.CivUniqueUnitType]) then
			unlock_map[row.ReplacesUnitType] = nil;
		end
	end
	
	local results = {};
	for k,v in pairs(unlockables) do
		if(unlock_map[v[2]])then
			table.insert(results, v);
		end
	end

	return results;
end

-- ===========================================================================
--  Returns a map containing all traits a given player has.  
--  Key == TraitType, value == true.
-- ===========================================================================
function GetTraitMapForPlayer(playerId)
	if(playerId == nil) or not(Players) then
		return nil;	
	else
		local has_trait:table = nil;
		local player = playerId and Players[playerId];
		if(player ~= nil) then
			has_trait = {};
			local config = PlayerConfigurations[playerId];
			if(config ~= nil) then
				local leaderType = config:GetLeaderTypeName();
				local civType = config:GetCivilizationTypeName();

				if(leaderType) then
					for row in GameInfo.LeaderTraits() do
						if(row.LeaderType== leaderType) then
							has_trait[row.TraitType] = true;
						end
					end
				end

				if(civType) then
					for row in GameInfo.CivilizationTraits() do
						if(row.CivilizationType== civType) then
							has_trait[row.TraitType] = true;
						end
					end
				end
			end
		end
		return has_trait;
	end
end

-- ===========================================================================
--  Returns an array of all possible items unlocked by an optional player id.
-- ===========================================================================
function GetUnlockableItems(playerId)
	
	local has_trait = GetTraitMapForPlayer(playerId);

	function CanEverUnlock(item)
		return item.TraitType ~= "TRAIT_BARBARIAN" and ((item.TraitType == nil) or (has_trait == nil) or has_trait[item.TraitType]);	
	end

	local unlockables = {};
	for row in GameInfo.Buildings() do
		if(CanEverUnlock(row)) then
			table.insert(unlockables, {row, row.BuildingType, row.Name});
		end
	end
		
	for row in GameInfo.Districts() do
		if(CanEverUnlock(row)) then
			table.insert(unlockables, {row, row.DistrictType, row.Name});
		end
	end		
	for row in GameInfo.Units() do
		if(CanEverUnlock(row)) then
			table.insert(unlockables, {row, row.UnitType, row.Name});
		end
	end

	for row in GameInfo.Governments() do
		if(CanEverUnlock(row)) then
			table.insert(unlockables, {row, row.GovernmentType, row.Name});
		end
	end

	for row in GameInfo.Improvements() do
		if(CanEverUnlock(row)) then
			table.insert(unlockables, {row, row.ImprovementType, row.Name});
		end
	end

	for row in GameInfo.Policies() do
		if(CanEverUnlock(row)) then
			table.insert(unlockables, {row, row.PolicyType, row.Name});
		end
	end

	for row in GameInfo.Projects() do
		if(CanEverUnlock(row)) then
			table.insert(unlockables, {row, row.ProjectType, row.Name});
		end
	end

	for row in GameInfo.Resources() do
		if(CanEverUnlock(row)) then
			table.insert(unlockables, {row, row.ResourceType, row.Name});
		end
	end

	for row in GameInfo.DiplomaticActions() do
		if(CanEverUnlock(row)) then
			table.insert(unlockables, {row, row.DiplomaticActionType, row.Name});
		end
	end

	return unlockables;
end

-- ===========================================================================
--	Returns an array of items unlocked by a given tech and optional player id.
-- ===========================================================================
function GetUnlockablesForTech( techType, playerId )

	-- Treat -1 NO_PLAYER as nil.
	if(type(playerId) == "number" and playerId < 0) then
		playerId = nil;
	end

	-- Ensure a string civic type rather than hash or index.
	local techInfo = GameInfo.Technologies[techType];
	techType = techInfo.TechnologyType;

	function CanUnlockWithThisTech(item) 
		return (item.PrereqTech == techType) or (item.InitiatorPrereqTech == techType);
	end
		
	-- Populate a complete list of unlockables.
	-- This must be a complete list because some replacement items exist with different prereqs than
	-- that which they replace.
	local unlockables = GetUnlockableItems(playerId);

	-- Filter out replaced items. 
	-- (Only do this if we have a player specified, otherwise this would filter ALL replaced items).
	if(playerId ~= nil) then
		unlockables = RemoveReplacedUnlockables(unlockables, playerId)
	end

	local results = {};
	for i, unlockable in ipairs(unlockables) do
		if(CanUnlockWithThisTech(unlockable[1])) then
			table.insert(results, {unlockable[2], unlockable[3]});
		end
	end

	for i, unlockable in ipairs(tSuk_Addins_Tech[techType]) do
		-- Apparently this file is referenced all over the place, and they all expect a regular structure
		-- So let's add this for conformity
		unlockable[1] = ""
		unlockable[2] = ""
		table.insert(results, unlockable)
	end

	return results;
end

-- ===========================================================================
--	Returns an array of items unlocked by a given civic and optional player id.
-- ===========================================================================
function GetUnlockablesForCivic(civicType, playerId)

	-- Treat -1 NO_PLAYER as nil.
	if(type(playerId) == "number" and playerId < 0) then
		playerId = nil;
	end
	
	-- Ensure a string civic type rather than hash or index.
	local civicInfo = GameInfo.Civics[civicType];
	civicType = civicInfo.CivicType;

	function CanUnlockWithCivic(item) 
		return item.PrereqCivic == civicType or item.InitiatorPrereqCivic == civicType;
	end
		
	-- Populate a complete list of unlockables.
	-- This must be a complete list because some replacement items exist with different prereqs than
	-- that which they replace.
	local unlockables = GetUnlockableItems(playerId);

	-- SHIMMY SHIM SHIM
	-- This is gifted via a modifier and we presently don't 
	-- support scrubbing modifiers to add to unlockables. 
	-- Maybe in a patch :)
	if(civicType == "CIVIC_DIPLOMATIC_SERVICE") then
		local spy = GameInfo.Units["UNIT_SPY"]
		table.insert(unlockables, {spy, spy.UnitType, spy.Name});
	end

	-- Filter out replaced items. 
	-- (Only do this if we have a player specified, otherwise this would filter ALL replaced items).
	if(playerId ~= nil) then
		unlockables = RemoveReplacedUnlockables(unlockables, playerId)
	end

	local results = {};
	for i, unlockable in ipairs(unlockables) do
		if(CanUnlockWithCivic(unlockable[1])) then
			table.insert(results, {unlockable[2], unlockable[3]});
		end
	end

	for i, unlockable in ipairs(tSuk_Addins_Civics[civicType]) do
		-- Apparently this file is referenced all over the place, and they all expect a regular structure
		-- So let's add this for conformity
		unlockable[1] = ""
		unlockable[2] = ""
		table.insert(results, unlockable)
	end

	return results;
end
-- ===========================================================================
--	Sukritact's Civics Addin
-- ===========================================================================
tSuk_Addins_Civics = {}

function PopulateSukritactAddins_Civic()

	if not(Game) then return end

	--Init Tables for all Civics
	local tExistingIcons = {}

	for tCivic in GameInfo.Civics() do
		tSuk_Addins_Civics[tCivic.CivicType] = {}
		tExistingIcons[tCivic.CivicType] = {}
	end

	-------------------------------------------
	-- Envoys and Spies
	-------------------------------------------
	for tRow in GameInfo.CivicModifiers() do
		local tTable = tSuk_Addins_Civics[tRow.CivicType]

		if tRow.ModifierId == "CIVIC_AWARD_ONE_INFLUENCE_TOKEN" then
			tTable[#tTable + 1] = {Icon = "ICON_NOTIFICATION_GIVE_INFLUENCE_TOKEN", Info = "", BG = "ICON_TECHUNLOCK_3", Size = 40}
		end
		if tRow.ModifierId == "CIVIC_AWARD_TWO_INFLUENCE_TOKENS" then
			tTable[#tTable + 1] = {Icon = "ICON_NOTIFICATION_GIVE_INFLUENCE_TOKEN", Info = "2", BG = "ICON_TECHUNLOCK_3", Size = 40}
		end
		if tRow.ModifierId == "CIVIC_AWARD_THREE_INFLUENCE_TOKENS" then
			tTable[#tTable + 1] = {Icon = "ICON_NOTIFICATION_GIVE_INFLUENCE_TOKEN", Info = "3", BG = "ICON_TECHUNLOCK_3", Size = 40}
		end
		if tRow.ModifierId == "CIVIC_GRANT_SPY" then
			tTable[#tTable + 1] = {Icon = "ICON_UNIT_SPY", BG = "ICON_TECHUNLOCK_3", Size = 40}
		end		
	end
	-------------------------------------------
	-- Get Unlockable Improvements
	-------------------------------------------
	local tValidImprovements = {}
	local iPlayer = 0; if Game then iPlayer = Game.GetLocalPlayer() end; if (iPlayer == -1) then iPlayer = 0 end;
	local tTraits = GetTraitMapForPlayer(iPlayer);

	function CanEverUnlock(item)
		return item.TraitType ~= "TRAIT_BARBARIAN" and ((item.TraitType == nil) or (tTraits == nil) or tTraits[item.TraitType]);	
	end
	for tImprovement in GameInfo.Improvements() do
		if(CanEverUnlock(tImprovement)) then
			tValidImprovements[tImprovement.ImprovementType] = true
		end
	end
	-------------------------------------------
	-- Civics Terrain Unlocks
	-------------------------------------------
	for tRow in GameInfo.Improvement_ValidTerrains() do
		if tValidImprovements[tRow.ImprovementType] and tRow.PrereqCivic then
			local sCivic = tRow.PrereqCivic
			local sImprovement = tRow.ImprovementType

			if not(tExistingIcons[sCivic][sImprovement .. "[ICON_NEW]"]) then
				local tTable = tSuk_Addins_Civics[sCivic]
				tTable[#tTable + 1] = {Icon = "ICON_" .. sImprovement, Info = "[ICON_NEW]", BG = "ICON_TECHUNLOCK_3"}
				tExistingIcons[sCivic][sImprovement .. "[ICON_NEW]"] = true
			end
		end
	end
	-------------------------------------------
	-- Yield Enhancements from Civics
	-------------------------------------------
	for tRow in GameInfo.Improvement_BonusYieldChanges() do
		if tValidImprovements[tRow.ImprovementType] and tRow.PrereqCivic then
			local sCivic = tRow.PrereqCivic
			local sImprovement = tRow.ImprovementType
			local sYield = tRow.YieldType
			local sYieldIcon = "[" .. string.gsub(sYield, "YIELD", "ICON") .. "]"

			if not(tExistingIcons[sCivic][sImprovement .. sYieldIcon]) then
				local tTable = tSuk_Addins_Civics[sCivic]
				tTable[#tTable + 1] = {Icon = "ICON_" .. sImprovement, Info = sYieldIcon, BG = "ICON_TECHUNLOCK_3"}
				tExistingIcons[sCivic][sImprovement .. sYieldIcon] = true
			end
		end
	end
	-------------------------------------------
	-- Adjacency Enhancements from Civics
	-------------------------------------------
	for tRow in GameInfo.Improvement_Adjacencies() do
		if tValidImprovements[tRow.ImprovementType] then

			local sID = tRow.YieldChangeId
			local sImprovement = tRow.ImprovementType

			for tRow2 in GameInfo.Adjacency_YieldChanges() do
				if (sID == tRow2.ID) and tRow2.PrereqCivic then

					local sCivic = tRow2.PrereqCivic
					local sYield = tRow2.YieldType
					local sYieldIcon = "[" .. string.gsub(sYield, "YIELD", "ICON") .. "]"


					if not(tExistingIcons[sCivic][sImprovement .. sYieldIcon]) then
						local tTable = tSuk_Addins_Civics[sCivic]
						tTable[#tTable + 1] = {Icon = "ICON_" .. sImprovement, Info = sYieldIcon, BG = "ICON_TECHUNLOCK_3"}
						tExistingIcons[sCivic][sImprovement .. sYieldIcon] = true
					end
				end 
			end
		end
	end	
end

PopulateSukritactAddins_Civic();
-- ===========================================================================
--	Sukritact's Tech Addin
-- ===========================================================================
tSuk_Addins_Tech = {}
function PopulateSukritactAddins_Tech()

	if not(Game) then return end

	--Init Tables for all Civics
	local tExistingIcons = {}

	for tTechnology in GameInfo.Technologies() do
		tSuk_Addins_Tech[tTechnology.TechnologyType] = {}
		tExistingIcons[tTechnology.TechnologyType] = {}

		if tTechnology.EmbarkUnitType or tTechnology.EmbarkAll then
			local tTable = tSuk_Addins_Tech[tTechnology.TechnologyType]
			tTable[#tTable + 1] = {Icon = "ICON_CIVILIZATION_LISBON", BG = "ICON_TECHUNLOCK_3", Size = 36, Info = "[ICON_MOVEMENT]"}
		end
	end

	-------------------------------------------
	-- Envoys and Spies
	-------------------------------------------
	for tRow in GameInfo.TechnologyModifiers() do
		local tTable = tSuk_Addins_Tech[tRow.TechnologyType]

		if (tRow.ModifierId == "MATHEMATICS_ADJUST_SEA_MOVEMENT") or (tRow.ModifierId == "CARTOGRAPHY_GRANT_OCEAN_NAVIGATION") or (tRow.ModifierId == "STEAM_POWER_ADJUST_EMBARKED_MOVEMENT") or (tRow.ModifierId == "COMBUSTION_ADJUST_EMBARKED_MOVEMENT") then
			tTable[#tTable + 1] = {Icon = "ICON_CIVILIZATION_LISBON", BG = "ICON_TECHUNLOCK_3", Size = 36, Info = "[ICON_MOVEMENT]"}
		end
		if tRow.ModifierId == "TECH_GRANT_SPY" then
			tTable[#tTable + 1] = {Icon = "ICON_UNIT_SPY", BG = "ICON_TECHUNLOCK_3"}
		end		
	end
	-------------------------------------------
	-- Remove Features
	-------------------------------------------
	for tRow in GameInfo.Features() do
		if tRow.RemoveTech then
			local tTable = tSuk_Addins_Tech[tRow.RemoveTech]
			local sFeature = tRow.FeatureType

			tTable[#tTable + 1] = {Icon = "ICON_" .. sFeature, BG = "ICON_TECHUNLOCK_2", Size = 50}
		end	
	end
	-------------------------------------------
	-- Get Unlockable Improvements
	-------------------------------------------
	local tValidImprovements = {}
	local iPlayer = 0; if Game then iPlayer = Game.GetLocalPlayer() end; if (iPlayer == -1) then iPlayer = 0 end;
	local tTraits = GetTraitMapForPlayer(iPlayer);

	function CanEverUnlock(item)
		return item.TraitType ~= "TRAIT_BARBARIAN" and ((item.TraitType == nil) or (tTraits == nil) or tTraits[item.TraitType]);	
	end
	for tImprovement in GameInfo.Improvements() do
		if(CanEverUnlock(tImprovement)) then
			tValidImprovements[tImprovement.ImprovementType] = true
		end
	end
	-------------------------------------------
	-- Civics Terrain Unlocks
	-------------------------------------------
	for tRow in GameInfo.Improvement_ValidTerrains() do
		if tValidImprovements[tRow.ImprovementType] and tRow.PrereqTech then
			local sTech = tRow.PrereqTech
			local sImprovement = tRow.ImprovementType

			if not(tExistingIcons[sTech][sImprovement .. "[ICON_NEW]"]) then
				local tTable = tSuk_Addins_Tech[sTech]
				tTable[#tTable + 1] = {Icon = "ICON_" .. sImprovement, Info = "[ICON_NEW]", BG = "ICON_TECHUNLOCK_3"}
				tExistingIcons[sTech][sImprovement .. "[ICON_NEW]"] = true
			end
		end
	end
	-------------------------------------------
	-- Yield Enhancements from Techs
	-------------------------------------------
	for tRow in GameInfo.Improvement_BonusYieldChanges() do
		if tValidImprovements[tRow.ImprovementType] and tRow.PrereqTech then
			local sTech = tRow.PrereqTech
			local sImprovement = tRow.ImprovementType
			local sYield = tRow.YieldType
			local sYieldIcon = "[" .. string.gsub(sYield, "YIELD", "ICON") .. "]"

			if not(tExistingIcons[sTech][sImprovement .. sYieldIcon]) then
				local tTable = tSuk_Addins_Tech[sTech]
				tTable[#tTable + 1] = {Icon = "ICON_" .. sImprovement, Info = sYieldIcon, BG = "ICON_TECHUNLOCK_3"}
				tExistingIcons[sTech][sImprovement .. sYieldIcon] = true
			end
		end
	end
	-------------------------------------------
	-- Adjacency Enhancements from Techs
	-------------------------------------------
	for tRow in GameInfo.Improvement_Adjacencies() do
		if tValidImprovements[tRow.ImprovementType] then

			local sID = tRow.YieldChangeId
			local sImprovement = tRow.ImprovementType

			for tRow2 in GameInfo.Adjacency_YieldChanges() do
				if (sID == tRow2.ID) and tRow2.PrereqTech then

					local sTech = tRow2.PrereqTech
					local sYield = tRow2.YieldType
					local sYieldIcon = "[" .. string.gsub(sYield, "YIELD", "ICON") .. "]"


					if not(tExistingIcons[sTech][sImprovement .. sYieldIcon]) then
						local tTable = tSuk_Addins_Tech[sTech]
						tTable[#tTable + 1] = {Icon = "ICON_" .. sImprovement, Info = sYieldIcon, BG = "ICON_TECHUNLOCK_3"}
						tExistingIcons[sTech][sImprovement .. sYieldIcon] = true
					end
				end 
			end
		end
	end	
end

PopulateSukritactAddins_Tech()
-- ===========================================================================
-- ===========================================================================