local CharacterObject = require "app/bf/unity/character_object"
local EffectObject = require "app/bf/unity/effect_object"
local BaseObject = require "app/bf/unity/base_object"
local ModelObject = class("ModelObject", BaseObject)

local BF_NODE_HELPER = GConst.TYPEOF_UNITY_CLASS.BF_NODE_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
}

local function _createModelChildObject(self, index, gameObject)
	local child = ModelObject:create()
	child:initWithModelHelper(self.modelHelper, index, gameObject)
	return child
end

local function _createCharacterChildObject(self, index, gameObject)
	local child = CharacterObject:create()
	child:initWithPrefab(nil, gameObject)
	return child
end

local function _createEffectChildObject(self, index, gameObject)
	local child = EffectObject:create()
	child:initWithPrefab(nil, gameObject)
	return child
end

ModelObject.createChildObject = {
	[GConst.GAME_OBJECT_TYPE.CHARACTER_OBJECT] = _createCharacterChildObject,
	[GConst.GAME_OBJECT_TYPE.EFFECT_OBJECT] = _createEffectChildObject,
}

function ModelObject:initWithPrefab(assetPath, prefab)
	BaseObject.initWithPrefab(self, assetPath, prefab)
	self.modelHelper = self:getComponent(BF_NODE_HELPER)
	if self.modelHelper == nil then
		self.modelHelper = self:addComponent(BF_NODE_HELPER)
	end
	self.objectIndex = -1
	self:_genAllChildren()
end

function ModelObject:initWithModelHelper(modelHelper, index, gameObject, name, admin)
	self.modelHelper = modelHelper
	self.objectIndex = index
	self.gameObject = gameObject
	self.name = name
	self.admin = admin
end

function ModelObject:_genAllChildren()
	local childMap = {}
	if self.modelHelper then
		local childNum = self.modelHelper:GetListCount()
		for i = 0, childNum do
			local gameObject = self.modelHelper:GetGameObjectByIndex(i)
			local hashName = self.modelHelper:GetHashNameByIndex(i)
			local objectType = self.modelHelper:GetObjectTypeByIndex(i)
			local func = self.createChildObject[objectType] or _createModelChildObject
			local child = func(self, i, gameObject)
			child:setName(hashName)
			child:setAdmin(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 ModelObject:getChildByName(name)
	return self.childMap[name]
end

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

function ModelObject:fastGetLocalEulerAngles()
	if self.modelHelper then
		self.modelHelper:CacheLocalEulerAngles(self.objectIndex)
		return self.modelHelper.PositionX, self.modelHelper.PositionY, self.modelHelper.PositionZ
	else
		local localEulerAngles = self:getTransform().localEulerAngles
		return localEulerAngles.x, localEulerAngles.y, localEulerAngles.z
	end
end

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

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

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

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

function ModelObject:onDestroy()
	BaseObject.onDestroy(self)
	self.modelHelper = nil
	self.childMap = nil
end

function ModelObject:setSpriteRenderRect(x, y)
	if not self.spriteRender then
		self.spriteRender = self:getComponent(GConst.TYPEOF_UNITY_CLASS.SPRITE_RENDERER)
	end
	if self.spriteRender then
		self.spriteRender.size = BF.Vector2(x, y)
	end
end

return ModelObject