local UIManager = {}

local MESSAGE_BOX_PATH = "assets/prefabs/ui/common/message_box.prefab"
local TUTORIAL_PATH = "assets/prefabs/ui/tutorial/tutorial_ui.prefab"

UIManager.UI_TYPE = {
	DEFAULT = 0,
	MULTI = 1, -- 非唯一界面,此类型界面同一时间可以打开多个
	MAIN = 2, -- 主要的界面,打开此界面的时候会关闭所有其他界面
}

UIManager.MESSAGE_BOX_TAG = {
	BATTLE_SKIP = 1,
	LOGIN_FAIL = 2
}

-- 个别uipath不同模块需要使用，统一写到一个地方避免后期要改的话改漏了
UIManager.UI_PATH = {
	GM_TOO_UI = "app/ui/gm/gm_tool_ui",
	MAINCITY_UI = "app/ui/main_city/main_city_ui",
	BATTLE_UI = "app/ui/battle/battle_ui",
	ROGUE_SKILL_UI = "app/ui/battle/battle_skill_select_ui",
	REWARD_BOX = "app/ui/tips/reward_box",
	HERO_DETAIL_UI = "app/ui/hero/hero_detail_ui",
	ARENA_MATCH_UI = "app/ui/arena/arena_match_ui",
	BATTLE_PVP_UI = "app/ui/battle/battle_ui_pvp",
}

-- 动画类型
UIManager.ANI_TYPE = {
	POP 			= 1,  -- 弹出
	NONE 			= 2,  -- 无动画
}

-- loading类型
UIManager.LOADING_TYPE = {
	BLACK = 1,
	CLOUD = 2
}

-- ui缓存上限
local UI_CACHE_SIZE = 5
-- 根据以往项目的经验提前申请一个值,避免动态扩容导致的开销,可根据项目实际情况调整
local MAIN_CANVAS_HIERARCHY_CAPACITY = 20480
local MAIN_CANVAS_ORDER = 1000
local UI_INTERVAL_ORDER = 400
local UI_MAX_ORDER = 28000
local UI_BARS_UNDER_ORDER = 2
local CLICK_EFFECT = 31000

local OTHER_CANVAS_INTERVAL_ORDER = {
	TOAST = 1,
	TUTORIAL = 2,
	NET = 3,
	LOADING = 4,
	SWALLOW_TOUCH = 5,
	MESSAGE_BOX_TOP = 6,
	LOADING_TOP = 7,
	-- 这里要注意一下不要超过sortingOrder的最大值32767,目前UI_MAX_ORDER + UI_INTERVAL_ORDER * LOADING_TOP:28000 + 400 * 7 = 30800 小于 32767
}

function UIManager:init(callback)
	if self.uiRoot and CS.BF.Utils.IsNull(self.uiRoot:getGameObject()) then
		return
	end
	self.uiList = {}
	self.loadingUI = {}
	self.uiCacheList = {}
	self.uiLoadedListeners = {}
	self.disableTouchCount = 0
	self.waitNetCount = 0
	UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/ui_root.prefab", nil, function(uiRoot)
		self.uiRoot = uiRoot
		CS.UnityEngine.GameObject.DontDestroyOnLoad(uiRoot:getGameObject())
		local uiMap = uiRoot:genAllChildren()
		self.uiCamera = uiMap["ui_root.ui_camera"]
		self.mainCanvas = uiMap["ui_root.main_canvas"]
		self.mainCanvas:getTransform().hierarchyCapacity = MAIN_CANVAS_HIERARCHY_CAPACITY

		self.currencyRoot = uiMap["ui_root.main_canvas.currency_root"]
		self:_loadCurrencyBar()
		self.currencyCanvas = self.currencyRoot:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS)

		self.swallowUITouches = uiMap["ui_root.main_canvas.swallow_ui_touches"]
		self.swallowUITouchesCanvas = self.swallowUITouches:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS)

		self.toastCanvas = uiMap["ui_root.toast_canvas"]
		self.toastCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.TOAST
		self.toastNode = uiMap["ui_root.toast_canvas.toast"]
		self.messageBoxNode = uiMap["ui_root.toast_canvas.messagebox"]

		self.netCanvas = uiMap["ui_root.net_canvas"]
		local netCanvasOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.NET
		self.netCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = netCanvasOrder
		self.netCanvas:setActive(false)

		self.tutorialCanvas = uiMap["ui_root.tutorial_canvas"]
		self.tutorialCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.TUTORIAL

		self.loadingCanvas = uiMap["ui_root.loading_canvas"]
		self.blackLoadingImg = uiMap["ui_root.loading_canvas.black"]
		self.swallowTouchesCanvas = uiMap["ui_root.swallow_touches_canvas"]

		self.swallowTouchesCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false
		self.swallowTouchesCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.SWALLOW_TOUCH

		-- ui预制件pool节点
		self.uiPrefabPoolNode = uiMap["ui_root.ui_prefab_pool"]

		callback()
	end)
end

