package edu.teco.dnd.network.tcp;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;

import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import edu.teco.dnd.util.FutureNotifier;
import edu.teco.dnd.util.JoinedFutureNotifier;

public class ServerChannelManager {
	private final Set<Channel> serverChannels = new HashSet<Channel>();
	
	private final ServerChannelFactory channelFactory;
	
	public ServerChannelManager(final ServerChannelFactory channelFactory) {
		this.channelFactory = channelFactory;
	}
	
	private void addChannel(final Channel serverChannel) {
		synchronized (this) {
			serverChannels.add(serverChannel);
		}
		serverChannel.closeFuture().addListener(new CloseFutureListener());
	}
	
	private void removeChannel(final Channel serverChannel) {
		synchronized (this) {
			serverChannels.remove(serverChannel);
		}
	}
	
	private class CloseFutureListener implements ChannelFutureListener {
		@Override
		public void operationComplete(final ChannelFuture future) throws Exception {
			removeChannel(future.channel());
		}
	}

	public ChannelFutureNotifier bind(final SocketAddress listenAddress) {
		if (listenAddress == null) {
			throw new IllegalArgumentException("listenAddress must not be null");
		}
		final ChannelFutureNotifier channelFuture = channelFactory.bind(listenAddress);
		addChannel(channelFuture.channel());
		return channelFuture;
	}

	public FutureNotifier<Collection<Void>> closeAllChannels() {
		final Collection<Channel> openChannels = new ArrayList<Channel>();
		synchronized (this) {
			openChannels.addAll(serverChannels);
		}
		
		final Collection<FutureNotifier<? extends Void>> closeFutureNotifiers =
				new ArrayList<FutureNotifier<? extends Void>>(openChannels.size());
		for (final Channel channel : openChannels) {
			final ChannelFuture closeFuture = channel.close();
			closeFutureNotifiers.add(new ChannelFutureNotifierWrapper(closeFuture));
		}

		return new JoinedFutureNotifier<Void>(closeFutureNotifiers);
	}

	public Collection<Channel> getChannels() {
		synchronized (this) {
			return new HashSet<Channel>(serverChannels);
		}
	}
}

@@ -374,16 +374,146 @@
 ifier;%0A%0A
+/**%0A * Allows to bind to addresses and close all open sockets.%0A * %0A * This class is thread-safe.%0A * %0A * @author Philipp Adolf%0A */%0A
 public c
@@ -780,24 +780,133 @@
 ctory;%0A%09%7D%0A%09%0A
+%09/**%0A%09 * Adds a Channel to the list of known Channels.%0A%09 * %0A%09 * @param serverChannel the Channel to add%0A%09 */%0A
 %09private voi
@@ -1086,24 +1086,141 @@
 er());%0A%09%7D%0A%09%0A
+%09/**%0A%09 * Removes a Channel from the list of known Channels.%0A%09 * %0A%09 * @param serverChannel the Channel to remove%0A%09 */%0A
 %09private voi
@@ -1340,16 +1340,124 @@
 %09%7D%0A%09%7D%0A%09%0A
+%09/**%0A%09 * Used to remove Channels from this manager once they're closed.%0A%09 * %0A%09 * @author Philipp Adolf%0A%09 */%0A
 %09private
@@ -1649,24 +1649,232 @@
 ));%0A%09%09%7D%0A%09%7D%0A%0A
+%09/**%0A%09 * Binds to a new address. The channel is automatically added to this manager.%0A%09 * %0A%09 * @param listenAddress the address to bind to%0A%09 * @return a ChannelFutureNotifier that will return the Channel%0A%09 */%0A
 %09public Chan
@@ -2186,24 +2186,161 @@
 Future;%0A%09%7D%0A%0A
+%09/**%0A%09 * Closes all currently known Channels.%0A%09 * %0A%09 * @return a FutureNotifier that can be used wait for all Channels to be closed%0A%09 */%0A
 %09public Futu
@@ -2924,16 +2924,114 @@
 s);%0A%09%7D%0A%0A
+%09/**%0A%09 * Returns all currently known Channels.%0A%09 * %0A%09 * @return all currently known Channels%0A%09 */%0A
 %09public 

Add JavaDoc for ServerChannelManager