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

local BF_CHARACTER_SPINE_HELPER = GConst.TYPEOF_UNITY_CLASS.BF_CHARACTER_SPINE_HELPER

local hash = GFunc.hash
local CHILDMAP_METATABLE = {
	__index = function(t, k)
		if rawget(t, k) == nil then
			local v = rawget(t, hash(k))
			if v then
				rawset(t, k, v)
			end
			return v
		end
		return rawget(t, k)
	end
}

function CharacterSpineObject:ctor()
end

function CharacterSpineObject:getCharacterSpineHelper()
	return self.characterSpineHelper
end

function CharacterSpineObject:initWithPrefab(assetPath, modelId, prefab)
	BaseObject.initWithPrefab(self, assetPath, prefab)
	self.modelId = modelId
	self.characterSpineHelper = self:getComponent(BF_CHARACTER_SPINE_HELPER)
	if self.characterSpineHelper == nil then
		self.characterSpineHelper = self:addComponent(BF_CHARACTER_SPINE_HELPER)
	end
	self.mainSpine = self.characterSpineHelper:GetSpineObject()
	self.objectIndex = -1
	self:_genAllChildren()
end

function CharacterSpineObject:initWithCharacterHelper(characterSpineHelper, index, gameObject, name, admin)
    self.characterSpineHelper = characterSpineHelper
	self.objectIndex = index
	self.gameObject = gameObject
	self.name = name
	self.admin = admin
end

function CharacterSpineObject:refreshSkeletonDataAsset(dataAsset)
	local skeletonGraphic = self:getSkeletonGraphic()
	skeletonGraphic.skeletonDataAsset = dataAsset
	skeletonGraphic:Initialize(true)
	self.characterSpineHelper:Reload()
end

function CharacterSpineObject:setSkin(skinName)
	local skeletonGraphic = self:getSkeletonGraphic()
	skeletonGraphic.initialSkinName = skinName
	skeletonGraphic:Initialize(true)
	self.characterSpineHelper:Reload()
end

function CharacterSpineObject:_genAllChildren()
	local childMap = {}
	if self.characterSpineHelper then
		local childNum = self.characterSpineHelper:GetListCount()
		for i = 0, childNum do
			local gameObject = self.characterSpineHelper:GetGameObjectByIndex(i)
			local hashName = self.characterSpineHelper:GetHashNameByIndex(i)
			local child = CharacterSpineObject:create()
			child:initWithCharacterHelper(self.characterSpineHelper, i, gameObject, hashName, self)
			if childMap[hashName] == nil then
				childMap[hashName] = child
			end
			table.insert(self.childList, child)
		end
	end
	setmetatable(childMap, CHILDMAP_METATABLE)
	self.childMap = childMap
end

function CharacterSpineObject:getChildByName(name)
	return self.childMap[name]
end

function CharacterSpineObject:getMainSpine()
	return self.mainSpine
end

function CharacterSpineObject:getModelId()
	return self.modelId
end

function CharacterSpineObject:fastGetBonePosition(name)
	if self.characterSpineHelper then
		self.characterSpineHelper:CacheBonePosition(name)
		return self.characterSpineHelper.PositionX, self.characterSpineHelper.PositionY, self.characterSpineHelper.PositionZ
	end
end

function CharacterSpineObject:fastGetPosition()
	if self.characterSpineHelper then
		self.characterSpineHelper:CachePosition(self.objectIndex)
		return self.characterSpineHelper.PositionX, self.characterSpineHelper.PositionY, self.characterSpineHelper.PositionZ
	else
		local position = self:getTransform().position
		return position.x, position.y, position.z
	end
end

function CharacterSpineObject:setPosition(x, y, z)
	if self.characterSpineHelper then
		self.characterSpineHelper:SetPosition(self.objectIndex, x, y, z)
	else
		BaseObject.SetPosition(self, x, y, z)
	end
end

function CharacterSpineObject:fastGetLocalPosition()
	if self.characterSpineHelper then
		self.characterSpineHelper:CacheLocalPosition(self.objectIndex)
		return self.characterSpineHelper.PositionX, self.characterSpineHelper.PositionY, self.characterSpineHelper.PositionZ
	else
		local position = self:getTransform().localPosition
		return position.x, position.y, position.z
	end