function UIManager:showUI(uiPath, params)
	if self.uiRoot == nil then
		return
	end
	local uiObj = self:checkOpen(uiPath)
	if uiObj then
		return uiObj
	end
	uiObj = require(uiPath):create(params)
	uiObj:setUIIndex(uiPath)
	uiObj:_recordParams(params)
	local topUISiblingIndex
	local topUI = self.uiList[#self.uiList]
	if topUI then
		topUISiblingIndex = topUI:getSiblingIndex() + 1
		topUI:_onCover()
	else
		topUISiblingIndex = 1
	end
	table.insert(self.uiList, uiObj)

	self:setUIOrder(uiObj, topUISiblingIndex)

	local aniType = self:getAniType(uiObj)
	if aniType then
		self:_setUISwallowOrder(topUISiblingIndex + 1)
		self.swallowUITouches:getGameObject():SetActive(true)
	else
		self:_updateUISwallowOrder()
	end

	uiObj:_onCreate()
	local bgm = uiObj:getBGMId()
	if bgm then
		self:playBGM(bgm)
	end
	Logger.logHighlight("Show UI:%s", uiPath)
	-- 上报打开界面事件
	BIReport:postOpenUI(uiObj:getPrefabPath())
	return uiObj
end

function UIManager:closeUI(uiObj)
	local uiNum = #self.uiList
	local removeIndex = 0
	for i = uiNum, 1, -1 do
		if uiObj == self.uiList[i] then
			removeIndex = i
			break
		end
	end
	if removeIndex <= 0 then
		Logger.log(uiObj:getUIIndex(), " is not open")
		return
	end

	if removeIndex == uiNum then -- 需要关闭的界面在最上层
		uiNum = uiNum - 1
		if uiNum > 0 then
			local topUI = self.uiList[uiNum]
			topUI:_onReshow()

			local aniType = self:getAniType(uiObj)
			if aniType and aniType ~= UIManager.ANI_TYPE.POP and
					aniType ~= UIManager.ANI_TYPE.NONE then
				if removeIndex > 0 then
					table.remove(self.uiList, removeIndex)
				end
				self:_setUISwallowOrder(uiObj:getSiblingIndex() + 1)
				self.swallowUITouches:getGameObject():SetActive(true)
				uiObj:_playExitAnimation()
			else
				if removeIndex > 0 then
					table.remove(self.uiList, removeIndex)
				end
				uiObj:_onExitAnimationComplete()
				self:_updateUISwallowOrder()
			end

			local bgm = topUI:getBGMId()
			if bgm then
				self:playBGM(bgm)
			elseif uiObj:getBGMId() then
				local openedUINum = uiNum
				while openedUINum > 1 do
					openedUINum = openedUINum - 1
					bgm = self.uiList[openedUINum]:getBGMId()
					if bgm then
						self:playBGM(bgm)
						break
					end
				end
			end
		else
			uiObj:_onExitAnimationComplete()
		end
	else
		if removeIndex > 0 then
			table.remove(self.uiList, removeIndex)
		end
		uiObj:_onExitAnimationComplete()
		if uiObj:isFullScreen() and uiObj:isVisible() then
			local curIndex = removeIndex - 1
			local currObj = nil
			while curIndex >= 1 do
				currObj = self.uiList[curIndex]
				currObj:_setVisible(true)
				self:setBarsVisible(currObj, true)
				if currObj:isFullScreen() then
					break
				end
				curIndex = curIndex - 1
			end
		end
	end

	uiObj:_onClose()
end

function UIManager:checkOpen(uiPath)
	local uiNum = #self.uiList
	if uiNum > 0 then
		for i = uiNum, 1, -1 do
			if self.uiList[i]:getUIIndex() == uiPath then
				-- 如果这个界面可以打开多个
				if self.uiList[i]:getUIType() == UIManager.UI_TYPE.MULTI then
					return nil
				end
				if i < uiNum then -- 如果这个界面已经打开，并且不是最顶层
					local reshowUI
					if self.uiList[i]:getUIType() == UIManager.UI_TYPE.MAIN then
						-- 关闭此界面之上所有界面
						for j = uiNum, i + 1, -1 do
							local closeUIObj = table.remove(self.uiList, j)
							closeUIObj:_onClose()
							closeUIObj:_onExitAnimationComplete()
						end
						reshowUI = self.uiList[i]
					else
						-- 将此界面放到所有界面的最顶层
						local topUI = self.uiList[uiNum]
						local siblingIndex = topUI:getSiblingIndex() + 1
						topUI:_onCover()
						reshowUI = table.remove(self.uiList, i)
						table.insert(self.uiList, reshowUI)
						self:setUIOrder(reshowUI, siblingIndex)
					end
					self:_updateUISwallowOrder()
					reshowUI:_onReshow()

					local bgm = reshowUI:getBGMId()
					if bgm then
						self:playBGM(bgm)
					end
                    return reshowUI
                end
				return self.uiList[i]
			end
		end
	end
	return nil
end

function UIManager:getUIPrefab(path, callback)
	for k, prefabObj in ipairs(self.uiCacheList) do
		if prefabObj:getAssetPath() == path then
			prefabObj:setParent(self.mainCanvas, false)
			table.remove(self.uiCacheList, k)
			return callback(prefabObj)
		end
	end
	UIPrefabManager:loadUIWidgetAsync(path, self.mainCanvas, callback)
end

function UIManager:clearUIPrefabCache()
	for i = 1,#self.uiCacheList do
		table.remove(self.uiCacheList):destroy()
	end
end

function UIManager:putbackUIPrefab(prefabObj)
	prefabObj:setParent(self.uiPrefabPoolNode, false)
	if #self.uiCacheList >= UI_CACHE_SIZE then	-- 缓存的ui prefab已经超上限了
		local head = table.remove(self.uiCacheList, 1)
		head:destroy()
	end
	table.insert(self.uiCacheList, prefabObj)
end

function UIManager:setUIOrder(uiObj, siblingIndex)
	local order = MAIN_CANVAS_ORDER + siblingIndex * UI_INTERVAL_ORDER
	if order < UI_MAX_ORDER then
		uiObj:setUIOrder(siblingIndex, order)
	else -- 超过最大值了,全部界面重新设置一下order
		for i, obj in ipairs(self.uiList) do
			order = MAIN_CANVAS_ORDER + i * UI_INTERVAL_ORDER
			obj:setUIOrder(i, order)
		end
		if self.currencyBarBindUI then
			local sortingOrder = self.currencyBarBindUI:getUIOrder()
			self.currencyCanvas.sortingOrder = sortingOrder + UI_INTERVAL_ORDER - UI_BARS_UNDER_ORDER
		end
		self:_updateUISwallowOrder()
	end
end

function UIManager:setBarsVisible(uiObj, visible)
	if self.currencyBarBindUI == uiObj then
		if self.currencyBar then
			self.currencyBar:setVisible(visible)
		end
	end
end

function UIManager:updateBarsState(uiObj)
	if self.currencyBarBindUI == uiObj then
		self:showCurrencyBar(uiObj)
	end
end

function UIManager:hideBehindUI(uiObj)
	local findIndex = 0
	for i = #self.uiList, 1, -1 do
		if uiObj == self.uiList[i] then
			findIndex = i
			break
		end
	end
	local curIndex = findIndex - 1
	local currObj = nil
	while curIndex >= 1 do
		currObj = self.uiList[curIndex]
		if currObj:isVisible() == false then
			break
		end
		currObj:_setVisible(false)
		self:setBarsVisible(currObj, false)
		curIndex = curIndex - 1
	end
end

function UIManager:showBehindUI(uiObj)
	local findIndex = 0
	for i = #self.uiList, 1, -1 do
		if uiObj == self.uiList[i] then
			findIndex = i
			break
		end
	end
	local curIndex = findIndex - 1
	local currObj = nil
	while curIndex >= 1 do
		currObj = self.uiList[curIndex]
		currObj:_setVisible(true)
		self:setBarsVisible(currObj, true)
		if currObj:isFullScreen() then
			break
		end
		curIndex = curIndex - 1
	end
end

function UIManager:getUIByIndex(index)
	for k, v in ipairs(self.uiList) do
		if v:getUIIndex() == index then
			return v
		end
	end
	return nil
end

-- 获取引导UI
function UIManager:getTutorial(callback)
	if self.tutorial == nil then
		UIPrefabManager:loadUIWidgetAsync(TUTORIAL_PATH, self.tutorialCanvas, function (prefabObject)
			if self.tutorial then
				prefabObject:destroy()
				return
			end
			self.tutorial = prefabObject
			if callback then
				callback(prefabObject)
			end
		end)
	else
		self.tutorial:setActive(true)
		if callback then
			callback(self.tutorial)
		end
	end
end

-- 显示引导节点
function UIManager:showTutorial()
	self.tutorialCanvas:setActive(true)
end

-- 隐藏引导节点
function UIManager:hideTutorial()
	self.tutorialCanvas:setActive(false)
end

function UIManager:getBlackLoadingImg()
	return self.blackLoadingImg
end

function UIManager:showLoading(loadingType, callback)
	self:disableTouch()
	self.loadingCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = true
	self.loadingCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.LOADING
	loadingType = loadingType or UIManager.LOADING_TYPE.BLACK
	if self.currLoadingType == nil then
		self.currLoadingType = loadingType
	end
	ModuleManager.LoadingManager:showLoading(loadingType, self.loadingCanvas, callback)
end

function UIManager:closeLoading(callback)
	if self.currLoadingType == nil then
		self.loadingCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false
		if callback then
			callback()
		end
		return false
	end
	ModuleManager.LoadingManager:closeLoading(self.currLoadingType, function ()
		self:onLoadingUICompletelyClosed()
		if callback then
			callback()
		end
	end)
	self.currLoadingType = nil
	return true
end

function UIManager:onLoadingUICompletelyClosed()
	self:enableTouch()
	self.loadingCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false
end

function UIManager:closeAllUI()
	local uiNum = #self.uiList
	for i = uiNum, 1, -1 do
		self.uiList[i]:_onClose()
		self.uiList[i]:_onExitAnimationComplete()
	end
	self.uiList = {}
	self.currencyBarBindUI = nil
	if self.currencyBar then
		self.currencyBar:setVisible(false)
	end
end

function UIManager:closeAllUIExceptMainUI(includeCurrencyBar)
	local uiNum = #self.uiList
	for i = uiNum, 1, -1 do
		if self.uiList[i]:getUIIndex() ~= UIManager.UI_PATH.MAINCITY_UI then
			self.uiList[i]:closeUI()
		end
		self:_updateUISwallowOrder()
	end
	if includeCurrencyBar and self.currencyBar then
		self.currencyBarBindUI = nil
		self.currencyBar:setVisible(false)
	end
end

function UIManager:hideMainUIExceptBattle()
	local uiObj = UIManager:getUIByIndex(UIManager.UI_PATH.MAINCITY_UI)
	if uiObj and uiObj:getIsLoadedComplete() then
		uiObj:hideMainUIExceptBattle()
	end
end

function UIManager:showMainUIExceptBattle()
	local uiObj = UIManager:getUIByIndex(UIManager.UI_PATH.MAINCITY_UI)
	if uiObj and uiObj:getIsLoadedComplete() then
		uiObj:showMainUIExceptBattle()
	end
end

-- 测试专用,有隐患,正常逻辑不要直接使用
function UIManager:reshowAllUI()
	if DEBUG and EDITOR_MODE then
		local reshowList = {}
		for k, v in ipairs(self.uiList) do
			reshowList[k] = v
		end
		self:closeAllUI()
		for i = 1, #reshowList do
			local params = reshowList[i]:_getRecordParams()
			if params and type(params) == "table" then
				params.aniType = nil
			end
			self:showUI(reshowList[i]:getUIIndex(), params)
		end
	end
end

function UIManager:closeBehindUI(uiObj)
	local closeFlag = false
	for i = #self.uiList, 1, -1 do
		local curUIObj = self.uiList[i]
		if closeFlag then
			table.remove(self.uiList, i)
			curUIObj:_onClose()
			curUIObj:_onExitAnimationComplete()
		else
			if curUIObj == uiObj then
				closeFlag = true
			end
		end
	end
	if closeFlag then
		self:_updateUISwallowOrder()
	end
end

function UIManager:closeUnderUI(uiObj)
	local closeFlag = false
	for i = 1, #self.uiList do
		local curUIObj = self.uiList[i]
		if curUIObj == uiObj then
			for j = #self.uiList, i + 1, -1 do
				curUIObj = self.uiList[j]
				table.remove(self.uiList, j)
				curUIObj:_onClose()
				curUIObj:_onExitAnimationComplete()
				closeFlag = true
			end
			break
		end
	end

	if closeFlag then
		uiObj:_onReshow()
		self:_updateUISwallowOrder()
	end
end

function UIManager:onUILoadedComplete(uiObj)
	local callback = self.uiLoadedListeners[uiObj:getUIIndex()]
	if callback then
		self.uiLoadedListeners[uiObj:getUIIndex()] = nil
		callback()
	end
end

function UIManager:onUIClosedComplete(uiObj)
	self:updateBarsWhenCloseUI(uiObj)
	if self.uiLoadedListeners[uiObj:getUIIndex()] then
		self.uiLoadedListeners[uiObj:getUIIndex()] = nil
	end
end

function UIManager:addLoadUICompleteListener(uiIndex, callback)
	local uiObj = self:getUIByIndex(uiIndex)
	if uiObj and uiObj._baseLoadComplete then
		callback()
	else
		self.uiLoadedListeners[uiIndex] = callback
	end
end

function UIManager:getMessageBox(top, callback)
	if top then
		if self.topMsgBox == nil then
			UIPrefabManager:loadUIWidgetAsync(MESSAGE_BOX_PATH, self.messageBoxNode, function (prefabObject)
				if self.topMsgBox then
					prefabObject:destroy()
					callback(self.topMsgBox)
					return
				end
				prefabObject:initPrefabHelper()
				prefabObject:getTransform():SetAsLastSibling()

				local messageBoxCanvas = prefabObject:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS)
				local messageBoxCanvasOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.MESSAGE_BOX_TOP
				messageBoxCanvas.overrideSorting = true
				messageBoxCanvas.sortingOrder = messageBoxCanvasOrder
				self.topMsgBox = prefabObject
				callback(prefabObject)
			end)
		else
			self.topMsgBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = true
			callback(self.topMsgBox)
		end
	else
		if self.messageBox == nil then
			UIPrefabManager:loadUIWidgetAsync(MESSAGE_BOX_PATH, self.messageBoxNode, function (prefabObject)
				if self.messageBox then
					prefabObject:destroy()
					callback(self.messageBox)
					return
				end
				prefabObject:initPrefabHelper()
				self.messageBox = prefabObject
				callback(prefabObject)
			end)
		else
			self.messageBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = true
			callback(self.messageBox)
		end
	end
