local BaseObject = class("GameObject")

local Vector2 = BF.Vector2(0, 0)
local Vector3 = BF.Vector3(0, 0, 0)

function BaseObject:ctor()
	self.components = {}
	self.childList = {}
end

function BaseObject:initWithPrefab(assetPath, prefab)
	self.assetPath = assetPath
	self.gameObject = prefab
end

function BaseObject:initWithGameObject(gameObject)
	self.gameObject = gameObject
end

function BaseObject:getAssetPath()
	return self.assetPath
end

function BaseObject:setCustomData(name, value)
	if self.customData == nil then
		self.customData = {}
	end
	self.customData[name] = value
end

function BaseObject:getCustomData(name)
	if self.customData == nil then
		return nil
	end
	return self.customData[name]
end

function BaseObject:dontDestroyOnLoad()
	CS.UnityEngine.GameObject.DontDestroyOnLoad(self:getGameObject())
end

function BaseObject:getGameObject()
	return self.gameObject
end

function BaseObject:getTransform()
	if self.transform == nil then
		local gameObject = self:getGameObject()
		if gameObject then
			self.transform = gameObject.transform
		end
	end
	return self.transform
end

function BaseObject:getInstanceID()
	local gameObject = self:getGameObject()
	if gameObject then
		return gameObject:GetInstanceID()
	end
	return 0
end

function BaseObject:addLuaComponent(componentType, params)
	local comp = self.components[componentType]
	if comp == nil then
		comp = require(componentType):create(params)
		comp:_init(self)
		self.components[componentType] = comp
	end
	return comp
end

function BaseObject:removeLuaComponent(componentType)
	self.components[componentType] = nil
end

function BaseObject:getLuaComponent(componentType)
	if self.components[componentType] == nil then
		local comp = require(componentType):create()
		comp:_init(self)
		self.components[componentType] = comp
	end
	return self.components[componentType]
end

function BaseObject:addComponent(componentType)
	if self.components[componentType] == nil then
		local gameObject = self:getGameObject()
		if gameObject then
			self.components[componentType] = gameObject:AddComponent(componentType)
		end
	end
	return self.components[componentType]
end

function BaseObject:getComponent(componentType)
	if self.components[componentType] == nil then
		local gameObject = self:getGameObject()
		if gameObject then
			local com = gameObject:BFGetComponent(componentType)
			self.components[componentType] = com
		end
	end
	return self.components[componentType]
end

function BaseObject:getAllComponents()
	return self.components
end

function BaseObject:getActiveSelf()
	local gameObject = self:getGameObject()
	return gameObject.activeSelf
end

function BaseObject:setActive(active)
	local gameObject = self:getGameObject()
	if gameObject then
		gameObject:SetActive(active)
	end
end

function BaseObject:setName(name)
	self.name = name
end

function BaseObject:getName()
	return self.name or ""
end

function BaseObject:setScrollRectCellName(nameIndex)
	local gameObject = self:getGameObject()
	if gameObject then
		gameObject.name = tostring(nameIndex)
	end
end

function BaseObject:setTag(tag)
	self.tag = tag
end

function BaseObject:getTag()
	return self.tag
end

function BaseObject:setLayer(layer)
	local trans = self:getTransform():GetComponentsInChildren(GConst.TYPEOF_UNITY_CLASS.TRANSFORM, true)
	if trans then
		local len = trans.Length
		for i = 0, len - 1 do
			trans[i].gameObject.layer = layer
		end
	end
end

function BaseObject:getAnchoredPosition()
	local transform = self:getTransform()
	return transform.anchoredPosition
end

function BaseObject:getAnchoredPositionX()
	local transform = self:getTransform()
	return transform.anchoredPosition.x
end

function BaseObject:getAnchoredPositionY()
	local transform = self:getTransform()
	return transform.anchoredPosition.y
end

function BaseObject:setAnchoredPositionX(x)
	local transform = self:getTransform()
	Vector2.x = x
	Vector2.y = transform.anchoredPosition.y
	transform.anchoredPosition = Vector2
end

function BaseObject:setAnchoredPositionY(y)
	local transform = self:getTransform()
	Vector2.x = transform.anchoredPosition.x
	Vector2.y = y
	transform.anchoredPosition = Vector2
end

function BaseObject:setAnchoredPosition(x, y)
	local transform = self:getTransform()
	Vector2.x = x
	Vector2.y = y
	transform.anchoredPosition = Vector2
end

function BaseObject:addAnchoredPosition(x, y)
	local transform = self:getTransform()
	local anchoredPosition = transform.anchoredPosition
	Vector2.x = x + anchoredPosition.x
	Vector2.y = y + anchoredPosition.y
	transform.anchoredPosition = Vector2
end

function BaseObject:getRectSize()
	local transform = self:getTransform()
	return transform.rect
end

