/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Ordinastie
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package net.malisis.core.network;

import java.util.List;

import net.malisis.core.IMalisisMod;
import net.malisis.core.MalisisCore;
import net.malisis.core.inventory.message.OpenInventoryMessage;

import com.google.common.base.Function;
import com.google.common.collect.Ordering;

import cpw.mods.fml.common.discovery.ASMDataTable;
import cpw.mods.fml.common.discovery.ASMDataTable.ASMData;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import cpw.mods.fml.relauncher.Side;

/**
 * {@link MalisisNetwork} is a wrapper around {@link SimpleNetworkWrapper} in order to ease the handling of discriminators.<br>
 * Each mod should instantiate a {@code MalisisNetwork} instance when constructed, and {@link IMessageHandler} should be annotated with
 * {@link MalisisMessage} and register their packets inside their own public paramless constructors.<br>
 * <br>
 * Example : {@link OpenInventoryMessage}.
 *
 *
 * @author Ordinastie
 */
public class MalisisNetwork extends SimpleNetworkWrapper
{
	/** The global discriminator for each packet. */
	private int discriminator = 0;
	/** Name of the channel used **/
	protected String name;

	/**
	 * Instantiates a new {@link MalisisNetwork}.
	 *
	 * @param channelName the channel name
	 */
	public MalisisNetwork(String channelName)
	{
		super(channelName);
		name = channelName;
	}

	/**
	 * Instantiates a new {@link MalisisNetwork}
	 *
	 * @param mod the mod
	 */
	public MalisisNetwork(IMalisisMod mod)
	{
		this(mod.getModId());
	}

	/**
	 * Register a message with the next discriminator available.
	 *
	 * @param <REQ> the generic type
	 * @param <REPLY> the generic type
	 * @param messageHandler the message handler
	 * @param requestMessageType the request message type
	 * @param side the side
	 */
	public <REQ extends IMessage, REPLY extends IMessage> void registerMessage(Class<? extends IMessageHandler<REQ, REPLY>> messageHandler, Class<REQ> requestMessageType, Side side)
	{
		super.registerMessage(messageHandler, requestMessageType, discriminator++, side);
		MalisisCore.log.info("Registering " + messageHandler.getSimpleName() + " for " + requestMessageType.getSimpleName()
				+ " with discriminator " + discriminator + " in channel " + name);
	}

	/**
	 * Register a message with the next discriminator available.
	 *
	 * @param <REQ> the generic type
	 * @param <REPLY> the generic type
	 * @param messageHandler the message handler
	 * @param requestMessageType the request message type
	 * @param side the side
	 */
	public <REQ extends IMessage, REPLY extends IMessage> void registerMessage(IMessageHandler<? super REQ, ? extends REPLY> messageHandler, Class<REQ> requestMessageType, Side side)
	{
		super.registerMessage(messageHandler, requestMessageType, discriminator++, side);
		MalisisCore.log.info("Registering " + messageHandler.getClass().getSimpleName() + " for " + requestMessageType.getSimpleName()
				+ " with discriminator " + discriminator + " in channel " + name);
	}

	/**
	 * Gets the next discriminator available.
	 *
	 * @return the next discriminator
	 */
	public int getNextDiscriminator()
	{
		return discriminator++;
	}

	/**
	 * Instantiates every {@link IMessageHandler} annotated with {@link MalisisMessage}.<br>
	 *
	 * @param asmDataTable the asm data table
	 */
	public static void createMessages(ASMDataTable asmDataTable)
	{
		List<ASMData> classes = Ordering.natural().onResultOf(new Function<ASMData, String>()
		{
			@Override
			public String apply(ASMData data)
			{
				return data.getClassName();
			}
		}).sortedCopy(asmDataTable.getAll(MalisisMessage.class.getName()));

		for (ASMData data : classes)
		{
			try
			{
				Class clazz = Class.forName(data.getClassName());
				if (IMessageHandler.class.isAssignableFrom(clazz))
					clazz.newInstance();
				else
					MalisisCore.log.error("@MalisisMessage found on {} that does not implement IMessageHandler", data.getClassName());
			}
			catch (Exception e)
			{
				MalisisCore.log.error("Could not create {} message.", data.getClassName(), e);
			}
		}

	}
}

@@ -1333,16 +1333,149 @@
 Message;
+%0Aimport net.malisis.core.util.EntityUtils;%0Aimport net.minecraft.entity.player.EntityPlayerMP;%0Aimport net.minecraft.world.chunk.Chunk;
 %0A%0Aimport
@@ -2888,24 +2888,453 @@
 dId());%0A%09%7D%0A%0A
+%09/**%0A%09 * Send the %7B@link IMessage%7D to all the players currently watching that specific chunk.%3Cbr%3E%0A%09 * The %7B@link IMessageHandler%7D for the message type should be on the CLIENT side.%0A%09 *%0A%09 * @param message the message%0A%09 * @param chunk the chunk%0A%09 */%0A%09public void sendToPlayersWatchingChunk(IMessage message, Chunk chunk)%0A%09%7B%0A%09%09for (EntityPlayerMP player : EntityUtils.getPlayersWatchingChunk(chunk))%0A%09%09%09sendTo(message, player);%0A%09%7D%0A%0A
 %09/**%0A%09 * Reg

Add MalisisNetwork.sendToPlayersWatchingChunk()