end

function UIManager:getMessageBoxGameObject(top)
	if top then
		return self.topMsgBox
	else
		return self.messageBox
	end
end

function UIManager:getMessageBoxCanvas()
	return self.messageBoxNode:getTransform()
end

function UIManager:hideMessageBox()
	if self.messageBox then
		self.messageBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false
	end
end

function UIManager:hideMessageBoxByTag(tag)
	if self.messageBox then
		if self.messageBox:getTag() == tag then
			self.messageBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false
		end
	end
	if self.topMsgBox then
		if self.topMsgBox:getTag() == tag then
			self.topMsgBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false
		end
	end
end

function UIManager:getToast(callback)
	if not self.toastPool then
		self.toastPool = {}
	end
	local toast
	for _, toastObj in ipairs(self.toastPool) do
		if not toastObj._using then
			toast = toastObj
		end
	end

	if toast == nil then
		UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/common/toast.prefab", self.toastNode, function (_prefabObject)
			_prefabObject:initPrefabHelper()
			table.insert(self.toastPool, _prefabObject)
			callback(_prefabObject)
		end)
	else
		callback(toast)
	end
end

function UIManager:getTaskToast(callback)
	if self.taskToast == nil then
		UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/common/task_toast.prefab", self.toastNode, function (_prefabObject)
			_prefabObject:initPrefabHelper()
			self.taskToast = _prefabObject
			callback(_prefabObject)
		end)
	else
		callback(self.taskToast)
	end
