/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <cassert>
#include <unistd.h>

#include "ingen/Interface.hpp"
#include "raul/log.hpp"

#include "ClientBroadcaster.hpp"
#include "EdgeImpl.hpp"
#include "EngineStore.hpp"
#include "ObjectSender.hpp"
#include "PluginImpl.hpp"
#include "util.hpp"

#define LOG(s) (s("[ClientBroadcaster] "))

namespace Ingen {
namespace Server {

/** Register a client to receive messages over the notification band.
 */
void
ClientBroadcaster::register_client(const Raul::URI&     uri,
                                   SharedPtr<Interface> client)
{
	Glib::Mutex::Lock lock(_clients_mutex);
	LOG(Raul::info)(Raul::fmt("Registered client <%1%>\n") % uri);
	_clients[uri] = client;
}

/** Remove a client from the list of registered clients.
 *
 * @return true if client was found and removed.
 */
bool
ClientBroadcaster::unregister_client(const Raul::URI& uri)
{
	Glib::Mutex::Lock lock(_clients_mutex);
	const size_t erased = _clients.erase(uri);

	if (erased > 0) {
		LOG(Raul::info)(Raul::fmt("Unregistered client <%1%>\n") % uri);
	}

	return (erased > 0);
}

/** Looks up the client with the given source @a uri (which is used as the
 * unique identifier for registered clients).
 */
SharedPtr<Interface>
ClientBroadcaster::client(const Raul::URI& uri)
{
	Glib::Mutex::Lock lock(_clients_mutex);
	Clients::iterator i = _clients.find(uri);
	if (i != _clients.end()) {
		return (*i).second;
	} else {
		return SharedPtr<Interface>();
	}
}

void
ClientBroadcaster::send_plugins(const NodeFactory::Plugins& plugins)
{
	Glib::Mutex::Lock lock(_clients_mutex);
	for (Clients::const_iterator c = _clients.begin(); c != _clients.end(); ++c) {
		send_plugins_to((*c).second.get(), plugins);
	}
}

void
ClientBroadcaster::send_plugins_to(Interface*                  client,
                                   const NodeFactory::Plugins& plugins)
{
	client->bundle_begin();

	for (NodeFactory::Plugins::const_iterator i = plugins.begin(); i != plugins.end(); ++i) {
		const PluginImpl* const plugin = i->second;
		client->put(plugin->uri(), plugin->properties());
	}

	client->bundle_end();
}

/** Send an object to all clients.
 *
 * @param o         Object to send
 * @param recursive If true send all children of object
 */
void
ClientBroadcaster::send_object(const GraphObjectImpl* o, bool recursive)
{
	Glib::Mutex::Lock lock(_clients_mutex);
	for (Clients::const_iterator i = _clients.begin(); i != _clients.end(); ++i) {
		ObjectSender::send_object((*i).second.get(), o, recursive);
	}
}

} // namespace Server
} // namespace Ingen