-- Listening:
function Replica:ListenToChange(path, listener) --> [ScriptConnection] listener(new_value)
	if type(listener) ~= "function" then
		error("[ReplicaController]: Only a function can be set as listener in Replica:ListenToChange()")
	end

	local path_array = (type(path) == "string") and StringPathToArray(path) or path
	if #path_array < 1 then
		error("[ReplicaController]: Passed empty path - a value key must be specified")
	end
	-- Getting listener table for given path:
	local listeners = CreateTableListenerPathIndex(self, path_array, 2)
	table.insert(listeners, listener)
	-- ScriptConnection which allows the disconnection of the listener:
	return Madwork.NewArrayScriptConnection(listeners, listener, CleanTableListenerTable, {self._table_listeners, path_array})
end

function Replica:ListenToNewKey(path, listener) --> [ScriptConnection] listener(new_value, new_key)
	if type(listener) ~= "function" then
		error("[ReplicaController]: Only a function can be set as listener in Replica:ListenToNewKey()")
	end

	local path_array = (type(path) == "string") and StringPathToArray(path) or path
	-- Getting listener table for given path:
	local listeners = CreateTableListenerPathIndex(self, path_array, 3)
	table.insert(listeners, listener)
	-- ScriptConnection which allows the disconnection of the listener:
	if #path_array == 0 then
		return Madwork.NewArrayScriptConnection(listeners, listener)
	else
		return Madwork.NewArrayScriptConnection(listeners, listener, CleanTableListenerTable, {self._table_listeners, path_array})
	end
end

function Replica:ListenToArrayInsert(path, listener) --> [ScriptConnection] listener(new_value, new_index)
	if type(listener) ~= "function" then
		error("[ReplicaController]: Only a function can be set as listener in Replica:ListenToArrayInsert()")
	end

	local path_array = (type(path) == "string") and StringPathToArray(path) or path
	-- Getting listener table for given path:
	local listeners = CreateTableListenerPathIndex(self, path_array, 4)
	table.insert(listeners, listener)
	-- ScriptConnection which allows the disconnection of the listener:
	if #path_array == 0 then
		return Madwork.NewArrayScriptConnection(listeners, listener)
	else
		return Madwork.NewArrayScriptConnection(listeners, listener, CleanTableListenerTable, {self._table_listeners, path_array})
	end
end

function Replica:ListenToArraySet(path, listener) --> [ScriptConnection] listener(new_value, index)
	if type(listener) ~= "function" then
		error("[ReplicaController]: Only a function can be set as listener in Replica:ListenToArraySet()")
	end

	local path_array = (type(path) == "string") and StringPathToArray(path) or path
	-- Getting listener table for given path:
	local listeners = CreateTableListenerPathIndex(self, path_array, 5)
	table.insert(listeners, listener)
	-- ScriptConnection which allows the disconnection of the listener:
	if #path_array == 0 then
		return Madwork.NewArrayScriptConnection(listeners, listener)
	else
		return Madwork.NewArrayScriptConnection(listeners, listener, CleanTableListenerTable, {self._table_listeners, path_array})
	end
end

function Replica:ListenToArrayRemove(path, listener) --> [ScriptConnection] listener(old_value, old_index)
	if type(listener) ~= "function" then
		error("[ReplicaController]: Only a function can be set as listener in Replica:ListenToArrayRemove()")
	end

	local path_array = (type(path) == "string") and StringPathToArray(path) or path
	-- Getting listener table for given path:
	local listeners = CreateTableListenerPathIndex(self, path_array, 6)
	table.insert(listeners, listener)
	-- ScriptConnection which allows the disconnection of the listener:
	if #path_array == 0 then
		return Madwork.NewArrayScriptConnection(listeners, listener)
	else
		return Madwork.NewArrayScriptConnection(listeners, listener, CleanTableListenerTable, {self._table_listeners, path_array})
	end
end

function Replica:ListenToWrite(function_name, listener) --> [ScriptConnection] listener(params...)
	if type(listener) ~= "function" then
		error("[ReplicaController]: Only a function can be set as listener in Replica:ListenToWrite()")
	end
	if self._write_lib == nil then
		error("[ReplicaController]: _write_lib was not declared for this replica")
	end

	local func_id = self._write_lib_dictionary[function_name]
	if func_id == nil then
		error("[ReplicaController]: Write function \"" .. function_name .. "\" not declared inside _write_lib of this replica")
	end

	-- Getting listener table for given path:
	local listeners = self._function_listeners[func_id]
	if listeners == nil then
		listeners = {}
		self._function_listeners[func_id] = listeners
	end
	table.insert(listeners, listener)
	-- ScriptConnection which allows the disconnection of the listener:
	return Madwork.NewArrayScriptConnection(listeners, listener)
end

function Replica:ListenToRaw(listener) --> [ScriptConnection] (action_name, params...)
	local listeners = self._raw_listeners
	table.insert(listeners, listener)
	return Madwork.NewArrayScriptConnection(listeners, listener)
end