end

function UIManager:getAllToast()
	return self.toastPool
end

function UIManager:hideToast()
	if self.toastPool then
		ModuleManager.ToastManager:clear()
		for i, toastObj in ipairs(self.toastPool) do
			if toastObj._toastSequence then
				toastObj._toastSequence:Kill()
				toastObj._toastSequence = nil
			end
			toastObj._using = false
			toastObj:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false
		end
	end
	if self.taskToast then
		ModuleManager.ToastManager:clear()
	end
end

function UIManager:showUpdateToast(msgData)
	local ts = msgData.ts // 1000
	GFunc.showUpdateToast(ts - Time:getServerTime())
end

function UIManager:getRollToast(callback)
	if not self.rollToast then
		UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/common/roll_toast.prefab", self.toastNode, function (_prefabObject)
			if self.rollToast then
				_prefabObject:destroy()
				return
			end
			_prefabObject:initPrefabHelper()
			self.rollToast = _prefabObject
			callback(_prefabObject)
		end)
	else
		callback(self.rollToast)
	end
end

---- 回到登录界面时 killseq为true
function UIManager:hideRollToast(killSeq)
	if not self.rollToast then
		return
	end
	if killSeq and self.rollToast._toastSequence then
		self.rollToast._toastSequence:Kill()
		self.rollToast._toastSequence = nil
	end
	ModuleManager.RollToastManager:clear(not killSeq)
	self.rollToast:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false