function BaseObject:getSizeDeltaY()
	local transform = self:getTransform()
	return transform.sizeDelta.y
end

function BaseObject:getSizeDeltaX()
	local transform = self:getTransform()
	return transform.sizeDelta.x
end

function BaseObject:setSizeDeltaX(x)
	local transform = self:getTransform()
	Vector2.x = x
	Vector2.y = transform.sizeDelta.y
	transform.sizeDelta = Vector2
end

function BaseObject:setSizeDeltaY(y)
	local transform = self:getTransform()
	Vector2.x = transform.sizeDelta.x
	Vector2.y = y
	transform.sizeDelta = Vector2
end

function BaseObject:setSizeDelta(x, y)
	local transform = self:getTransform()
	Vector2.x = x
	Vector2.y = y
	transform.sizeDelta = Vector2
end

function BaseObject:addSizeDelta(x, y)
	local transform = self:getTransform()
	local sizeDelta = transform.sizeDelta
	Vector2.x = x + sizeDelta.x
	Vector2.y = y + sizeDelta.y
	transform.sizeDelta = Vector2
end

function BaseObject:setPosition(x, y, z)
	local transform = self:getTransform()
	Vector3.x = x
	Vector3.y = y
	Vector3.z = z
	transform.position = Vector3
end

function BaseObject:addPosition(x, y, z)
	local transform = self:getTransform()
	local position = transform.position
	Vector3.x = x + position.x
	Vector3.y = y + position.y
	Vector3.z = z + position.z
	transform.position = Vector3
end

function BaseObject:getPosition()
	local transform = self:getTransform()
	return transform.position
end

function BaseObject:getLocalPosition()
	local transform = self:getTransform()
	return transform.localPosition
end

function BaseObject:setLocalPosition(x, y, z)
	local transform = self:getTransform()
	Vector3.x = x
	Vector3.y = y
	Vector3.z = z
	transform.localPosition = Vector3
end

function BaseObject:setLocalPositionX(x)
	local transform = self:getTransform()
	local localPosition = transform.localPosition
	Vector3.x = x
	Vector3.y = localPosition.y
	Vector3.z = localPosition.z
	transform.localPosition = Vector3
end

function BaseObject:setLocalPositionY(y)
	local transform = self:getTransform()
	local localPosition = transform.localPosition
	Vector3.x = localPosition.x
	Vector3.y = y
	Vector3.z = localPosition.z
	transform.localPosition = Vector3
end

function BaseObject:setLocalPositionZ(z)
	local transform = self:getTransform()
	local localPosition = transform.localPosition
	Vector3.x = localPosition.x
	Vector3.y = localPosition.y
	Vector3.z = z
	transform.localPosition = Vector3
end

function BaseObject:addLocalPosition(x, y, z)
	local transform = self:getTransform()
	local localPosition = transform.localPosition
	Vector3.x = x + localPosition.x
	Vector3.y = y + localPosition.y
	Vector3.z = z + localPosition.z
	transform.localPosition = Vector3
end

function BaseObject:setVisible(visible, scale)
	local transform = self:getTransform()
	if visible then
		Vector3.x = scale or 1
		Vector3.y = scale or 1
		Vector3.z = scale or 1
	else
		Vector3.x = 0
		Vector3.y = 0
		Vector3.z = 0
	end
	transform.localScale = Vector3
end

function BaseObject:setLocalScale(x, y, z)
	local transform = self:getTransform()
	Vector3.x = x
	Vector3.y = y
	Vector3.z = z
	transform.localScale = Vector3
end

function BaseObject:setLocalScaleX(x)
	local transform = self:getTransform()
	local currScale = transform.localScale
	Vector3.x = x
	Vector3.y = currScale.y
	Vector3.z = currScale.z
	transform.localScale = Vector3
end

function BaseObject:addLocalScale(x, y, z)
	local transform = self:getTransform()
	local localScale = transform.localScale
	Vector3.x = x + localScale.x
	Vector3.y = y + localScale.y
	Vector3.z = z + localScale.z
	transform.localScale = Vector3
end

function BaseObject:setLocalRotation(x, y, z)
	local transform = self:getTransform()
	Vector3.x = x
	Vector3.y = y
	Vector3.z = z
	transform.localRotation = Vector3
end

function BaseObject:setEulerAngles(x, y, z)
	local transform = self:getTransform()
	Vector3.x = x
	Vector3.y = y
	Vector3.z = z
	transform.eulerAngles = Vector3
end

function BaseObject:addEulerAngles(x, y, z)
	local transform = self:getTransform()
	local eulerAngles = transform.eulerAngles
	Vector3.x = x + eulerAngles.x
	Vector3.y = y + eulerAngles.y
	Vector3.z = z + eulerAngles.z
	transform.eulerAngles = Vector3
end

