local BaseObject = require "app/bf/unity/base_object"
local UISpineObject = class("SpineObject", BaseObject)

local BF_UI_TOUCH_EVENT = GConst.TYPEOF_UNITY_CLASS.BF_UI_TOUCH_EVENT
local TYPE_OF_SPINE_ASSET = GConst.TYPEOF_UNITY_CLASS.SKELETON_DATA_ASSET
local SPINE_ASSET_PATH = "assets/arts/spines/ui/%s/%s_skeletondata.asset"
local CHARACTERS_SPINE_ASSET_PATH = "assets/arts/spines/characters/%s/%s_skeletondata.asset"

function UISpineObject:ctor()
end

function UISpineObject:initSkeletonDataAsset(dataAsset)
	local skeletonGraphic = self:getSkeletonGraphic()
	skeletonGraphic.skeletonDataAsset = dataAsset
	skeletonGraphic:Initialize(false)
	skeletonGraphic.raycastTarget = false
end

function UISpineObject:refreshAssets(dataAsset)
	local skeletonGraphic = self:getSkeletonGraphic()
	skeletonGraphic.skeletonDataAsset = dataAsset
	skeletonGraphic:Initialize(true)
end

function UISpineObject:getSkeletonGraphic()
	if not self.skeletonGraphic then
		self.skeletonGraphic = self:getComponent(GConst.TYPEOF_UNITY_CLASS.SKELETON_GRAPHIC)
	end
	if not self.skeletonGraphic then
		Logger.logFatal("UISpineObject missing component CS.Spine.Unity.SkeletonGraphic!")
	end
	return self.skeletonGraphic
end

function UISpineObject:getAnimationState(forceRefresh)
	self:getSkeletonGraphic()
	if (not self.animationState and self.skeletonGraphic) or forceRefresh then
		self.animationState = self.skeletonGraphic.AnimationState
	end
	return self.animationState
end

function UISpineObject:playAnim(animName, loop, forceRefresh, forceGetSG)
	self:getAnimationState(forceGetSG)
	if self.animationState then
		local trackEntry = self.animationState:SetAnimation(0, animName, loop)
		if forceRefresh then
			self.skeletonGraphic:Update(0)
		end
		return trackEntry
	end
end

function UISpineObject:setSkin(skinName)
	self.skeletonGraphic.initialSkinName = skinName
	self.skeletonGraphic:Initialize(true)
	self:getAnimationState(true)
end

function UISpineObject:getAnimationKeyFrameTime(animName)
	if not self.animationKeyFrameTime then
		self.animationKeyFrameTime = {}
	end
	local timeList = self.animationKeyFrameTime[animName]
	if not timeList then
		timeList = {}
		self.animationKeyFrameTime[animName] = timeList
		if not self.uiSpineHelper then
			self.uiSpineHelper = self:getComponent(GConst.TYPEOF_UNITY_CLASS.BF_UI_SPINE_HELPER)
			if self.uiSpineHelper == nil then
				self.uiSpineHelper = self:addComponent(GConst.TYPEOF_UNITY_CLASS.BF_UI_SPINE_HELPER)
			end
		end
		local list = self.uiSpineHelper:GetAnimationKeyFrameTime(animName)
		local count = list.Count
		if count > 0 then
			for i = 1, count do
				table.insert(timeList, list[i - 1])
			end
		end
	end
	return timeList
end

function UISpineObject:clearAnimationKeyFrameTime()
	for aniName, _ in pairs(self.animationKeyFrameTime) do
		self.animationKeyFrameTime[aniName] = nil
	end
end

--未验证TODO
function UISpineObject:rePlayAnim(animName, loop, forceRefresh)
	self:getAnimationState()
	if self.animationState then
		self.animationState:SetEmptyAnimation(0, 1)
		local trackEntry = self.animationState:SetAnimation(0, animName, loop)
		if forceRefresh then
			self.skeletonGraphic:Update(0)
		end
		return trackEntry
	end
end

function UISpineObject:playAnimComplete(animName, loop, forceRefresh, complete, forceGetSG)
	local spineAnim = self:getAnimation(self:playAnim(animName, loop, forceRefresh, forceGetSG))
	local duration = spineAnim.Duration
	if self.playAnimCompleteSeq then
		self.playAnimCompleteSeq:Kill()
		self.playAnimCompleteSeq = nil
	end
	self.playAnimCompleteSeq = self:createBindTweenSequence()
	self.playAnimCompleteSeq:AppendInterval(duration)
	self.playAnimCompleteSeq:OnComplete(complete)
	return duration
end

function UISpineObject:findAnim(animName)
	self:getAnimationState()
	if self.animationState then
		return self.animationState.Data.SkeletonData:FindAnimation(animName)
	end