end

function UIManager:hideToastAndMessageBox()
	self:hideToast()
	self:hideRollToast()
end

function UIManager:getMainCanvasTransform()
	return self.mainCanvas:getTransform()
end

function UIManager:getMainCanvas()
	return self.mainCanvas
end

function UIManager:getUICameraComponent()
	return self.uiCamera:getComponent(GConst.TYPEOF_UNITY_CLASS.CAMERA)
end

function UIManager:showWaitPay()
	if self.waitNetCount == 0 then
		if self.waitPaySeq == nil then
			local seq = DOTweenManager:createSeqWithIntId(GConst.DOTWEEN_IDS.WAIT_PAY)
			seq:SetAutoKill(false)
			seq:AppendInterval(1)
			seq:AppendCallback(function()
				self.netCanvas:setActive(true)
			end)
			self.waitPaySeq = seq
		elseif not self.waitPaySeq:IsPlaying() then
			self.waitPaySeq:Restart()
		end
	end
	self.waitNetCount = self.waitNetCount + 1
	self:disableTouch()
end

function UIManager:hideWaitPay()
	self:hideWaitNet()
	if self.waitNetCount <= 0 then
		if self.waitPaySeq then
			self.waitPaySeq:Pause()
		end
	end
end

function UIManager:showWaitNet(forceRestart)
	if self.waitNetCount == 0 or forceRestart then
		if self.waitNetSeq == nil then
			local seq = DOTweenManager:createSeqWithIntId(GConst.DOTWEEN_IDS.WAIT_NET)
			seq:SetAutoKill(false)
			seq:AppendInterval(1)
			seq:AppendCallback(function()
				self.netCanvas:setActive(true)
			end)
			seq:AppendInterval(GConst.WAIT_NET_RSP_TIME)
			seq:OnComplete(function()
				-- 一段时间后还没收到回复就断开连接
				NetManager:disconnectAndReconnect()
			end)
			self.waitNetSeq = seq
		elseif not self.waitNetSeq:IsPlaying() then
			self.waitNetSeq:Restart()
		end
	end
	self.waitNetCount = self.waitNetCount + 1
	self:disableTouch()
end

function UIManager:hideWaitNet(hideAll)
	if hideAll then
		local count = self.waitNetCount
		self.waitNetCount = 0
		if self.waitNetSeq then
			self.waitNetSeq:Pause()
		end
		self.netCanvas:setActive(false)
		for i = 1, count do
			self:enableTouch()
		end
	else
		if self.waitNetCount > 0 then
			self:enableTouch()
		end
		self.waitNetCount = self.waitNetCount - 1
		if self.waitNetCount <= 0 then
			self.waitNetCount = 0
			if self.waitNetSeq then
				self.waitNetSeq:Pause()
			end
			self.netCanvas:setActive(false)
		end
	end