function BaseObject:setLocalEulerAngles(x, y, z)
	local transform = self:getTransform()
	Vector3.x = x
	Vector3.y = y
	Vector3.z = z
	transform.localEulerAngles = Vector3
end

function BaseObject:addLocalEulerAngles(x, y, z)
	local transform = self:getTransform()
	local localEulerAngles = transform.localEulerAngles
	Vector3.x = x + localEulerAngles.x
	Vector3.y = y + localEulerAngles.y
	Vector3.z = z + localEulerAngles.z
	transform.localEulerAngles = Vector3
end

function BaseObject:getAdmin()
	return self.admin
end

-- admin可能是parent也可能不是
function BaseObject:setAdmin(admin)
	self.admin = admin
end

function BaseObject:removeAllChildren()
	if self.childList then
		local count = #self.childList
		for i = 1, count do
			local child = table.remove(self.childList)
			child:setAdmin(nil)
			child:destroy()
		end
	end
end

function BaseObject:removeChild(child)
	if self.childList then
		for k, v in ipairs(self.childList) do
			if v == child then
				table.remove(self.childList, k)
				break
			end
		end
	end
end

function BaseObject:getChildList()
	return self.childList
end

function BaseObject:getFirstChild()
	return self.childList[1]
end

function BaseObject:setParent(parent, worldPositionStays)
	if self.admin then
		self.admin:removeChild(self)
	end
	local transform = self:getTransform()
	local parentTransform = parent and parent:getTransform() or nil
	transform:SetParent(parentTransform, worldPositionStays)
	if parent then
		parent:addChildList(self)
	else
		self.admin = nil
	end
end

function BaseObject:removeFromParent(isNeedCleanUp)
	if isNeedCleanUp then
		self:destroy()
	else
		if self.admin then
			self.admin:removeChild(self)
			self.admin = nil
		end
		self:getTransform():SetParent(nil, false)
	end
end

function BaseObject:addChildList(child)
	child:setAdmin(self)
	table.insert(self.childList, child)
end

function BaseObject:addPrefab(prefab, worldPositionStays)
	prefab.transform:SetParent(self:getTransform(), worldPositionStays)
end

function BaseObject:scheduleGlobal(func, inter)
	local sid = SchedulerManager:scheduleGlobal(func, inter)
	if self._schedulerIds == nil then
		self._schedulerIds = {}
	end
	table.insert(self._schedulerIds, sid)
	return sid
end

function BaseObject:performWithDelayGlobal(func, delay)
	local sid = SchedulerManager:performWithDelayGlobal(func, delay)
	if self._schedulerIds == nil then
		self._schedulerIds = {}
	end
	table.insert(self._schedulerIds, sid)
	return sid
end

function BaseObject:unscheduleGlobal(sid)
	if self._schedulerIds == nil then
		return
	end
	for k, v in ipairs(self._schedulerIds) do
		if v == sid then
			table.remove(self._schedulerIds, k)
			break
		end
	end
	SchedulerManager:unscheduleGlobal(sid)
end

function BaseObject:createBindTweenSequence()
	local sequence = DOTweenManager:createSeqWithGameObject(self:getGameObject())
	return sequence
end

function BaseObject:doScale(endValue, duration, onComplete)
	DOTweenManager:doScale(self:getTransform(),endValue,duration,onComplete)
end

function BaseObject:addUnloadCallback(callback)
	self._unloadCallback = callback
end

function BaseObject:addOnDestroyCallback(callback)
	if not self._onDestroyCallbacks then
		self._onDestroyCallbacks = {}
	end
	table.insert(self._onDestroyCallbacks, callback)
end

function BaseObject:clearOnDestroyCallback()
	self._onDestroyCallbacks = nil
end

function BaseObject:isDestroyed()
	return self._destroy
end

function BaseObject:onDestroy()
	if self._destroy then
		return
	end
	self._destroy = true
	for k, child in ipairs(self.childList) do
		child:onDestroy()
	end
	if self._schedulerIds then
		for k, v in ipairs(self._schedulerIds) do
			SchedulerManager:unscheduleGlobal(v)
		end
		self._schedulerIds = nil
	end
	if self._unloadCallback then
		self._unloadCallback(self)
		self._unloadCallback = nil
	end
	if self._onDestroyCallbacks then
		for _, callback in ipairs(self._onDestroyCallbacks) do
			callback(self)
		end
		self._onDestroyCallbacks = nil
	end
	self.childList = nil
	for k, v in pairs(self.components) do
		self.components[k] = nil
	end
	self.admin = nil
	self.gameObject = nil
	self.transform = nil
end

function BaseObject:destroy()
	if self._destroy then
		return
	end
	if self.admin then
		self.admin:removeChild(self)
	end
	local gameObject = self.gameObject
	if gameObject and not CS.BF.Utils.IsNull(gameObject) then
		ResourceManager:destroyPrefab(gameObject)
	end
	self:onDestroy()
end

return BaseObject