-- Write handlers:

local function ReplicaSetValue(replica_id, path_array, value)
	local replica = Replicas[replica_id]
	-- Getting path pointer and listener table:
	local pointer = replica.Data
	local listeners = replica._table_listeners
	for i = 1, #path_array - 1 do
		pointer = pointer[path_array[i]]
		if listeners ~= nil then
			listeners = listeners[1][path_array[i]]
		end
	end
	-- Setting value:
	local key = path_array[#path_array]
	local old_value = pointer[key]
	pointer[key] = value
	-- Signaling listeners:
	if old_value ~= value and listeners ~= nil then
		if old_value == nil then
			if listeners[3] ~= nil then -- "NewKey" listeners
				for _, listener in ipairs(listeners[3]) do
					listener(value, key)
				end
			end
		end
		listeners = listeners[1][path_array[#path_array]]
		if listeners ~= nil then
			if listeners[2] ~= nil then -- "Change" listeners
				for _, listener in ipairs(listeners[2]) do
					listener(value, old_value)
				end
			end
		end
	end
	-- Raw listeners:
	for _, listener in ipairs(replica._raw_listeners) do
		listener("SetValue", path_array, value)
	end
end

local function ReplicaSetValues(replica_id, path_array, values)
	local replica = Replicas[replica_id]
	-- Getting path pointer and listener table:
	local pointer = replica.Data
	local listeners = replica._table_listeners
	for i = 1, #path_array do
		pointer = pointer[path_array[i]]
		if listeners ~= nil then
			listeners = listeners[1][path_array[i]]
		end
	end
	-- Setting values:
	for key, value in pairs(values) do
		-- Set value:
		local old_value = pointer[key]
		pointer[key] = value
		-- Signaling listeners:
		if old_value ~= value and listeners ~= nil then
			if old_value == nil then
				if listeners[3] ~= nil then -- "NewKey" listeners
					for _, listener in ipairs(listeners[3]) do
						listener(value, key)
					end
				end
			end
			local key_listeners = listeners[1][key]
			if key_listeners ~= nil then
				if key_listeners[2] ~= nil then -- "Change" listeners
					for _, listener in ipairs(key_listeners[2]) do
						listener(value, old_value)
					end
				end
			end
		end
	end
	-- Raw listeners:
	for _, listener in ipairs(replica._raw_listeners) do
		listener("SetValues", path_array, values)
	end
end

local function ReplicaArrayInsert(replica_id, path_array, value) --> new_index
	local replica = Replicas[replica_id]
	-- Getting path pointer and listener table:
	local pointer = replica.Data
	local listeners = replica._table_listeners
	for i = 1, #path_array do
		pointer = pointer[path_array[i]]
		if listeners ~= nil then
			listeners = listeners[1][path_array[i]]
		end
	end
	-- Setting value:
	table.insert(pointer, value)
	-- Signaling listeners:
	local new_index = #pointer
	if listeners ~= nil then
		if listeners[4] ~= nil then -- "ArrayInsert" listeners
			for _, listener in ipairs(listeners[4]) do
				listener(new_index, value)
			end
		end
	end
	-- Raw listeners:
	for _, listener in ipairs(replica._raw_listeners) do
		listener("ArrayInsert", path_array, value, new_index)
	end
	return new_index
end

local function ReplicaArraySet(replica_id, path_array, index, value)
	local replica = Replicas[replica_id]
	-- Getting path pointer and listener table:
	local pointer = replica.Data
	local listeners = replica._table_listeners
	for i = 1, #path_array do
		pointer = pointer[path_array[i]]
		if listeners ~= nil then
			listeners = listeners[1][path_array[i]]
		end
	end
	-- Setting value:
	pointer[index] = value
	-- Signaling listeners:
	if listeners ~= nil then
		if listeners[5] ~= nil then -- "ArraySet" listeners
			for _, listener in ipairs(listeners[5]) do
				listener(index, value)
			end
		end
	end
	-- Raw listeners:
	for _, listener in ipairs(replica._raw_listeners) do
		listener("ArraySet", path_array, index, value)
	end
end

local function ReplicaArrayRemove(replica_id, path_array, index) --> removed_value
	local replica = Replicas[replica_id]
	-- Getting path pointer and listener table:
	local pointer = replica.Data
	local listeners = replica._table_listeners
	for i = 1, #path_array do
		pointer = pointer[path_array[i]]
		if listeners ~= nil then
			listeners = listeners[1][path_array[i]]
		end
	end
	-- Setting value:
	local old_value = table.remove(pointer, index)
	-- Signaling listeners:
	if listeners ~= nil then
		if listeners[6] ~= nil then -- "ArrayRemove" listeners
			for _, listener in ipairs(listeners[6]) do
				listener(index, old_value)
			end
		end
	end
	-- Raw listeners:
	for _, listener in ipairs(replica._raw_listeners) do
		listener("ArrayRemove", path_array, index, old_value)
	end
	return old_value
end