end

function UIManager:getWaitNetCount()
	return self.waitNetCount
end

function UIManager:disableTouch()
	if self.disableTouchCount == 0 then
		self.swallowTouchesCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = true
	end
	self.disableTouchCount = self.disableTouchCount + 1
	if self.disableTouchCount <= 0 then
		Logger.logError("UIManager:disableTouch count error:%d", self.disableTouchCount)
	end
end

function UIManager:enableTouch()
	self.disableTouchCount = self.disableTouchCount - 1
	if self.disableTouchCount <= 0 then
		self.swallowTouchesCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false
	end
end

function UIManager:_updateUISwallowOrder()
	local topSwallowTouchIndex = 0
	for i = #self.uiList, 1, -1 do
		if self.uiList[i]:swallowTouchBetweenUI() then
			topSwallowTouchIndex = self.uiList[i]:getSiblingIndex()
			self:_setUISwallowOrder(topSwallowTouchIndex)
			break
		end
	end
	self.swallowUITouches:getGameObject():SetActive(topSwallowTouchIndex > 0)
end

function UIManager:_setUISwallowOrder(siblingIndex)
	local order = MAIN_CANVAS_ORDER + siblingIndex * UI_INTERVAL_ORDER
	self.swallowUITouches:getTransform():SetSiblingIndex(siblingIndex - 1)
	self.swallowUITouchesCanvas.sortingOrder = order - 1
end

function UIManager:_getUpperUIObj(uiObj)
	local uiNum = #self.uiList
	for i = uiNum, 1, -1 do
		if self.uiList[i] == uiObj then
			return self.uiList[i - 1]
		end
	end
	return nil
end

function UIManager:getTopUIObj()
	local uiNum = #self.uiList
	return self.uiList[uiNum]
end

function UIManager:getTopUIIndex()
	if not self:getTopUIObj() then
		return
	end
	return self:getTopUIObj():getUIIndex()
end

function UIManager:getUIList()
	return self.uiList
end

function UIManager:getAniType(uiObj)
	local params = uiObj:_getRecordParams()
	if type(params) == "table" and params.aniType then
		return params.aniType
	end
	if not uiObj:isFullScreen() then
		return self.ANI_TYPE.POP
	end
	return nil
end

function UIManager:playBGM(id)
	if id ~= self.currBGMId then
		self.currBGMId = id
		AudioManager:playMusic(id, true)
	end
end

function UIManager:stopBGM(id)
	if id == self.currBGMId then
		self.currBGMId = nil
		AudioManager:stopMusicById(id, true)
	end
end

function UIManager:stopCurrentBGM()
	if self.currBGMId then
		AudioManager:stopMusicById(self.currBGMId, true)
		self.currBGMId = nil
	end
end

function UIManager:getCurrentBGM()
	return self.currBGMId
end

function UIManager:clear()
	if self.waitNetSeq then
		self.waitNetSeq:Kill()
		self.waitNetSeq = nil
	end
end

function UIManager:destroyUIRoot()
	if self.uiRoot then
		self.uiRoot:destroy()
		self.uiRoot = nil
	end
end

-- 显示刘海屏(模拟IphoneX)
function UIManager:showNotchScreen()
	if self.notchScreen then
		self.notchScreen:setActive(true)
	else
		-- 创建一个刘海屏
		local notchHeight = SafeAreaManager:getNotchScreenHeight()
		Logger.log("模拟刘海屏高度:%s", notchHeight)
		local notchScreen = CS.UnityEngine.GameObject("NotchScreen")
		notchScreen:AddComponent(GConst.TYPEOF_UNITY_CLASS.RECTTRANSFORM)
		self.notchScreen = BaseObject:create()
		self.notchScreen:initWithGameObject(notchScreen)
		self.notchScreen:getTransform():SetParent(self.toastCanvas:getTransform())
		self.notchScreen:getTransform().anchorMin = BF.Vector2(0, 1)
		self.notchScreen:getTransform().anchorMax = BF.Vector2(1, 1)
		self.notchScreen:getTransform().pivot = BF.Vector2(0.5, 1)
		self.notchScreen:setAnchoredPosition(0, 0)
		self.notchScreen:setSizeDelta(0, notchHeight)
		self.notchScreen:setLocalScale(1, 1, 1)
		local cacheLocalPos = self.notchScreen:getTransform().localPosition
		self.notchScreen:getTransform().localPosition = BF.Vector3(cacheLocalPos.x, cacheLocalPos.y, 0)
		local img = notchScreen:AddComponent(GConst.TYPEOF_UNITY_CLASS.UI_IMAGE)
		img.color = BF.Color(0, 0, 0, 0.5)
	end
end

function UIManager:backToLogin()
	self:stopCurrentBGM()
	SDKManager:logout()
	-- 清除引导
	ModuleManager.TutorialManager:stopTutorial()
	self:closeAllUI()
	ModuleManager.BattleManager:clearOnExitScene()
	Game:showLoginUI()
end

function UIManager:backToLoginWithoutLogout()
	self:hideMessageBox()
	self:stopCurrentBGM()
	ModuleManager.TutorialManager:stopTutorial()

	self:closeAllUI()
	ModuleManager.BattleManager:clearOnExitScene()
	Game:showLoginUI()