end

function UISpineObject:hasAnim(animName)
	return nil ~= self:findAnim(animName)
end

function UISpineObject:getAnimation(trackEntry)
	return trackEntry and trackEntry.Animation
end

function UISpineObject:getAnimSpeed()
	if self.skeletonGraphic then
		return self.skeletonGraphic.timeScale
	end
end

function UISpineObject:setTimeScale(timeScale)
	if self.skeletonGraphic then
		self.skeletonGraphic.timeScale = timeScale
	end
end

function UISpineObject:setIsFreeze(value)
	if self.skeletonGraphic then
		self.skeletonGraphic.freeze = value
	end
end

function UISpineObject:setIsUnScaledTime(value)
	if self.skeletonGraphic then
		self.skeletonGraphic.unscaledTime = value
	end
end

function UISpineObject:clearTrack()
	if self.animationState then
		self.animationState:ClearTrack(0)
	end
end

function UISpineObject:addClickListener(func)
	self._addTouchFlag = true
	local eventListener = self:getComponent(BF_UI_TOUCH_EVENT)
	if eventListener == nil then
		eventListener = self:addComponent(BF_UI_TOUCH_EVENT)
	end
	self._touchEventCallback = func
	eventListener:AddTouchEventListener(function(eventType, x, y)
		self:_onClickEvent(eventType, x, y)
	end)
end

function UISpineObject:_onClickEvent(eventType, x, y)
	if self._touchEventCallback and eventType == GConst.TOUCH_EVENT.UP_INSIDE then
		self._touchEventCallback(eventType, x, y)
	end
end

function UISpineObject:setTouchEnable(enable)
	local graphic = self:getSkeletonGraphic()
	graphic.raycastTarget = enable
end

function UISpineObject:getWidth()
	local graphic = self:getSkeletonGraphic()
	return graphic.SkeletonData.Width
end

function UISpineObject:getHeight()
	local graphic = self:getSkeletonGraphic()
	return graphic.SkeletonData.Height
end

function UISpineObject:setGrey(isGrey)
	local component = self:getSkeletonGraphic()
	GFunc.setGrey(component, isGrey)
end

function UISpineObject:loadAssetAsync(assetName, callback, useCharacterPath)
	local path
	if useCharacterPath then
		path = string.format(CHARACTERS_SPINE_ASSET_PATH, assetName, assetName)
	else
		path = string.format(SPINE_ASSET_PATH, assetName, assetName)
	end

	if self.curAssetPath == path and not self.loadingAsset then
		return callback and callback()
	end
	self:onLoadAsset()
	self.curAssetPath = path
	self.loadingAsset = true
	ResourceManager:loadOriginAssetAsync(path, TYPE_OF_SPINE_ASSET, function(spineAssetPath, spineAsset)
		self.loadingAsset = false
		if self:isDestroyed() then
			ResourceManager:unload(spineAssetPath)
			return
		end
		if self.curAssetPath ~= spineAssetPath then
			ResourceManager:unload(spineAssetPath)
			return
		end
		local skeletonGraphic = self:getSkeletonGraphic()
		skeletonGraphic.skeletonDataAsset = spineAsset
		skeletonGraphic:Initialize(true)
		if callback then
			callback()
		end
	end)
end

function UISpineObject:getIsLoadingAsset()
	return self.loadingAsset
end

function UISpineObject:onLoadAsset()
	if self.curAssetPath then
		ResourceManager:unload(self.curAssetPath)
		self.curAssetPath = nil
	end
	self:addUnloadCallback(function()
		if self.curAssetPath then
			ResourceManager:unload(self.curAssetPath)
			self.curAssetPath = nil
		end
	end)
end

function UISpineObject:addAnimationCompleteCallback(callback)
    if self._animationStateCompleteCallback then
        return
    end
    self._animationStateCompleteCallback = function(entry)
        callback(entry.Animation.Name)
    end
    local state = self:getAnimationState()
    if state then
	    state:Complete("+", self._animationStateCompleteCallback)
	end
end

function UISpineObject:removeAnimationCompleteCallback()
	if self._animationStateCompleteCallback then
        local state = self:getAnimationState()
        if state then
	        state:Complete("-", self._animationStateCompleteCallback)
	    end
        self._animationStateCompleteCallback = nil
    end
end

function UISpineObject:setTimeScale(timeScale)
	if self.skeletonGraphic then
		self.skeletonGraphic.timeScale = timeScale
	end
end

function UISpineObject:onDestroy()
	self:removeAnimationCompleteCallback()
	if self._addTouchFlag then
		self._touchEventCallback = nil
	end
	BaseObject.onDestroy(self)
	self.skeletonGraphic = nil
	self.animationState = nil
end

return UISpineObject