-- ===========================================================================
--	ReportScreen
--	All the data
--
-- ===========================================================================
include("CitySupport");
include("Civ6Common");
include("InstanceManager");
include("SupportFunctions");
include("TabSupport");


-- ===========================================================================
--	DEBUG
--	Toggle these for temporary debugging help.
-- ===========================================================================
local m_debugFullHeight		:boolean = false;		-- (false) if the screen area should resize to full height of the available space.


-- ===========================================================================
--	CONSTANTS
-- ===========================================================================
local DARKEN_CITY_INCOME_AREA_ADDITIONAL_Y		:number = 6;
local DATA_FIELD_SELECTION						:string = "Selection";
local SIZE_HEIGHT_BOTTOM_YIELDS					:number = 135;
local SIZE_HEIGHT_PADDING_BOTTOM_ADJUST			:number = 85;	-- (Total Y - (scroll area + THIS PADDING)) = bottom area

-- Mapping of unit type to cost.
local UnitCostMap:table = {};
do
	for row in GameInfo.Units() do
		UnitCostMap[row.UnitType] = row.Maintenance;
	end
end

-- !! Added function to sort out tables for units

function spairs( t, order )
		local keys = {}

		for k in pairs(t) do keys[#keys+1] = k end
		
		if order then
			table.sort(keys, function(a,b) return order(t, a, b) end)
		else
			table.sort(keys)
		end

		local i = 0
		return function()
			i = i + 1
			if keys[i] then
				return keys[i], t[keys[i]]
			end
		end
	end
-- !! end of function

-- ===========================================================================
--	VARIABLES
-- ===========================================================================

local m_groupIM			:table = InstanceManager:new("GroupInstance",	"Top", Controls.Stack);				-- Collapsable
local m_simpleIM		:table = InstanceManager:new("SimpleInstance",	"Top", Controls.Stack);				-- Non-Collapsable, simple
local m_tabIM			:table = InstanceManager:new("TabInstance",		"Button", Controls.TabContainer);
local m_tabs			:table;
local m_kCityData		:table = nil;
local m_kCityTotalData	:table = nil;
local m_kUnitData		:table = nil;	-- TODO: Show units by promotion class
local m_kResourceData	:table = nil;
local m_kDealData		:table = nil;
local m_uiGroups		:table = nil;	-- Track the groups on-screen for collapse all action.


-- ===========================================================================
--	Single exit point for display
-- ===========================================================================
function Close()
	UIManager:DequeuePopup(ContextPtr);
	UI.PlaySound("UI_Screen_Close");
end


-- ===========================================================================
--	UI Callback
-- ===========================================================================
function OnCloseButton()
	Close();
end

-- ===========================================================================
--	Single entry point for display
-- ===========================================================================
function Open()
	UIManager:QueuePopup( ContextPtr, PopupPriority.Normal );
	Controls.ScreenAnimIn:SetToBeginning();
	Controls.ScreenAnimIn:Play();
	UI.PlaySound("UI_Screen_Open");

	m_kCityData, m_kCityTotalData, m_kResourceData, m_kUnitData, m_kDealData = GetData();
	
	m_tabs.SelectTab( 1 );
	
end

-- ===========================================================================
--	LUA Events
--	Opened via the top panel
-- ===========================================================================
function OnTopOpenReportsScreen()
	Open();
end

-- ===========================================================================
--	LUA Events
--	Closed via the top panel
-- ===========================================================================
function OnTopCloseReportsScreen()
	Close();	
end

-- ===========================================================================
--	UI Callback
--	Collapse all the things!
-- ===========================================================================
function OnCollapseAllButton()
	if m_uiGroups == nil or table.count(m_uiGroups) == 0 then
		return;
	end

	for i,instance in ipairs( m_uiGroups ) do
		if instance["isCollapsed"] == false then
			instance["isCollapsed"] = true;
			instance.CollapseAnim:Reverse();
			RealizeGroup( instance );
		end
	end
end

-- ===========================================================================
--	Populate with all data required for any/all report tabs.
-- ===========================================================================
function GetData()
	local kResources	:table = {};
	local kCityData		:table = {};
	local kCityTotalData:table = {
		Income	= {},
		Expenses= {},
		Net		= {},
		Treasury= {}
	};
	local kUnitData		:table = {};

	kCityTotalData.Income[YieldTypes.CULTURE]	= 0;
	kCityTotalData.Income[YieldTypes.FAITH]		= 0;
	kCityTotalData.Income[YieldTypes.FOOD]		= 0;
	kCityTotalData.Income[YieldTypes.GOLD]		= 0;
	kCityTotalData.Income[YieldTypes.PRODUCTION]= 0;
	kCityTotalData.Income[YieldTypes.SCIENCE]	= 0;
	kCityTotalData.Income["TOURISM"]			= 0;
	kCityTotalData.Expenses[YieldTypes.GOLD]	= 0;
	
	local playerID	:number = Game.GetLocalPlayer();
	if playerID == PlayerTypes.NONE then
		UI.DataError("Unable to get valid playerID for report screen.");
		return;
	end

	local player	:table  = Players[playerID];
	local pCulture	:table	= player:GetCulture();
	local pTreasury	:table	= player:GetTreasury();
	local pReligion	:table	= player:GetReligion();
	local pScience	:table	= player:GetTechs();

	-- ==========================
	-- !! this will use the m_kUnitData to fill out player's unit info
	-- ==========================
	local group_name : string = "default"

	kUnitData["Unit_Expenses"] = {}
	kUnitData["Unit_Report"] = {}

	for _, unit in player:GetUnits():Members() do
		local unitInfo : table = GameInfo.Units[unit:GetUnitType()]
		local unitGreatPerson = unit:GetGreatPerson()

		if GameInfo.GreatPersonClasses[unitGreatPerson:GetClass()] then group_name = "GREAT_PERSON"
		elseif unitInfo.MakeTradeRoute == true then group_name = "TRADER"
		elseif GameInfo.Units[unitInfo.UnitType].Spy == true then group_name = "SPY"
		elseif unit:GetReligiousStrength() > 0 then group_name = "RELIGIOUS"
		elseif unit:GetCombat() == 0 and unit:GetRangedCombat() == 0 then group_name = "CIVILIAN"
		elseif unitInfo.Domain == "DOMAIN_LAND" then group_name = "MILITARY_LAND"
		elseif unitInfo.Domain == "DOMAIN_AIR" then group_name = "MILITARY_AIR"
		elseif unitInfo.Domain == "DOMAIN_SEA" then group_name = "MILITARY_SEA"
		end

		if kUnitData["Unit_Report"][group_name] == nil then
			if group_name == "GREAT_PERSON" then
				kUnitData["Unit_Report"][group_name] = { Name = "LOC_HUD_UNITS_Great_People", ID = 6, Header = "UnitsGreatPeopleHeaderInstance", Entry = "UnitsGreatPeopleEntryInstance", units = {} }
			elseif group_name == "SPY" then
				kUnitData["Unit_Report"][group_name] = { Name = "LOC_HUD_UNITS_Spy", ID = 8, Header = "UnitsSpyHeaderInstance", Entry = "UnitsSpyEntryInstance", units = {} }
			elseif group_name == "RELIGIOUS" then
				kUnitData["Unit_Report"][group_name] = { Name = "LOC_HUD_UNITS_Religious", ID = 5, Header = "UnitsReligiousHeaderInstance", Entry = "UnitsReligiousEntryInstance", units = {} }
			elseif group_name == "TRADER" then
				kUnitData["Unit_Report"][group_name] = { Name = "LOC_HUD_UNITS_Trader", ID = 7, Header = "UnitsTraderHeaderInstance", Entry = "UnitsTraderEntryInstance", units = {} }
			elseif group_name == "MILITARY_LAND" then
				kUnitData["Unit_Report"][group_name] = { Name = "LOC_HUD_UNITS_Military_Land", ID = 1, Header = "UnitsMilitaryHeaderInstance", Entry = "UnitsMilitaryEntryInstance", units = {} }
			elseif group_name == "MILITARY_AIR" then
				kUnitData["Unit_Report"][group_name] = { Name = "LOC_HUD_UNITS_Military_Air", ID = 3, Header = "UnitsMilitaryHeaderInstance", Entry = "UnitsMilitaryEntryInstance", units = {} }
			elseif group_name == "MILITARY_SEA" then
				kUnitData["Unit_Report"][group_name] = { Name = "LOC_HUD_UNITS_Military_Sea", ID = 2, Header = "UnitsMilitaryHeaderInstance", Entry = "UnitsMilitaryEntryInstance", units = {} }
			else
				kUnitData["Unit_Report"][group_name] = { Name = "LOC_HUD_UNITS_Civilian_Support", ID = 4, Header = "UnitsCivilianHeaderInstance", Entry = "UnitsCivilianEntryInstance", units = {} }
			end
		end

		table.insert( kUnitData["Unit_Report"][group_name].units, unit )

		if kUnitData["Unit_Expenses"][unitInfo.UnitType] == nil then
			kUnitData["Unit_Expenses"][unitInfo.UnitType] = { Name = Locale.Lookup( unitInfo.Name ), Amount = 0, Cost = unitInfo.Maintenance }
		end

		kUnitData["Unit_Expenses"][unitInfo.UnitType].Amount = kUnitData["Unit_Expenses"][unitInfo.UnitType].Amount + 1
	end
	-- ==========================
	-- !! end of edit
	-- ==========================

	local pCities = player:GetCities();
	for i, pCity in pCities:Members() do	
		local cityName	:string = pCity:GetName();
			
		-- Big calls, obtain city data and add report specific fields to it.
		local data		:table	= GetCityData( pCity );
		data.Resources			= GetCityResourceData( pCity );					-- Add more data (not in CitySupport)			
		data.WorkedTileYields	= GetWorkedTileYieldData( pCity, pCulture );	-- Add more data (not in CitySupport)

		-- Add to totals.
		kCityTotalData.Income[YieldTypes.CULTURE]	= kCityTotalData.Income[YieldTypes.CULTURE] + data.CulturePerTurn;
		kCityTotalData.Income[YieldTypes.FAITH]		= kCityTotalData.Income[YieldTypes.FAITH] + data.FaithPerTurn;
		kCityTotalData.Income[YieldTypes.FOOD]		= kCityTotalData.Income[YieldTypes.FOOD] + data.FoodPerTurn;
		kCityTotalData.Income[YieldTypes.GOLD]		= kCityTotalData.Income[YieldTypes.GOLD] + data.GoldPerTurn;
		kCityTotalData.Income[YieldTypes.PRODUCTION]= kCityTotalData.Income[YieldTypes.PRODUCTION] + data.ProductionPerTurn;
		kCityTotalData.Income[YieldTypes.SCIENCE]	= kCityTotalData.Income[YieldTypes.SCIENCE] + data.SciencePerTurn;
		kCityTotalData.Income["TOURISM"]			= kCityTotalData.Income["TOURISM"] + data.WorkedTileYields["TOURISM"];
			
		kCityData[cityName] = data;

		-- Add resources
		for eResourceType,amount in pairs(data.Resources) do
			if kResources[eResourceType] == nil then
				kResources[eResourceType] = {
					CityList	= {},
					Icon		= "[ICON_"..GameInfo.Resources[eResourceType].ResourceType.."]",
					IsStrategic	= GameInfo.Resources[eResourceType].ResourceClassType == "RESOURCECLASS_STRATEGIC",
					Total		= 0
				};
			end
			table.insert( kResources[eResourceType].CityList, 
			{
				CityName = cityName,
				Amount	 = amount,					
			});

			kResources[eResourceType].Total = kResources[eResourceType].Total + amount;
		end
	end

	kCityTotalData.Expenses[YieldTypes.GOLD] = pTreasury:GetTotalMaintenance();

	-- NET = Income - Expense
	kCityTotalData.Net[YieldTypes.GOLD]			= kCityTotalData.Income[YieldTypes.GOLD] - kCityTotalData.Expenses[YieldTypes.GOLD];
	kCityTotalData.Net[YieldTypes.FAITH]		= kCityTotalData.Income[YieldTypes.FAITH];

	-- Treasury
	kCityTotalData.Treasury[YieldTypes.CULTURE]		= Round( pCulture:GetCultureYield(), 0 );
	kCityTotalData.Treasury[YieldTypes.FAITH]		= Round( pReligion:GetFaithBalance(), 0 );
	kCityTotalData.Treasury[YieldTypes.GOLD]		= Round( pTreasury:GetGoldBalance(), 0 );
	kCityTotalData.Treasury[YieldTypes.SCIENCE]		= Round( pScience:GetScienceYield(), 0 );
	kCityTotalData.Treasury["TOURISM"]				= Round( kCityTotalData.Income["TOURISM"], 0 );


	-- Units (TODO: Group units by promotion class and determine total maintenance cost)
	local pUnits :table = player:GetUnits(); 	
	for i, unit in pUnits:Members() do
		--local unitTypeName = UnitManager.GetTypeName(unit)
		--if "UNIT_SETTLER" == unitTypeName then
		--end
	end
	
	local kDealData	:table = {};
	local kPlayers	:table = PlayerManager.GetAliveMajors();
	for _, pOtherPlayer in ipairs(kPlayers) do
		local otherID:number = pOtherPlayer:GetID();
		if  otherID ~= playerID then			
			
			local pPlayerConfig	:table = PlayerConfigurations[otherID];
			local pDeals		:table = DealManager.GetPlayerDeals(playerID, otherID);
			
			if pDeals ~= nil then
				for i,pDeal in ipairs(pDeals) do
					if pDeal:IsValid() then
						local pOutgoingDeal :table	= pDeal:FindItemsByType(DealItemTypes.GOLD, DealItemSubTypes.NONE, playerID);
						if pOutgoingDeal ~= nil then
							for i,pDealItem in ipairs(pOutgoingDeal) do
								local duration		:number = pDealItem:GetDuration();
								if duration ~= 0 then
									local gold :number = pDealItem:GetAmount()
									table.insert( kDealData, {
										Amount		= gold,
										Duration	= duration,
										IsOutgoing	= true,
										PlayerID	= otherID,
										Name		= Locale.Lookup( pPlayerConfig:GetCivilizationDescription() )
									});						
								end
							end
						end
					
						local pIncomingDeal :table = pDeal:FindItemsByType(DealItemTypes.GOLD, DealItemSubTypes.NONE, otherID);
						if pIncomingDeal ~= nil then
							for i,pDealItem in ipairs(pIncomingDeal) do
								local duration		:number = pDealItem:GetDuration();
								if duration ~= 0 then
									local gold :number = pDealItem:GetAmount()
									table.insert( kDealData, {
										Amount		= gold,
										Duration	= duration,
										IsOutgoing	= false,
										PlayerID	= otherID,
										Name		= Locale.Lookup( pPlayerConfig:GetCivilizationDescription() )
									});						
								end
							end
						end
					end	
				end							
			end

		end
	end

	--print("Debug stuff: ", table.count(kDealData) );

	return kCityData, kCityTotalData, kResources, kUnitData, kDealData;
end


-- ===========================================================================
--	Obtain the total resources for a given city.
-- ===========================================================================
function GetCityResourceData( pCity:table )

	-- Loop through all the plots for a given city; tallying the resource amount.
	local kResources : table = {};
	local cityPlots : table = Map.GetCityPlots():GetPurchasedPlots(pCity)
	for _, plotID in ipairs(cityPlots) do
		local plot			: table = Map.GetPlotByIndex(plotID)
		local plotX			: number = plot:GetX()
		local plotY			: number = plot:GetY()
		local eResourceType : number = plot:GetResourceType();

		-- TODO: Account for trade/diplomacy resources.
		if eResourceType ~= -1 and Players[pCity:GetOwner()]:GetResources():IsResourceExtractableAt(plot) then
			if kResources[eResourceType] == nil then
				kResources[eResourceType] = 1;
			else
				kResources[eResourceType] = kResources[eResourceType] + 1;
			end
		end
	end
	return kResources;
end

-- ===========================================================================
--	Obtain the yields from the worked plots
-- ===========================================================================
function GetWorkedTileYieldData( pCity:table, pCulture:table )

	-- Loop through all the plots for a given city; tallying the resource amount.
	local kYields : table = {
		YIELD_PRODUCTION= 0,
		YIELD_FOOD		= 0,
		YIELD_GOLD		= 0,
		YIELD_FAITH		= 0,
		YIELD_SCIENCE	= 0,
		YIELD_CULTURE	= 0,
		TOURISM			= 0,
	};
	local cityPlots : table = Map.GetCityPlots():GetPurchasedPlots(pCity);
	local pCitizens	: table = pCity:GetCitizens();	
	for _, plotID in ipairs(cityPlots) do		
		local plot	: table = Map.GetPlotByIndex(plotID);
		local x		: number = plot:GetX();
		local y		: number = plot:GetY();
		isPlotWorked = pCitizens:IsPlotWorked(x,y);
		if isPlotWorked then
			for row in GameInfo.Yields() do			
				kYields[row.YieldType] = kYields[row.YieldType] + plot:GetYield(row.Index);				
			end
		end

		-- Support tourism.
		-- Not a common yield, and only exposure from game core is based off
		-- of the plot so the sum is easily shown, but it's not possible to 
		-- show how individual buildings contribute... yet.
		kYields["TOURISM"] = kYields["TOURISM"] + pCulture:GetTourismAt( plotID );
	end
	return kYields;
end



-- ===========================================================================
--	Set a group to it's proper collapse/open state
--	Set + - in group row
-- ===========================================================================
function RealizeGroup( instance:table )
	local v :number = (instance["isCollapsed"]==false and instance.RowExpandCheck:GetSizeY() or 0);
	instance.RowExpandCheck:SetTextureOffsetVal(0, v);

	instance.ContentStack:CalculateSize();	
	instance.CollapseScroll:CalculateSize();
	
	local groupHeight	:number = instance.ContentStack:GetSizeY();
	instance.CollapseAnim:SetBeginVal(0, -(groupHeight - instance["CollapsePadding"]));
	instance.CollapseScroll:SetSizeY( groupHeight );				

	instance.Top:ReprocessAnchoring();
end

-- ===========================================================================
--	Callback
--	Expand or contract a group based on its existing state.
-- ===========================================================================
function OnToggleCollapseGroup( instance:table )
	instance["isCollapsed"] = not instance["isCollapsed"];
	instance.CollapseAnim:Reverse();
	RealizeGroup( instance );
end

-- ===========================================================================
--	Toggle a group expanding / collapsing
--	instance,	A group instance.
-- ===========================================================================
function OnAnimGroupCollapse( instance:table)
		-- Helper
	function lerp(y1:number,y2:number,x:number)
		return y1 + (y2-y1)*x;
	end
	local groupHeight	:number = instance.ContentStack:GetSizeY();
	local collapseHeight:number = instance["CollapsePadding"]~=nil and instance["CollapsePadding"] or 0;
	local startY		:number = instance["isCollapsed"]==true  and groupHeight or collapseHeight;
	local endY			:number = instance["isCollapsed"]==false and groupHeight or collapseHeight;
	local progress		:number = instance.CollapseAnim:GetProgress();
	local sizeY			:number = lerp(startY,endY,progress);

	instance.CollapseAnim:SetSizeY( groupHeight );		
	instance.CollapseScroll:SetSizeY( sizeY );	
	instance.ContentStack:ReprocessAnchoring();	
	instance.Top:ReprocessAnchoring()

	Controls.Stack:CalculateSize();
	Controls.Scroll:CalculateSize();			
end


-- ===========================================================================
function SetGroupCollapsePadding( instance:table, amount:number )
	instance["CollapsePadding"] = amount;
end


-- ===========================================================================
function ResetTabForNewPageContent()
	m_uiGroups = {};
	m_simpleIM:ResetInstances();
	m_groupIM:ResetInstances();
	Controls.Scroll:SetScrollValue( 0 );	
end


-- ===========================================================================
--	Instantiate a new collapsable row (group) holder & wire it up.
--	ARGS:	(optional) isCollapsed
--	RETURNS: New group instance
-- ===========================================================================
function NewCollapsibleGroupInstance( isCollapsed:boolean )
	if isCollapsed == nil then
		isCollapsed = false;
	end
	local instance:table = m_groupIM:GetInstance();	
	instance.ContentStack:DestroyAllChildren();
	instance["isCollapsed"]		= isCollapsed;
	instance["CollapsePadding"] = nil;				-- reset any prior collapse padding

	instance.CollapseAnim:SetToBeginning();
	if isCollapsed == false then
		instance.CollapseAnim:SetToEnd();
	end	

	instance.RowHeaderButton:RegisterCallback( Mouse.eLClick, function() OnToggleCollapseGroup(instance); end );			
  	instance.RowHeaderButton:RegisterCallback( Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end);

	instance.CollapseAnim:RegisterAnimCallback(               function() OnAnimGroupCollapse( instance ); end );

	table.insert( m_uiGroups, instance );

	return instance;
end


-- ===========================================================================
--	debug - Create a test page.
-- ===========================================================================
function ViewTestPage()

	ResetTabForNewPageContent();

	local instance:table = NewCollapsibleGroupInstance();	
	instance.RowHeaderButton:SetText( "Test City Icon 1" );
	instance.Top:SetID("foo");
	
	local pHeaderInstance:table = {}
	ContextPtr:BuildInstanceForControl( "CityIncomeHeaderInstance", pHeaderInstance, instance.ContentStack ) ;	

	local pCityInstance:table = {};
	ContextPtr:BuildInstanceForControl( "CityIncomeInstance", pCityInstance, instance.ContentStack ) ;

	for i=1,3,1 do
		local pLineItemInstance:table = {};
		ContextPtr:BuildInstanceForControl("CityIncomeLineItemInstance", pLineItemInstance, pCityInstance.LineItemStack );
	end

	local pFooterInstance:table = {};
	ContextPtr:BuildInstanceForControl("CityIncomeFooterInstance", pFooterInstance, instance.ContentStack  );
	
	SetGroupCollapsePadding(instance, pFooterInstance.Top:GetSizeY() );
	RealizeGroup( instance );
	
	Controls.BottomYieldTotals:SetHide( true );
	Controls.BottomResourceTotals:SetHide( true );
	Controls.Scroll:SetSizeY( Controls.Main:GetSizeY() - (Controls.BottomYieldTotals:GetSizeY() + SIZE_HEIGHT_PADDING_BOTTOM_ADJUST ) );
end

-- ===========================================================================
--	Tab Callback
-- ===========================================================================
function ViewYieldsPage()	

	ResetTabForNewPageContent();

	local pPlayer:table = Players[Game.GetLocalPlayer()];

	local instance:table = nil;
	instance = NewCollapsibleGroupInstance();
	instance.RowHeaderButton:SetText( Locale.Lookup("LOC_HUD_REPORTS_ROW_CITY_INCOME") );
	
	local pHeaderInstance:table = {}
	ContextPtr:BuildInstanceForControl( "CityIncomeHeaderInstance", pHeaderInstance, instance.ContentStack ) ;	

	local goldCityTotal		:number = 0;
	local faithCityTotal	:number = 0;
	local scienceCityTotal	:number = 0;
	local cultureCityTotal	:number = 0;
	local tourismCityTotal	:number = 0;
	

	-- ========== City Income ==========

	for cityName,kCityData in pairs(m_kCityData) do
		local pCityInstance:table = {};
		ContextPtr:BuildInstanceForControl( "CityIncomeInstance", pCityInstance, instance.ContentStack ) ;
		pCityInstance.LineItemStack:DestroyAllChildren();
		pCityInstance.CityName:SetText( Locale.Lookup(kCityData.CityName) );

		-- Current Production
		local kCurrentProduction:table = kCityData.ProductionQueue[1];
		pCityInstance.CurrentProduction:SetHide( kCurrentProduction == nil );
		if kCurrentProduction ~= nil then
			local tooltip:string = Locale.Lookup(kCurrentProduction.Name);
			if kCurrentProduction.Description ~= nil then
				tooltip = tooltip .. "[NEWLINE]" .. Locale.Lookup(kCurrentProduction.Description);
			end
			pCityInstance.CurrentProduction:SetToolTipString( tooltip )

			if kCurrentProduction.Icon then
				pCityInstance.CityBannerBackground:SetHide( false );
				pCityInstance.CurrentProduction:SetIcon( kCurrentProduction.Icon );
				pCityInstance.CityProductionMeter:SetPercent( kCurrentProduction.PercentComplete );
				pCityInstance.CityProductionNextTurn:SetPercent( kCurrentProduction.PercentCompleteNextTurn );			
				pCityInstance.ProductionBorder:SetHide( kCurrentProduction.Type == ProductionType.DISTRICT );
			else
				pCityInstance.CityBannerBackground:SetHide( true );
			end
		end

		pCityInstance.Production:SetText( toPlusMinusString(kCityData.ProductionPerTurn) );
		pCityInstance.Food:SetText( toPlusMinusString(kCityData.FoodPerTurn) );
		pCityInstance.Gold:SetText( toPlusMinusString(kCityData.GoldPerTurn) );
		pCityInstance.Faith:SetText( toPlusMinusString(kCityData.FaithPerTurn) );
		pCityInstance.Science:SetText( toPlusMinusString(kCityData.SciencePerTurn) );
		pCityInstance.Culture:SetText( toPlusMinusString(kCityData.CulturePerTurn) );
		pCityInstance.Tourism:SetText( toPlusMinusString(kCityData.WorkedTileYields["TOURISM"]) );

		-- Add to all cities totals
		goldCityTotal	= goldCityTotal + kCityData.GoldPerTurn;
		faithCityTotal	= faithCityTotal + kCityData.FaithPerTurn;
		scienceCityTotal= scienceCityTotal + kCityData.SciencePerTurn;
		cultureCityTotal= cultureCityTotal + kCityData.CulturePerTurn;
		tourismCityTotal= tourismCityTotal + kCityData.WorkedTileYields["TOURISM"];
		
		-- Compute tiles worked by setting to total and subtracting all the things...
		local productionTilesWorked :number = kCityData.ProductionPerTurn;
		local foodTilesWorked		:number = kCityData.FoodPerTurn;
		local goldTilesWorked		:number = kCityData.GoldPerTurn;
		local faithTilesWorked		:number = kCityData.FaithPerTurn;
		local scienceTilesWorked	:number = kCityData.SciencePerTurn;
		local cultureTilesWorked	:number = kCityData.CulturePerTurn;

		for i,kDistrict in ipairs(kCityData.BuildingsAndDistricts) do			
			for i,kBuilding in ipairs(kDistrict.Buildings) do
				local pLineItemInstance:table = {};
				ContextPtr:BuildInstanceForControl("CityIncomeLineItemInstance", pLineItemInstance, pCityInstance.LineItemStack );
				pLineItemInstance.LineItemName:SetText( kBuilding.Name );

				pLineItemInstance.Production:SetText( toPlusMinusNoneString(kBuilding.ProductionPerTurn) );
				pLineItemInstance.Food:SetText( toPlusMinusNoneString(kBuilding.FoodPerTurn) );
				pLineItemInstance.Gold:SetText( toPlusMinusNoneString(kBuilding.GoldPerTurn) );
				pLineItemInstance.Faith:SetText( toPlusMinusNoneString(kBuilding.FaithPerTurn) );
				pLineItemInstance.Science:SetText( toPlusMinusNoneString(kBuilding.SciencePerTurn) );
				pLineItemInstance.Culture:SetText( toPlusMinusNoneString(kBuilding.CulturePerTurn) );
				
				productionTilesWorked	= productionTilesWorked - kBuilding.ProductionPerTurn;
				foodTilesWorked			= foodTilesWorked		- kBuilding.FoodPerTurn;
				goldTilesWorked			= goldTilesWorked		- kBuilding.GoldPerTurn;
				faithTilesWorked		= faithTilesWorked		- kBuilding.FaithPerTurn;
				scienceTilesWorked		= scienceTilesWorked	- kBuilding.SciencePerTurn;
				cultureTilesWorked		= cultureTilesWorked	- kBuilding.CulturePerTurn;
			end
		end

		local pLineItemInstance:table = {};
		ContextPtr:BuildInstanceForControl("CityIncomeLineItemInstance", pLineItemInstance, pCityInstance.LineItemStack );
		pLineItemInstance.LineItemName:SetText( Locale.Lookup("LOC_HUD_REPORTS_WORKED_TILES") );
		pLineItemInstance.Production:SetText( toPlusMinusNoneString(kCityData.WorkedTileYields["YIELD_PRODUCTION"]) );
		pLineItemInstance.Food:SetText( toPlusMinusNoneString(kCityData.WorkedTileYields["YIELD_FOOD"]) );
		pLineItemInstance.Gold:SetText( toPlusMinusNoneString(kCityData.WorkedTileYields["YIELD_GOLD"]) );
		pLineItemInstance.Faith:SetText( toPlusMinusNoneString(kCityData.WorkedTileYields["YIELD_FAITH"]) );
		pLineItemInstance.Science:SetText( toPlusMinusNoneString(kCityData.WorkedTileYields["YIELD_SCIENCE"]) );
		pLineItemInstance.Culture:SetText( toPlusMinusNoneString(kCityData.WorkedTileYields["YIELD_CULTURE"]) );

		local iYieldPercent = (Round(1 + (kCityData.HappinessNonFoodYieldModifier/100), 2)*.1);
		pLineItemInstance = {};
		ContextPtr:BuildInstanceForControl("CityIncomeLineItemInstance", pLineItemInstance, pCityInstance.LineItemStack );
		pLineItemInstance.LineItemName:SetText( Locale.Lookup("LOC_HUD_REPORTS_HEADER_AMENITIES") );
		pLineItemInstance.Production:SetText( toPlusMinusNoneString((kCityData.WorkedTileYields["YIELD_PRODUCTION"] * iYieldPercent) ) );
		pLineItemInstance.Food:SetText( "" );
		pLineItemInstance.Gold:SetText( toPlusMinusNoneString((kCityData.WorkedTileYields["YIELD_GOLD"] * iYieldPercent)) );
		pLineItemInstance.Faith:SetText( toPlusMinusNoneString((kCityData.WorkedTileYields["YIELD_FAITH"] * iYieldPercent)) );
		pLineItemInstance.Science:SetText( toPlusMinusNoneString((kCityData.WorkedTileYields["YIELD_SCIENCE"] * iYieldPercent)) );
		pLineItemInstance.Culture:SetText( toPlusMinusNoneString((kCityData.WorkedTileYields["YIELD_CULTURE"] * iYieldPercent)) );

		pCityInstance.LineItemStack:CalculateSize();
		pCityInstance.Darken:SetSizeY( pCityInstance.LineItemStack:GetSizeY() + DARKEN_CITY_INCOME_AREA_ADDITIONAL_Y );
		pCityInstance.Top:ReprocessAnchoring();
	end

	local pFooterInstance:table = {};
	ContextPtr:BuildInstanceForControl("CityIncomeFooterInstance", pFooterInstance, instance.ContentStack  );
	pFooterInstance.Gold:SetText( "[Icon_GOLD]"..toPlusMinusString(goldCityTotal) );
	pFooterInstance.Faith:SetText( "[Icon_FAITH]"..toPlusMinusString(faithCityTotal) );
	pFooterInstance.Science:SetText( "[Icon_SCIENCE]"..toPlusMinusString(scienceCityTotal) );
	pFooterInstance.Culture:SetText( "[Icon_CULTURE]"..toPlusMinusString(cultureCityTotal) );
	pFooterInstance.Tourism:SetText( "[Icon_TOURISM]"..toPlusMinusString(tourismCityTotal) );

	SetGroupCollapsePadding(instance, pFooterInstance.Top:GetSizeY() );
	RealizeGroup( instance );


	-- ========== Building Expenses ==========

	instance = NewCollapsibleGroupInstance();
	instance.RowHeaderButton:SetText( Locale.Lookup("LOC_HUD_REPORTS_ROW_BUILDING_EXPENSES") );

	local pHeader:table = {};
	ContextPtr:BuildInstanceForControl( "BuildingExpensesHeaderInstance", pHeader, instance.ContentStack ) ;

	local iTotalBuildingMaintenance :number = 0;
	for cityName,kCityData in pairs(m_kCityData) do

		-- Adds district costs to expenses !!
		-- don't count city center
		-- District maintenance isn't factored into the expense screen ( but is factored into maintenance )
		-- This helps rectify that by adding up all the districts in a city, -1 for city center
		-- Tooltip shows districts have a -1 gpt cost, not sure if this goes up or if its different for other districts or
		-- later eras

		local iNumDistricts : number = 0

		-- Can't find/figure out how to find district type, so i'll do it myself
		-- this goes through the districts and adds the maintenance if not pillaged/being built
		for _,kBuilding in ipairs(kCityData.BuildingsAndDistricts) do
			if kBuilding.isBuilt then
				for i = 1, #GameInfo.Districts do
					if kBuilding.Name == Locale.Lookup( GameInfo.Districts[i].Name ) then
						iNumDistricts = iNumDistricts + GameInfo.Districts[i].Maintenance
						break
					end
				end
			end
		end

		if ( iNumDistricts > 0 ) then
			local pBuildingInstance:table = {}
			ContextPtr:BuildInstanceForControl( "BuildingExpensesEntryInstance", pBuildingInstance, instance.ContentStack )
			pBuildingInstance.CityName:SetText( Locale.Lookup(cityName) )
			pBuildingInstance.BuildingName:SetText( "Districts" )
			pBuildingInstance.Gold:SetText( "-" .. tostring( iNumDistricts ) )
			iTotalBuildingMaintenance = iTotalBuildingMaintenance - iNumDistricts
		end

		for i,kBuilding in ipairs(kCityData.Buildings) do
			if kBuilding.Maintenance > 0 then
				local pBuildingInstance:table = {};
				ContextPtr:BuildInstanceForControl( "BuildingExpensesEntryInstance", pBuildingInstance, instance.ContentStack ) ;		
				pBuildingInstance.CityName:SetText( Locale.Lookup(cityName) );
				pBuildingInstance.BuildingName:SetText( Locale.Lookup(kBuilding.Name) );
				pBuildingInstance.Gold:SetText( tostring( "-" .. kBuilding.Maintenance ) );
				iTotalBuildingMaintenance = iTotalBuildingMaintenance - kBuilding.Maintenance;
			end
		end
	end
	local pBuildingFooterInstance:table = {};		
	ContextPtr:BuildInstanceForControl( "GoldFooterInstance", pBuildingFooterInstance, instance.ContentStack ) ;		
	pBuildingFooterInstance.Gold:SetText("[ICON_Gold]"..tostring(iTotalBuildingMaintenance) );

	SetGroupCollapsePadding(instance, pBuildingFooterInstance.Top:GetSizeY() );
	RealizeGroup( instance );

	-- ========== Diplomatic Deals Expenses ==========
	
	instance = NewCollapsibleGroupInstance();	
	instance.RowHeaderButton:SetText( Locale.Lookup("LOC_HUD_REPORTS_ROW_DIPLOMATIC_DEALS") );

	local pHeader:table = {};
	ContextPtr:BuildInstanceForControl( "DealHeaderInstance", pHeader, instance.ContentStack ) ;

	local iTotalDealGold :number = 0;

	for i,kDeal in ipairs(m_kDealData) do
		local pDealInstance:table = {};		
		ContextPtr:BuildInstanceForControl( "DealEntryInstance", pDealInstance, instance.ContentStack ) ;		

		pDealInstance.Civilization:SetText( kDeal.Name );
		pDealInstance.Duration:SetText( kDeal.Duration );
		if kDeal.IsOutgoing then
			pDealInstance.Gold:SetText( "-"..tostring(kDeal.Amount) );
			iTotalDealGold = iTotalDealGold - kDeal.Amount;
		else
			pDealInstance.Gold:SetText( "+"..tostring(kDeal.Amount) );
			iTotalDealGold = iTotalDealGold + kDeal.Amount;
		end
	end
	local pDealFooterInstance:table = {};		
	ContextPtr:BuildInstanceForControl( "GoldFooterInstance", pDealFooterInstance, instance.ContentStack ) ;		
	pDealFooterInstance.Gold:SetText("[ICON_Gold]"..tostring(iTotalDealGold) );

	SetGroupCollapsePadding(instance, pDealFooterInstance.Top:GetSizeY() );
	RealizeGroup( instance );

	-- ========== !! Unit Expenses ==========

	instance = NewCollapsibleGroupInstance();
	instance.RowHeaderButton:SetText( Locale.Lookup( "LOC_HUD_UNITS_Unit_Expenses" ) );

	local pHeader:table = {};
	ContextPtr:BuildInstanceForControl( "UnitExpensesHeaderInstance", pHeader, instance.ContentStack ) ;

	local iTotalUnitMaintenance : number = 0
	local iTotalUnits : number = 0
	local conscript_levee : number = 0

	-- start of crappy code !!
	-- this is a way to calculate expenses for units, however if you have the conscript
	-- civic, it can cause issues, this is a way to detect it
	-- honestly, this is a terribly awful way to code but until i can dig deeper to see
	-- if there is a better way, or when they release the dll stuff, this will have to do
	-- Also: Unit Expenses must be last in line in order to calculate the total maintenance costs
	for _, kUnitGroup in pairs( m_kUnitData["Unit_Expenses"] ) do
		if kUnitGroup.Cost > 0 then
			iTotalUnitMaintenance = iTotalUnitMaintenance - kUnitGroup.Amount * kUnitGroup.Cost
			iTotalUnits = iTotalUnits + kUnitGroup.Amount
		end
	end

	local iTotalExpenses : number = iTotalBuildingMaintenance + iTotalUnitMaintenance
	local conscript_levee : number = 0
	local totalCost : number = -m_kCityTotalData.Expenses[YieldTypes.GOLD]

	-- this is nasty way of figuring out if you have conscript or levee
	if iTotalExpenses == totalCost then
		conscript_levee = 0
	elseif iTotalExpenses + iTotalUnits == totalCost then
		conscript_levee = 1
	else
		conscript_levee = 2
	end

	iTotalUnitMaintenance = 0

	for _, kUnitGroup in pairs( m_kUnitData["Unit_Expenses"] ) do
		if kUnitGroup.Cost - conscript_levee > 0 then
			local pUnitInstance:table = {}
			ContextPtr:BuildInstanceForControl( "UnitExpensesEntryInstance", pUnitInstance, instance.ContentStack )
			pUnitInstance.UnitName:SetText( kUnitGroup.Name )
			pUnitInstance.Gold:SetText( "-"..tostring( kUnitGroup.Amount * ( kUnitGroup.Cost - conscript_levee ) ) )
			iTotalUnitMaintenance = iTotalUnitMaintenance - kUnitGroup.Amount * ( kUnitGroup.Cost - conscript_levee )
		end
	end

	local pBuildingFooterInstance : table = {};
	ContextPtr:BuildInstanceForControl( "GoldFooterInstance", pBuildingFooterInstance, instance.ContentStack ) ;		
	pBuildingFooterInstance.Gold:SetText( "[ICON_Gold]" .. tostring( iTotalUnitMaintenance ) );

	SetGroupCollapsePadding(instance, pBuildingFooterInstance.Top:GetSizeY() );
	RealizeGroup( instance );

	-- Unit Expense END!!

	-- ========== TOTALS ==========

	Controls.Stack:CalculateSize();
	Controls.Scroll:CalculateSize();

	-- Totals at the bottom
	Controls.GoldIncome:SetText( toPlusMinusNoneString( m_kCityTotalData.Income[YieldTypes.GOLD] ));
	Controls.FaithIncome:SetText( toPlusMinusNoneString( m_kCityTotalData.Income[YieldTypes.FAITH] ));
	Controls.ScienceIncome:SetText( toPlusMinusNoneString( m_kCityTotalData.Income[YieldTypes.SCIENCE] ));
	Controls.CultureIncome:SetText( toPlusMinusNoneString( m_kCityTotalData.Income[YieldTypes.CULTURE] ));
	Controls.TourismIncome:SetText( toPlusMinusNoneString( m_kCityTotalData.Income["TOURISM"] ));	
	Controls.GoldExpense:SetText( toPlusMinusNoneString( -m_kCityTotalData.Expenses[YieldTypes.GOLD] ));	-- Flip that value!
	Controls.GoldNet:SetText( toPlusMinusNoneString( m_kCityTotalData.Net[YieldTypes.GOLD] ));
	Controls.FaithNet:SetText( toPlusMinusNoneString( m_kCityTotalData.Net[YieldTypes.FAITH] ));
	
	Controls.GoldBalance:SetText( m_kCityTotalData.Treasury[YieldTypes.GOLD] );
	Controls.FaithBalance:SetText( m_kCityTotalData.Treasury[YieldTypes.FAITH] );
	Controls.ScienceBalance:SetText( m_kCityTotalData.Treasury[YieldTypes.SCIENCE] );
	Controls.CultureBalance:SetText( m_kCityTotalData.Treasury[YieldTypes.CULTURE] );
	Controls.TourismBalance:SetText( m_kCityTotalData.Treasury["TOURISM"] );
	
	Controls.BottomYieldTotals:SetHide( false );
	Controls.BottomYieldTotals:SetSizeY( SIZE_HEIGHT_BOTTOM_YIELDS );
	Controls.BottomResourceTotals:SetHide( true );
	Controls.Scroll:SetSizeY( Controls.Main:GetSizeY() - (Controls.BottomYieldTotals:GetSizeY() + SIZE_HEIGHT_PADDING_BOTTOM_ADJUST ) );	
end


-- ===========================================================================
--	Tab Callback
-- ===========================================================================
function ViewResourcesPage()	

	ResetTabForNewPageContent();

	local strategicResources:string = "";
	local luxuryResources	:string = "";

	for eResourceType,kSingleResourceData in pairs(m_kResourceData) do
		
		local instance:table = NewCollapsibleGroupInstance();	

		local kResource :table = GameInfo.Resources[eResourceType];
		instance.RowHeaderButton:SetText(  kSingleResourceData.Icon..Locale.Lookup( kResource.Name ) );

		local pHeaderInstance:table = {};
		ContextPtr:BuildInstanceForControl( "ResourcesHeaderInstance", pHeaderInstance, instance.ContentStack ) ;

		local kCitiesAmount:table = kSingleResourceData.CityList;
		for i,kCityAmount in ipairs(kCitiesAmount) do
			local pCityInstance:table = {};
			ContextPtr:BuildInstanceForControl( "ResourcesEntryInstance", pCityInstance, instance.ContentStack ) ;
			pCityInstance.CityName:SetText( Locale.Lookup(kCityAmount.CityName) );
			pCityInstance.Control:SetText("-");	--??TRON TODO:
			pCityInstance.Amount:SetText( (kCityAmount.Amount==0) and "0" or "+"..tostring(kCityAmount.Amount) );
		end

		local pFooterInstance:table = {};
		ContextPtr:BuildInstanceForControl( "ResourcesFooterInstance", pFooterInstance, instance.ContentStack ) ;
		pFooterInstance.Amount:SetText( tostring(kSingleResourceData.Total) );		

		if kSingleResourceData.IsStrategic then
			strategicResources = strategicResources .. kSingleResourceData.Icon .. tostring( kSingleResourceData.Total );
		else
			luxuryResources = luxuryResources .. kSingleResourceData.Icon .. tostring( kSingleResourceData.Total );			
		end

		SetGroupCollapsePadding(instance, pFooterInstance.Top:GetSizeY() );
		RealizeGroup( instance );
	end

	Controls.StrategicResources:SetText( strategicResources );
	Controls.LuxuryResources:SetText( luxuryResources );

	Controls.Stack:CalculateSize();
	Controls.Scroll:CalculateSize();

	Controls.BottomYieldTotals:SetHide( true );
	Controls.BottomResourceTotals:SetHide( false );
	Controls.Scroll:SetSizeY( Controls.Main:GetSizeY() - (Controls.BottomResourceTotals:GetSizeY() + SIZE_HEIGHT_PADDING_BOTTOM_ADJUST ) );	
end

-- ===========================================================================
--	Tab Callback
-- ===========================================================================
function ViewCityStatusPage()	

	ResetTabForNewPageContent();

	local instance:table = m_simpleIM:GetInstance();	
	instance.Top:DestroyAllChildren();
	
	local pHeaderInstance:table = {}
	ContextPtr:BuildInstanceForControl( "CityStatusHeaderInstance", pHeaderInstance, instance.Top ) ;	

	-- 
	for cityName,kCityData in pairs(m_kCityData) do

		local pCityInstance:table = {}
		ContextPtr:BuildInstanceForControl( "CityStatusEntryInstance", pCityInstance, instance.Top ) ;	
		pCityInstance.CityName:SetText( Locale.Lookup(kCityData.CityName) );
		pCityInstance.Population:SetText( tostring(kCityData.Population) );

		if kCityData.HousingMultiplier == 0 then
			status = "LOC_HUD_REPORTS_STATUS_HALTED";
		elseif kCityData.HousingMultiplier <= 0.5 then
			status = "LOC_HUD_REPORTS_STATUS_SLOWED";
		else
			status = "LOC_HUD_REPORTS_STATUS_NORMAL";
		end
		pCityInstance.GrowthRateStatus:SetText( Locale.Lookup(status) );

		pCityInstance.Housing:SetText( tostring(kCityData.Housing) );
		pCityInstance.Amenities:SetText( tostring(kCityData.AmenitiesNum).." / "..tostring(kCityData.AmenitiesRequiredNum) );

		local happinessText:string = Locale.Lookup( GameInfo.Happinesses[kCityData.Happiness].Name );
		pCityInstance.CitizenHappiness:SetText( happinessText );

		local warWearyValue:number = kCityData.AmenitiesLostFromWarWeariness;
		pCityInstance.WarWeariness:SetText( (warWearyValue==0) and "0" or "-"..tostring(warWearyValue) );

		pCityInstance.Status:SetText( kCityData.IsUnderSiege and Locale.Lookup("LOC_HUD_REPORTS_STATUS_UNDER_SEIGE") or Locale.Lookup("LOC_HUD_REPORTS_STATUS_NORMAL") );

		pCityInstance.Strength:SetText( tostring(kCityData.Defense) );
		pCityInstance.Damage:SetText( tostring(kCityData.Damage) );			
	end

	Controls.Stack:CalculateSize();
	Controls.Scroll:CalculateSize();

	Controls.BottomYieldTotals:SetHide( true );
	Controls.BottomResourceTotals:SetHide( true );
	Controls.Scroll:SetSizeY( Controls.Main:GetSizeY() - 88);
end

-- ===========================================================================
--	!! Start of Unit Report Page
-- ===========================================================================
function ViewUnitsPage()

	ResetTabForNewPageContent();	
	
	for _, kUnitGroup in spairs( m_kUnitData["Unit_Report"], function( t, a, b ) return t[b].ID > t[a].ID end ) do
		local instance : table = NewCollapsibleGroupInstance()
		local iTotal : number = 0
		
		instance.RowHeaderButton:SetText( Locale.Lookup(kUnitGroup.Name))
		
		local pHeaderInstance:table = {}
		ContextPtr:BuildInstanceForControl( kUnitGroup.Header, pHeaderInstance, instance.ContentStack )
		
		for i, unit in ipairs( kUnitGroup.units ) do
			iTotal = iTotal + 1
			
			local unitInstance:table = {}
			ContextPtr:BuildInstanceForControl( kUnitGroup.Entry, unitInstance, instance.ContentStack )
			local unitGreatPerson = unit:GetGreatPerson()
			unitInstance.UnitName:SetText( Locale.Lookup( unit:GetName() ) )
			
			if ( unit:GetFormationUnitCount() > 1 ) then
				unitInstance.UnitMove:SetText( tostring( unit:GetFormationMovesRemaining() ) .. "/" .. tostring( unit:GetFormationMaxMoves() ) )
				unitInstance.Formation:SetHide( false )
			elseif kUnitGroup.Entry ~= "UnitsTraderEntryInstance" then
				unitInstance.UnitMove:SetText( tostring( unit:GetMovesRemaining() ) .. "/" .. tostring( unit:GetMaxMoves() ) )
			end
			
			-- adds the status icon
			local activityType:number = UnitManager.GetActivityType( unit )

			if activityType == ActivityTypes.ACTIVITY_SLEEP then
				local textureOffsetX:number, textureOffsetY:number, textureSheet:string = IconManager:FindIconAtlas( "ICON_STATS_SLEEP", 22 )
				unitInstance.UnitStatus:SetTexture( textureOffsetX, textureOffsetY, textureSheet )
			elseif activityType == ActivityTypes.ACTIVITY_HOLD then
				local textureOffsetX:number, textureOffsetY:number, textureSheet:string = IconManager:FindIconAtlas( "ICON_STATS_SKIP", 22 )
				unitInstance.UnitStatus:SetTexture( textureOffsetX, textureOffsetY, textureSheet )
			elseif activityType ~= ActivityTypes.ACTIVITY_AWAKE and unit:GetFortifyTurns() > 0 then
				local textureOffsetX:number, textureOffsetY:number, textureSheet:string = IconManager:FindIconAtlas( "ICON_DEFENSE", 22 );
				unitInstance.UnitStatus:SetTexture( textureOffsetX, textureOffsetY, textureSheet );
			end
			
			if kUnitGroup.Entry == "UnitsMilitaryEntryInstance" then
				local unitExp : table = unit:GetExperience()
				
				if ( unit:GetMilitaryFormation() == MilitaryFormationTypes.CORPS_FORMATION ) then
					unitInstance.UnitName:SetText( Locale.Lookup( unit:GetName() ) .. " " .. "[ICON_Corps]" )
				elseif ( unit:GetMilitaryFormation() == MilitaryFormationTypes.ARMY_FORMATION ) then
					unitInstance.UnitName:SetText( Locale.Lookup( unit:GetName() ) .. " " .. "[ICON_Army]" )
				end
			
				unitInstance.UnitLevel:SetText( tostring( unitExp:GetLevel() ) )
				
				unitInstance.UnitExp:SetText( tostring( unitExp:GetExperiencePoints() ) .. "/" .. tostring( unitExp:GetExperienceForNextLevel() ) )
				if ( unitExp:GetExperiencePoints() >= unitExp:GetExperienceForNextLevel() and unit:GetMovesRemaining() > 0 ) then
					unitInstance.Promotion:SetHide( false )
					local bCanStart, tResults = UnitManager.CanStartCommand( unit, UnitCommandTypes.PROMOTE, true, true);
					local tPromotions		= tResults[UnitCommandResults.PROMOTIONS];
					--unitInstance.Promotion:RegisterCallback( Mouse.eMouseEnter, function() UI.SelectUnit(unit) end )
					unitInstance.Promotion:RegisterCallback( Mouse.eLClick, function() LuaEvents.Report_PromoteUnit( unit ); end )
				end

				unitInstance.UnitHealth:SetText( tostring( unit:GetMaxDamage() - unit:GetDamage() ) .. "/" .. tostring( unit:GetMaxDamage() ) )
				
				local bCanStart, tResults = UnitManager.CanStartOperation( unit, UnitOperationTypes.UPGRADE, nil, true );

				if ( bCanStart ) then
					local bCanStart, tResults = UnitManager.CanStartOperation( unit, UnitOperationTypes.UPGRADE, nil, false, true )
					
					unitInstance.Upgrade:SetHide( false )
					unitInstance.Upgrade:RegisterCallback( Mouse.eLClick, function() UnitManager.RequestOperation( unit, UnitOperationTypes.UPGRADE ); ContextPtr:RequestRefresh() end )
					local upgradeUnitName = GameInfo.Units[tResults[UnitOperationResults.UNIT_TYPE]].Name;
					local toolTipString	= Locale.Lookup( "LOC_UNITOPERATION_UPGRADE_DESCRIPTION" );
					toolTipString = toolTipString .. " " .. Locale.Lookup(upgradeUnitName);

					local upgradeCost = unit:GetUpgradeCost();
					
					if (upgradeCost ~= nil) then
						toolTipString = toolTipString .. ": " .. upgradeCost .. " " .. Locale.Lookup("LOC_TOP_PANEL_GOLD");
					end

					toolTipString = Locale.Lookup( "LOC_UNITOPERATION_UPGRADE_INFO", upgradeUnitName, upgradeCost );
					
					if (tResults[UnitOperationResults.FAILURE_REASONS] ~= nil) then
						-- Add the reason(s) to the tool tip
						for i,v in ipairs(tResults[UnitOperationResults.FAILURE_REASONS]) do
							toolTipString = toolTipString .. "[NEWLINE]" .. "[COLOR:Red]" .. Locale.Lookup(v) .. "[ENDCOLOR]";
						end
					end
						
					unitInstance.Upgrade:SetToolTipString( toolTipString )
				end
			elseif kUnitGroup.Entry == "UnitsCivilianEntryInstance" then
				unitInstance.UnitCharges:SetText( tostring( unit:GetBuildCharges() ) )
			elseif kUnitGroup.Entry == "UnitsGreatPeopleEntryInstance" then
				unitInstance.UnitClass:SetText( Locale.Lookup( GameInfo.GreatPersonClasses[unitGreatPerson:GetClass()].Name ) )
			elseif kUnitGroup.Entry == "UnitsTraderEntryInstance" then
				local owningPlayer:table = Players[unit:GetOwner()];
				local cities:table = owningPlayer:GetCities();
				local yieldtype : table = { ["YIELD_FOOD"] = "[ICON_Food]",
											["YIELD_PRODUCTION"] = "[ICON_Production]",
											["YIELD_GOLD"] = "[ICON_Gold]",
											["YIELD_SCIENCE"] = "[ICON_Science]",
											["YIELD_CULTURE"] = "[ICON_Culture]",
											["YIELD_FAITH"] = "[ICON_Faith]"
										  }
				local yields : string = ""

				for _, city in cities:Members() do
					local outgoingRoutes:table = city:GetTrade():GetOutgoingRoutes();
					for i,route in ipairs(outgoingRoutes) do
						if unit:GetID() == route.TraderUnitID then
							-- Find origin city
							local originCity:table = cities:FindID(route.OriginCityID);

							-- Find destination city
							local destinationPlayer:table = Players[route.DestinationCityPlayer];
							local destinationCities:table = destinationPlayer:GetCities();
							local destinationCity:table = destinationCities:FindID(route.DestinationCityID);

							-- Set origin to destination name
							if originCity and destinationCity then
								unitInstance.UnitRoute:SetText( Locale.Lookup("LOC_HUD_UNIT_PANEL_TRADE_ROUTE_NAME", originCity:GetName(), destinationCity:GetName()) );
							end

							for j, yieldInfo in pairs( route.OriginYields ) do
								if yieldInfo.Amount > 0 then
									local yieldDetails:table = GameInfo.Yields[yieldInfo.YieldIndex];
									yields = yields .. yieldtype[yieldDetails.YieldType] .. "+" .. yieldInfo.Amount
									unitInstance.UnitYields:SetText( yields )
								end
							end
						end
					end
				end
			elseif kUnitGroup.Entry == "UnitsSpyEntryInstance" then
				local operationType : number = unit:GetSpyOperation();

				if ( operationType ~= -1 ) then
					-- Mission Name
					local operationInfo:table = GameInfo.UnitOperations[operationType];
					unitInstance.UnitOperation:SetText( Locale.Lookup( operationInfo.Description ) )

					-- Turns Remaining
					unitInstance.UnitTurns:SetText( Locale.Lookup( "LOC_UNITPANEL_ESPIONAGE_MORE_TURNS", unit:GetSpyOperationEndTurn() - Game.GetCurrentGameTurn() ) )
				end
			end
			
			-- allows you to select a unit and zoom to them
			unitInstance.LookAtButton:RegisterCallback( Mouse.eLClick, function() Close(); UI.LookAtPlot( unit:GetX( ), unit:GetY( ) ); UI.SelectUnit( unit ); end )
			unitInstance.LookAtButton:RegisterCallback( Mouse.eMouseEnter, function() UI.PlaySound( "Main_Menu_Mouse_Over" ); end )
		end
	
		local pFooterInstance:table = {}
		ContextPtr:BuildInstanceForControl( "UnitsFooterInstance", pFooterInstance, instance.ContentStack )
		pFooterInstance.Amount:SetText( tostring( iTotal ) )
	
		SetGroupCollapsePadding( instance, pFooterInstance.Top:GetSizeY() )
		RealizeGroup( instance )
	end

	Controls.Stack:CalculateSize();
	Controls.Scroll:CalculateSize();
	
	Controls.BottomYieldTotals:SetHide( true )
	Controls.BottomResourceTotals:SetHide( true )
	Controls.Scroll:SetSizeY( Controls.Main:GetSizeY() - 88 )
	

end

-- ===========================================================================
--	!! End of Unit Report Page
-- ===========================================================================

-- ===========================================================================
--
-- ===========================================================================
function AddTabSection( name:string, populateCallback:ifunction )
	local kTab		:table				= m_tabIM:GetInstance();	
	kTab.Button[DATA_FIELD_SELECTION]	= kTab.Selection;

	local callback	:ifunction	= function()
		if m_tabs.prevSelectedControl ~= nil then
			m_tabs.prevSelectedControl[DATA_FIELD_SELECTION]:SetHide(true);
		end
		kTab.Selection:SetHide(false);
		populateCallback();
	end

	kTab.Button:GetTextControl():SetText( Locale.Lookup(name) );
	kTab.Button:SetSizeToText( 40, 20 );
    kTab.Button:RegisterCallback( Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end);

	m_tabs.AddTab( kTab.Button, callback );
end


-- ===========================================================================
--	UI Callback
-- ===========================================================================
function OnInputHandler( pInputStruct:table )
	local uiMsg :number = pInputStruct:GetMessageType();
	if uiMsg == KeyEvents.KeyUp then 
		local uiKey = pInputStruct:GetKey();
		if uiKey == Keys.VK_ESCAPE then
			if ContextPtr:IsHidden()==false then
				Close();
				return true;
			end
		end		
	end
	return false;
end


-- ===========================================================================
--	UI Event
-- ===========================================================================
function OnInit( isReload:boolean )
	if isReload then		
		if ContextPtr:IsHidden()==false then
			Open();
		end
	end
	m_tabs.AddAnimDeco(Controls.TabAnim, Controls.TabArrow);	
end


-- ===========================================================================
function Resize()
	local topPanelSizeY:number = 30;

	if m_debugFullHeight then
		x,y = UIManager:GetScreenSizeVal();
		Controls.Main:SetSizeY( y - topPanelSizeY );
		Controls.Main:SetOffsetY( topPanelSizeY * 0.5 );
	end
end

-- ===========================================================================
--
-- ===========================================================================
function Initialize()

	Resize();

	m_tabs = CreateTabs( Controls.TabContainer, 42, 34, 0xFF331D05 );
	--AddTabSection( "Test",								ViewTestPage );			--TRONSTER debug
	--AddTabSection( "Test2",								ViewTestPage );			--TRONSTER debug
	AddTabSection( "LOC_HUD_REPORTS_TAB_YIELDS",		ViewYieldsPage );
	AddTabSection( "LOC_HUD_REPORTS_TAB_RESOURCES",		ViewResourcesPage );
	AddTabSection( "LOC_HUD_REPORTS_TAB_CITY_STATUS",	ViewCityStatusPage );
	AddTabSection( "LOC_HUD_REPORTS_TAB_UNITS",								ViewUnitsPage );

	m_tabs.SameSizedTabs(50);
	m_tabs.CenterAlignTabs(-10);		

	-- UI Callbacks
	ContextPtr:SetInitHandler( OnInit );
	ContextPtr:SetInputHandler( OnInputHandler, true );
	ContextPtr:SetRefreshHandler( function() m_kCityData, m_kCityTotalData, m_kResourceData, m_kUnitData, m_kDealData = GetData(); ViewUnitsPage(); end );
	
	Events.UnitPromoted.Add( function() LuaEvents.UnitPanel_HideUnitPromotion(); ContextPtr:RequestRefresh() end )

	Controls.CloseButton:RegisterCallback( Mouse.eLClick, OnCloseButton );
	Controls.CloseButton:RegisterCallback(	Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end);
	Controls.CollapseAll:RegisterCallback( Mouse.eLClick, OnCollapseAllButton );
	Controls.CollapseAll:RegisterCallback(	Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end);
	
	-- Events
	LuaEvents.TopPanel_OpenReportsScreen.Add( OnTopOpenReportsScreen );
	LuaEvents.TopPanel_CloseReportsScreen.Add( OnTopCloseReportsScreen );
end
Initialize();
