-- Written by Kip Turner, Copyright ROBLOX 2015

local CoreGui = Game:GetService("CoreGui")
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
local Modules = GuiRoot:FindFirstChild("Modules")
local Utility = require(Modules:FindFirstChild('Utility'))

local PlatformService = nil
pcall(function() PlatformService = game:GetService('PlatformService') end)


local SoundManager = require(Modules:FindFirstChild('SoundManager'))

local ScreenManager = {}

local ScreenStack = {}
local ScreenToHideMap = {}

local function ContainsScreenInternal(screen)
	local foundScreenIndex = nil
	for i, otherScreen in pairs(ScreenStack) do
		if otherScreen == screen then
			foundScreenIndex = i
		end
	end

	return foundScreenIndex
end

-- TODO: handle race conditions for opening multiple screens
function ScreenManager:OpenScreen(screen, hideCurrent)
	if hideCurrent == nil then
		hideCurrent = true
	end

	local currentScreen = self:GetTopScreen()

	if currentScreen ~= screen then
		local foundScreenIndex = ContainsScreenInternal(screen)


		if foundScreenIndex then
			table.remove(ScreenStack, foundScreenIndex)
		end

		if currentScreen then
			currentScreen:RemoveFocus()
			if hideCurrent then
				currentScreen:Hide()
			end
		end

		table.insert(ScreenStack, screen)
		ScreenToHideMap[screen] = hideCurrent
		-- spawn(function()
			screen:Show()
			screen:Focus()
		-- end)
	end
end

function ScreenManager:CloseCurrent()
	local showNewTop = true
	local currentScreen = ScreenStack[#ScreenStack]
	local belowScreen = currentScreen and self:GetScreenBelow(currentScreen)
	if currentScreen then
		-- spawn(function()
			currentScreen:Hide()
			currentScreen:RemoveFocus()
			if currentScreen.ScreenRemoved then
				currentScreen:ScreenRemoved()
			end
		-- end)
		if not ScreenToHideMap[currentScreen] then
			showNewTop = false
		end
		table.remove(ScreenStack, #ScreenStack)
		ScreenToHideMap[currentScreen] = nil
	end

	-- if belowScreen and belowScreen ~= self:GetTopScreen() then return end
	local newTop = belowScreen
	if newTop and newTop == self:GetTopScreen() then
		-- spawn(function()
			if showNewTop then
				newTop:Show()
			end
			newTop:Focus()
		-- end)
	end
end

function ScreenManager:ContainsScreen(screen)
	local index = ContainsScreenInternal(screen)
	if index then
		return ScreenStack[index]
	end
	return nil
end

function ScreenManager:GetScreenBelow(screen)
	local thisScreenIndex = ContainsScreenInternal(screen)
	if thisScreenIndex then
		return ScreenStack[thisScreenIndex - 1]
	end
	return nil
end

function ScreenManager:GetTopScreen()
	return ScreenStack[#ScreenStack]
end


----- TWEENS -----

local function FadeInElement(element, tweeners)
	if element == nil then return end
	if element:IsA('ImageLabel') or element:IsA('ImageButton') then
		table.insert(tweeners, Utility.PropertyTweener(element, 'ImageTransparency', 1, element.ImageTransparency, 0.5, Utility.EaseOutQuad))
	end
	if element:IsA('GuiObject') then
		table.insert(tweeners, Utility.PropertyTweener(element, 'BackgroundTransparency', 1, element.BackgroundTransparency, 0.5, Utility.EaseOutQuad))
	end
	if element:IsA('TextLabel') or element:IsA('TextBox') or element:IsA('TextButton') then
		table.insert(tweeners, Utility.PropertyTweener(element, 'TextTransparency', 1, element.TextTransparency, 0.5, Utility.EaseOutQuad))
	end
	for _, child in pairs(element:GetChildren()) do
		FadeInElement(child, tweeners)
	end
end

function ScreenManager:FadeInSitu(guiObject)
	local tweeners = {}
	if guiObject then
		FadeInElement(guiObject, tweeners)
	end
	return tweeners
end

function ScreenManager:DefaultFadeIn(guiObject)
	local tweeners = {}

	if guiObject then
		table.insert(tweeners, Utility.PropertyTweener(guiObject, 'Position', guiObject.Position + UDim2.new(0.15, 0, 0, 0), guiObject.Position, 0.5,
			function(t,b,c,d)
				if t >= d then return b + c end
				t = t / d;
				local tComputed = t*(t-2)
				return -UDim2.new(c.X.Scale * tComputed, c.X.Offset * tComputed, c.Y.Scale * tComputed, c.Y.Offset * tComputed) + b
			end))

		FadeInElement(guiObject, tweeners)
	end

	pcall(function()
		if UserSettings().GameSettings:InStudioMode() or (PlatformService and PlatformService.DatamodelType == 0) then
			local CameraManager = require(Modules:FindFirstChild('CameraManager'))
			CameraManager:StartTransitionScreenEffect()
		end
	end)

	return tweeners
end

function ScreenManager:DefaultCancelFade(tweens)
	if tweens then
		for _, tween in pairs(tweens) do
			tween:Finish()
		end
	end

	return nil
end
---------------

--------- SOUNDS ---------

function ScreenManager:PlayDefaultOpenSound()
	SoundManager:Play('ScreenChange')
end

----------------------------



return ScreenManager