end

-- 掉线提示处理
function UIManager:showKickOut(msgData)
	local content
	local reason = NetManager:getKickOutReasonEnum(msgData.reason)
	if reason == 0 then -- 服务器维护
		content = I18N:getGlobalText(I18N.GlobalConst.MAINTAIN)
	elseif reason == 1 then	-- 网络消息流控，也就是短时间内通信次数太多
		content = I18N:getGlobalText(I18N.GlobalConst.DISCONNECT_RELOGIN)
	elseif reason == 2 then -- 封号
		content = I18N:getGlobalText(I18N.GlobalConst.FORBIDDEN)
	elseif reason == 3 then	-- 多点登录
		content = I18N:getGlobalText(I18N.GlobalConst.OTHER_LOGIN)
	else
		content = I18N:getGlobalText(I18N.GlobalConst.DISCONNECT_RELOGIN)
	end
	self.disconnectMsgBoxVisible = true
	-- 被踢了的话就先断开连接再弹确认框
	NetManager:closeAndClear()
	local params = {
		content = content,
		okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK),
		okFunc = function()
			self.disconnectMsgBoxVisible = false
		 	ModuleManager.LoginManager:goToLoginScene()
		end,
		boxType = GConst.MESSAGE_BOX_TYPE.MB_OK,
		top = true,
	}
	GFunc.showMessageBox(params)
end

-- 掉线提示处理
function UIManager:showDisconnect()
	self.disconnectMsgBoxVisible = true
	local params = {
		content = I18N:getGlobalText(I18N.GlobalConst.DISCONNECT_RELOGIN),
		okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK),
		okFunc = function()
			self.disconnectMsgBoxVisible = false
			ModuleManager.LoginManager:goToLoginScene()
		end,
		boxType = GConst.MESSAGE_BOX_TYPE.MB_OK,
		top = true,
	}
	GFunc.showMessageBox(params)
end

function UIManager:isDisconnectMsgBoxVisible()
	return self.disconnectMsgBoxVisible
end

function UIManager:_loadCurrencyBar(params, showBg, hidAddImg)
	if self.currencyBar == nil then
		UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/common/currency_bar.prefab", self.currencyRoot, function (_prefabObject)
			if self.currencyBar then
				_prefabObject:destroy()
			else
				self.currencyBar = _prefabObject:addLuaComponent(GConst.TYPEOF_LUA_CLASS.CURRENCY_BAR)
			end
			self.currencyBar:show(params, showBg, hidAddImg)
		end)
	end
end

function UIManager:showCurrencyBar(uiObj)
	local params, showBg, hidAddImg = uiObj:getCurrencyParams()
	if params then
		local currCurrencyBarOrder = 0
		if self.currencyBarBindUI then
			currCurrencyBarOrder = self.currencyBarBindUI:getUIOrder()
		end
		local sortingOrder = uiObj:getUIOrder()
		if sortingOrder >= currCurrencyBarOrder then
			self.currencyBarBindUI = uiObj
			-- 设置为比下一个界面的order低x点
			self.currencyCanvas.sortingOrder = sortingOrder + UI_INTERVAL_ORDER - UI_BARS_UNDER_ORDER
			if self.currencyBar == nil then
				self:_loadCurrencyBar(params, showBg, hidAddImg)
			else
				self.currencyBar:show(params, showBg, hidAddImg)
			end
			return true
		elseif sortingOrder == currCurrencyBarOrder then -- 同界面
			if self.currencyBar then
				self.currencyBar:show(params, showBg, hidAddImg)
			else
				-- self.currencyParam = params
				self:_loadCurrencyBar(params, showBg, hidAddImg)
			end
			return true
		end
	end
	return false
end

function UIManager:updateCurrentBattleType(battleType)
	local uiObj = UIManager:getUIByIndex(UIManager.UI_PATH.MAINCITY_UI)
	if uiObj and uiObj:getIsLoadedComplete() then
		uiObj:updateCurrentBattleType(battleType)
	end
end

function UIManager:updateBarsWhenCloseUI(uiObj)
	if self.currencyBarBindUI == uiObj then -- 关闭的是跟顶部货币栏有关联的ui
		self.currencyBarBindUI = nil
		local updateFlag = false
		for i = #self.uiList, 1, -1 do
			if self:showCurrencyBar(self.uiList[i]) then
				updateFlag = true
				break
			end
		end
		if not updateFlag then
			if self.currencyBar then
				self.currencyBar:setVisible(false)
			end
		end
	end
end

function UIManager:refreshCurrencyBar()
	if self.currencyBar then
		self.currencyBar:refreshTextRightNow()
	end
end

