local BaseData = class("BaseData")

function BaseData:ctor(...)
	self.data = {}
	self.data.__parent = self

	local innerData = nil
	innerData = {
		__index = function (t, key)
			return innerData[key]
		end,
		__newindex = function (t, key, value)
			local preValue = innerData[key]
			innerData[key] = value
			t.__parent:invoke(key, preValue, value)
		end
	}
	setmetatable(self.data, innerData)

	self.bindList = {}
	self.forceList = {}
	self._baseInvokeCount = 0
end

function BaseData:invoke(name, preValue, value)
	self._baseInvokeCount = self._baseInvokeCount + 1
	if (self.forceList[name] or preValue ~= value) or type(preValue) == "table" then
		self.forceList[name] = nil
		if self.bindList[name] then
			for _, info in ipairs(self.bindList[name]) do
				info.bindFunc(info.binder, value)
			end
		end
	end
	self._baseInvokeCount = self._baseInvokeCount - 1
	if self._baseInvokeCount > 0 then -- 说明还在递归中
		return
	end
	if self._baseRemoveFlag then
		self._baseRemoveFlag = false
		if self._waitRemoveMap then
			for key, v in pairs(self._waitRemoveMap) do
				local list = self.bindList[key]
				if list then
					for i = #list, 1, -1 do
						if list[i] and list[i].waitRemove then
							table.remove(list, i)
						end
					end
				end
				self._waitRemoveMap[key] = nil
			end
		end
	end
end

function BaseData:bind(name, binder, bindFunc, immediately)
	if not self.bindList[name] then
		self.bindList[name] = {}
	end

	local unique = true
	for i, info in ipairs(self.bindList[name]) do
		if info and binder and info.binder == binder then
			self.bindList[name][i].bindFunc = bindFunc
			unique = false
			break
		end
	end

	if unique then
		table.insert(self.bindList[name], {binder = binder, bindFunc = bindFunc})
	end

	if immediately then
		self:invoke(name, nil, self.data[name])
	end
end

function BaseData:unBind(name, binder)
	if self.bindList[name] then
		for i, info in ipairs(self.bindList[name]) do
			if info.binder == binder then
				if self._baseInvokeCount > 0 then -- 正在invoke过程中
					info.waitRemove = true
					self._baseRemoveFlag = true
					if self._waitRemoveMap == nil then
						self._waitRemoveMap = {}
					end
					self._waitRemoveMap[name] = true
				else
					table.remove(self.bindList[name], i)
				end
				break
			end
		end
	end
end

function BaseData:setForceInvoke(name, value)
	self.forceList[name] = true
	self.data[name] = value
end

function BaseData:clearBind(name)
	if self.bindList[name] then
		self.bindList[name] = nil
	end
end

function BaseData:clearBindAll()
	self.bindList = {}
end

function BaseData:clear()
end

if NOT_PUBLISH then
	function BaseData:_typeValid(name)
		local value = self.data[name]
		local vt = type(value)
		if vt == "string" or
			vt == "number" or
			vt == "nil" or
			vt == "boolean" or
			vt == "table" then
			return true
		end
		return false
	end

	BaseData._releaseBind = BaseData.bind
    function BaseData:bind(name, ...)
		if not self:_typeValid(name) then
			Logger.logFatal("%s:%s type is valid", self.__cname, name)
		end
		self:_releaseBind(name, ...)
	end
end

return BaseData