end

function CharacterSpineObject:setLocalPosition(x, y, z)
	if self.characterSpineHelper then
		self.characterSpineHelper:SetLocalPosition(self.objectIndex, x, y, z)
	else
		BaseObject.SetLocalPosition(self, x, y, z)
	end
end

function CharacterSpineObject:setEulerAngles(x, y, z)
	if self.characterSpineHelper then
		self.characterSpineHelper:SetEulerAngles(self.objectIndex, x, y, z)
	else
		BaseObject.setEulerAngles(self, x, y, z)
	end
end

function CharacterSpineObject:setLocalEulerAngles(x, y, z)
	if self.characterSpineHelper then
		self.characterSpineHelper:SetLocalEulerAngles(self.objectIndex, x, y, z)
	else
		BaseObject.setLocalEulerAngles(self, x, y, z)
	end
end

function CharacterSpineObject:setLocalScale(x, y, z)
	if self.characterSpineHelper then
		self.characterSpineHelper:SetLocalScale(self.objectIndex, x, y, z)
	else
		BaseObject.setLocalScale(self, x, y, z)
	end
end

function CharacterSpineObject:setLocalScaleX(x)
	if self.characterSpineHelper then
		self.characterSpineHelper:SetLocalScaleX(self.objectIndex, x)
	else
		BaseObject.setLocalScaleX(self, x)
	end
end

function CharacterSpineObject:playAnimation(animName, loop, forceRefresh)
	if self.characterSpineHelper then
		self.characterSpineHelper:PlayAnimation(animName, loop, forceRefresh)
	end
end

function CharacterSpineObject:setDefaultMix(mixDuration)
	if self.characterSpineHelper then
		self.characterSpineHelper:SetDefaultMix(mixDuration)
	end
end

-- 战斗里面粒子特效和spine特效混用，统一调用的stop接口，这里先放一个空方法
function CharacterSpineObject:stop()
end

function CharacterSpineObject:setTimeScale(timeScale)
	self.timeScale = timeScale
	if self.characterSpineHelper then
		if self.localTimeScale then
			self.characterSpineHelper:SetAnimationSpeed(self.timeScale*self.localTimeScale)
		else
			self.characterSpineHelper:SetAnimationSpeed(self.timeScale)
		end
	end
end

function CharacterSpineObject:setLocalTimeScale(localTimeScale)
	self.localTimeScale = localTimeScale
	self:setTimeScale(self.timeScale or 1)
end

function CharacterSpineObject:setLoop(isLoop)
	if self.characterSpineHelper then
    	self.characterSpineHelper:SetLoop(isLoop)
	end
end

function CharacterSpineObject:getAnimationDuration(animationName)
	if self.characterSpineHelper then
    	return self.characterSpineHelper:GetAnimationDuration(animationName)
	end
	return 0
end

function CharacterSpineObject:getAnimationKeyFrameTimes(animationName)
	local times = {}
	if self.characterSpineHelper then
		local timeList = self.characterSpineHelper:GetAnimationKeyFrameTime(animationName)
		local count = timeList.Count
		if count > 0 then
			for i = 1, count do
				table.insert(times, timeList[i - 1])
			end
		end
	end
	return times
end

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

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

function CharacterSpineObject:getSkeletonGraphic()
	if self.skeletonGraphic == nil then
		self.skeletonGraphic = self.characterSpineHelper:GetSkeletonGraphic()
	end
	return self.skeletonGraphic
end


function CharacterSpineObject:getInstanceID()
	if self.characterSpineHelper then
		return self.characterSpineHelper:GetInstanceID(self.objectIndex)
	end
	return BaseObject.getInstanceID(self)
end

function CharacterSpineObject:setBattleScheduleId(id)
	self.battleScheduleId = id
end

function CharacterSpineObject:getBattleScheduleId()
	return self.battleScheduleId
end

function CharacterSpineObject:onDestroy()
    self:removeAnimationCompleteCallback()
    BaseObject.onDestroy(self)
    self.animationState = nil
end

return CharacterSpineObject