function UIManager:refreshCurrencyAddTx(itemId, num)
	local topUI = self.uiList[#self.uiList]
	if self.currencyBar and self.currencyBarBindUI == topUI then
		self.currencyBar:refreshCurrencyAddTx(itemId, num)
	end
end

function UIManager:showCurrencyAction(pos, imgNum)
	local topUI = self.uiList[#self.uiList]
	if self.currencyBar and self.currencyBarBindUI == topUI then
		self.currencyBar:showCurrencyAction(pos, imgNum)
	end
end

function UIManager:showChatBtn(isFirstEnter)
	if self.uiRoot then
		if self.chatBtn then
			self.chatBtn:getLuaComponent(GConst.TYPEOF_LUA_CLASS.CHAT_BTN_COMP):show(isFirstEnter)
		else
			if self.isShowChat ~= nil then
				return
			end
			self.isShowChat = true
			UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/chat/chat_btn.prefab", self.mainCanvas, function(prefab)
				self.chatBtn = prefab
				self.chatBtn:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).overrideSorting = true
				self.chatBtn:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER
				local comp = self.chatBtn:addLuaComponent(GConst.TYPEOF_LUA_CLASS.CHAT_BTN_COMP)
				if self.isShowChat then
					comp:show(isFirstEnter)
				else
					comp:hide()
				end
				self.isShowChat = nil
			end)
		end
	end
end

function UIManager:hideChatBtn()
	if self.uiRoot then
		if self.chatBtn then
			self.chatBtn:getLuaComponent(GConst.TYPEOF_LUA_CLASS.CHAT_BTN_COMP):hide()
		elseif self.isShowChat then
			self.isShowChat = false
		end
	end
end

-- 切换语言后刷新一些缓存的界面
function UIManager:refreshOnChangeLanguage()
	if self.currencyBar then
		self.currencyBar:refreshText()
	end
	local MessageBox = require "app/ui/common/message_box"
	if self.messageBox then
		MessageBox:refreshText(false)
	end
	if self.topMsgBox then
		MessageBox:refreshText(true)
	end
	ModuleManager.ToastManager:refreshText()
	ModuleManager.TaskToastManager:refreshText()
end

if EDITOR_MODE then
	UIManager._editorUpdateUISwallowOrder = UIManager._updateUISwallowOrder
    function UIManager:_updateUISwallowOrder()
		self:_editorUpdateUISwallowOrder()
		if self.mainCanvas:getTransform().hierarchyCapacity > MAIN_CANVAS_HIERARCHY_CAPACITY then
			Logger.logTodo("current main ui canvas hierarchyCount is:%d", self.mainCanvas:getTransform().hierarchyCapacity)
		end
    end
end

if NOT_PUBLISH then
	UIManager._releaseEnableTouch = UIManager.enableTouch
	function UIManager:enableTouch()
		if self._debugEnableTouchFuncMap == nil then
            self._debugEnableTouchFuncMap = {
                [SceneManager.onFinished] = true,
				[BaseUI.enableUITouch] = true,
				[BaseScene.enableTouch] = true,
				[UIManager.onLoadingUICompletelyClosed] = true,
				[UIManager.hideWaitNet] = true
            }
        end
		local currFunc = debug.getinfo(2, "f").func
        if self._debugEnableTouchFuncMap[currFunc] == nil then
            Logger.logFatal("you can not call UIManager:enableTouch directly")
        end
		self:_releaseEnableTouch()
	end

	UIManager._releaseDisableTouch = UIManager.disableTouch
	function UIManager:disableTouch()
		if self._debugDisableTouchFuncMap == nil then
            self._debugDisableTouchFuncMap = {
                [SceneManager.changeScene] = true,
				[BaseUI.disableUITouch] = true,
				[BaseScene.disableTouch] = true,
				[UIManager.showLoading] = true,
				[UIManager.showWaitNet] = true,
				[UIManager.showWaitPay] = true
            }
        end
		local currFunc = debug.getinfo(2, "f").func
        if self._debugDisableTouchFuncMap[currFunc] == nil then
            Logger.logFatal("you can not call UIManager:disableTouch directly")
        end
		self:_releaseDisableTouch()
	end
end

function UIManager:onPressAndroidBackspace()
	if self.uiRoot == nil then
		return
	end
	if self.disableTouchCount > 0 then
		return
	end
	if DataManager == nil then
		return
	end
	if DataManager.TutorialData:getIsInTutorial() then
		return
	end
	if DataManager.TutorialData:getIsFuncTutorial() then
		return
	end
	if self.topMsgBox and self.topMsgBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled then
		if self.topMsgBox._closeByAndroidBackspace then
			local MessageBox = require "app/ui/common/message_box"
			local uiMap = self.topMsgBox:genAllChildren()
			MessageBox:closeAndClear(self.topMsgBox, uiMap)
		end
		return
	end
	if self.messageBox and self.messageBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled then
		if self.messageBox._closeByAndroidBackspace then
			local MessageBox = require "app/ui/common/message_box"
			local uiMap = self.messageBox:genAllChildren()
			MessageBox:closeAndClear(self.messageBox, uiMap)
		end
		return
	end
	if #self.uiList <= 0 then
		return
	end
	local topUI = self.uiList[#self.uiList]
	if topUI:isClosed() then
		return
	end
	if topUI.root == nil then
		return
	end
	if topUI.root:isDestroyed() then
		return
	end
	if not topUI:isVisible() then
		return
	end
	if not topUI:getIsShowComplete() then
		return
	end
	topUI:onPressBackspace()
end

return UIManager