public void addListeners (Telegraph listener, int... msgs) {
		for (int msg : msgs)
			addListener(listener, msg);
	}

	/** Registers a provider for the specified message code.
	 * @param msg the message code
	 * @param provider the provider to add */
	public void addProvider (TelegramProvider provider, int msg) {
		Array<TelegramProvider> providers = msgProviders.get(msg);
		if (providers == null) {
			// Associate an empty unordered array with the message code
			providers = new Array<TelegramProvider>(false, 16);
			msgProviders.put(msg, providers);
		}
		providers.add(provider);
	}

	/** Registers a provider for a selection of message types.
	 * @param provider the provider to add
	 * @param msgs the message codes */
	public void addProviders (TelegramProvider provider, int... msgs) {
		for (int msg : msgs)
			addProvider(provider, msg);
	}

	/** Unregister the specified listener for the specified message code.
	 * @param listener the listener to remove
	 * @param msg the message code */
	public void removeListener (Telegraph listener, int msg) {
		Array<Telegraph> listeners = msgListeners.get(msg);
		if (listeners != null) {
			listeners.removeValue(listener, true);
		}
	}

	/** Unregister the specified listener for the selection of message codes.
	 * 
	 * @param listener the listener to remove
	 * @param msgs the message codes */
	public void removeListener (Telegraph listener, int... msgs) {
		for (int msg : msgs)
			removeListener(listener, msg);
	}

	/** Unregisters all the listeners for the specified message code.
	 * @param msg the message code */
	public void clearListeners (int msg) {
		msgListeners.remove(msg);
	}

	/** Unregisters all the listeners for the given message codes.
	 * 
	 * @param msgs the message codes */
	public void clearListeners (int... msgs) {
		for (int msg : msgs)
			clearListeners(msg);
	}

	/** Removes all the registered listeners for all the message codes. */
	public void clearListeners () {
		msgListeners.clear();
	}

	/** Unregisters all the providers for the specified message code.
	 * @param msg the message code */
	public void clearProviders (int msg) {
		msgProviders.remove(msg);
	}

	/** Unregisters all the providers for the given message codes.
	 * 
	 * @param msgs the message codes */
	public void clearProviders (int... msgs) {
		for (int msg : msgs)
			clearProviders(msg);
	}

	/** Removes all the registered providers for all the message codes. */
	public void clearProviders () {
		msgProviders.clear();
	}

	/** Removes all the telegrams from the queue and releases them to the internal pool. */
	public void clearQueue () {
		for (int i = 0; i < queue.size(); i++) {
			POOL.free(queue.get(i));
		}
		queue.clear();
	}

	/** Removes all the telegrams from the queue and the registered listeners for all the messages. */
	public void clear () {
		clearQueue();
		clearListeners();
		clearProviders();
	}

	/** Sends an immediate message to all registered listeners, with no extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * null, null, msg, null, false)}
	 * 
	 * @param msg the message code */
	public void dispatchMessage (int msg) {
		dispatchMessage(0f, null, null, msg, null, false);
	}

	/** Sends an immediate message to all registered listeners, with no extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * sender, null, msg, null, false)}
	 * 
	 * @param sender the sender of the telegram
	 * @param msg the message code */
	public void dispatchMessage (Telegraph sender, int msg) {
		dispatchMessage(0f, sender, null, msg, null, false);
	}

	/** Sends an immediate message to all registered listeners, with no extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * sender, null, msg, null, needsReturnReceipt)}
	 * 
	 * @param sender the sender of the telegram
	 * @param msg the message code
	 * @param needsReturnReceipt whether the return receipt is needed or not
	 * @throws IllegalArgumentException if the sender is {@code null} and the return receipt is needed */
	public void dispatchMessage (Telegraph sender, int msg, boolean needsReturnReceipt) {
		dispatchMessage(0f, sender, null, msg, null, needsReturnReceipt);
	}

	/** Sends an immediate message to all registered listeners, with extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * null, null, msg, extraInfo, false)}
	 * 
	 * @param msg the message code
	 * @param extraInfo an optional object */
	public void dispatchMessage (int msg, Object extraInfo) {
		dispatchMessage(0f, null, null, msg, extraInfo, false);
	}

	/** Sends an immediate message to all registered listeners, with extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * sender, null, msg, extraInfo, false)}
	 * 
	 * @param sender the sender of the telegram
	 * @param msg the message code
	 * @param extraInfo an optional object */
	public void dispatchMessage (Telegraph sender, int msg, Object extraInfo) {
		dispatchMessage(0f, sender, null, msg, extraInfo, false);
	}

	/** Sends an immediate message to all registered listeners, with extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * sender, null, msg, extraInfo, needsReturnReceipt)}
	 * 
	 * @param sender the sender of the telegram
	 * @param msg the message code
	 * @param extraInfo an optional object
	 * @param needsReturnReceipt whether the return receipt is needed or not
	 * @throws IllegalArgumentException if the sender is {@code null} and the return receipt is needed */
	public void dispatchMessage (Telegraph sender, int msg, Object extraInfo, boolean needsReturnReceipt) {
		dispatchMessage(0f, sender, null, msg, extraInfo, needsReturnReceipt);
	}

	/** Sends an immediate message to the specified receiver with no extra info. The receiver doesn't need to be a register listener
	 * for the specified message code.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * sender, receiver, msg, null, false)}
	 * 
	 * @param sender the sender of the telegram
	 * @param receiver the receiver of the telegram; if it's {@code null} the telegram is broadcasted to all the receivers
	 *           registered for the specified message code
	 * @param msg the message code */
	public void dispatchMessage (Telegraph sender, Telegraph receiver, int msg) {
		dispatchMessage(0f, sender, receiver, msg, null, false);
	}

	/** Sends an immediate message to the specified receiver with no extra info. The receiver doesn't need to be a register listener
	 * for the specified message code.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * sender, receiver, msg, null, needsReturnReceipt)}
	 * 
	 * @param sender the sender of the telegram
	 * @param receiver the receiver of the telegram; if it's {@code null} the telegram is broadcasted to all the receivers
	 *           registered for the specified message code
	 * @param msg the message code
	 * @param needsReturnReceipt whether the return receipt is needed or not
	 * @throws IllegalArgumentException if the sender is {@code null} and the return receipt is needed */
	public void dispatchMessage (Telegraph sender, Telegraph receiver, int msg, boolean needsReturnReceipt) {
		dispatchMessage(0f, sender, receiver, msg, null, needsReturnReceipt);
	}

	/** Sends an immediate message to the specified receiver with extra info. The receiver doesn't need to be a register listener
	 * for the specified message code.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * sender, receiver, msg, extraInfo, false)}
	 * 
	 * @param sender the sender of the telegram
	 * @param receiver the receiver of the telegram; if it's {@code null} the telegram is broadcasted to all the receivers
	 *           registered for the specified message code
	 * @param msg the message code
	 * @param extraInfo an optional object */
	public void dispatchMessage (Telegraph sender, Telegraph receiver, int msg, Object extraInfo) {
		dispatchMessage(0f, sender, receiver, msg, extraInfo, false);
	}

	/** Sends an immediate message to the specified receiver with extra info. The receiver doesn't need to be a register listener
	 * for the specified message code.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean) dispatchMessage(0,
	 * sender, receiver, msg, extraInfo, needsReturnReceipt)}
	 * 
	 * @param sender the sender of the telegram
	 * @param receiver the receiver of the telegram; if it's {@code null} the telegram is broadcasted to all the receivers
	 *           registered for the specified message code
	 * @param msg the message code
	 * @param extraInfo an optional object
	 * @param needsReturnReceipt whether the return receipt is needed or not
	 * @throws IllegalArgumentException if the sender is {@code null} and the return receipt is needed */
	public void dispatchMessage (Telegraph sender, Telegraph receiver, int msg, Object extraInfo, boolean needsReturnReceipt) {
		dispatchMessage(0f, sender, receiver, msg, extraInfo, needsReturnReceipt);
	}

	/** Sends a message to all registered listeners, with the specified delay but no extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean)
	 * dispatchMessage(delay, null, null, msg, null, null)}
	 * 
	 * @param delay the delay in seconds
	 * @param msg the message code */
	public void dispatchMessage (float delay, int msg) {
		dispatchMessage(delay, null, null, msg, null, false);
	}

	/** Sends a message to all registered listeners, with the specified delay but no extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean)
	 * dispatchMessage(delay, sender, null, msg, null, false)}
	 * 
	 * @param delay the delay in seconds
	 * @param sender the sender of the telegram
	 * @param msg the message code */
	public void dispatchMessage (float delay, Telegraph sender, int msg) {
		dispatchMessage(delay, sender, null, msg, null, false);
	}

	/** Sends a message to all registered listeners, with the specified delay but no extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean)
	 * dispatchMessage(delay, sender, null, msg, null, needsReturnReceipt)}
	 * 
	 * @param delay the delay in seconds
	 * @param sender the sender of the telegram
	 * @param msg the message code
	 * @param needsReturnReceipt whether the return receipt is needed or not
	 * @throws IllegalArgumentException if the sender is {@code null} and the return receipt is needed */
	public void dispatchMessage (float delay, Telegraph sender, int msg, boolean needsReturnReceipt) {
		dispatchMessage(delay, sender, null, msg, null, needsReturnReceipt);
	}

	/** Sends a message to all registered listeners, with the specified delay and extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean)
	 * dispatchMessage(delay, null, null, msg, extraInfo, false)}
	 * 
	 * @param delay the delay in seconds
	 * @param msg the message code
	 * @param extraInfo an optional object */
	public void dispatchMessage (float delay, int msg, Object extraInfo) {
		dispatchMessage(delay, null, null, msg, extraInfo, false);
	}

	/** Sends a message to all registered listeners, with the specified delay and extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean)
	 * dispatchMessage(delay, sender, null, msg, extraInfo, false)}
	 * 
	 * @param delay the delay in seconds
	 * @param sender the sender of the telegram
	 * @param msg the message code
	 * @param extraInfo an optional object */
	public void dispatchMessage (float delay, Telegraph sender, int msg, Object extraInfo) {
		dispatchMessage(delay, sender, null, msg, extraInfo, false);
	}

	/** Sends a message to all registered listeners, with the specified delay and extra info.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean)
	 * dispatchMessage(delay, sender, null, msg, extraInfo, needsReturnReceipt)}
	 * 
	 * @param delay the delay in seconds
	 * @param sender the sender of the telegram
	 * @param msg the message code
	 * @param extraInfo an optional object
	 * @param needsReturnReceipt whether the return receipt is needed or not
	 * @throws IllegalArgumentException if the sender is {@code null} and the return receipt is needed */
	public void dispatchMessage (float delay, Telegraph sender, int msg, Object extraInfo, boolean needsReturnReceipt) {
		dispatchMessage(delay, sender, null, msg, extraInfo, needsReturnReceipt);
	}

	/** Sends a message to the specified receiver, with the specified delay but no extra info. The receiver doesn't need to be a
	 * register listener for the specified message code.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean)
	 * dispatchMessage(delay, sender, receiver, msg, null, false)}
	 * 
	 * @param delay the delay in seconds
	 * @param sender the sender of the telegram
	 * @param receiver the receiver of the telegram; if it's {@code null} the telegram is broadcasted to all the receivers
	 *           registered for the specified message code
	 * @param msg the message code */
	public void dispatchMessage (float delay, Telegraph sender, Telegraph receiver, int msg) {
		dispatchMessage(delay, sender, receiver, msg, null, false);
	}

	/** Sends a message to the specified receiver, with the specified delay but no extra info. The receiver doesn't need to be a
	 * register listener for the specified message code.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean)
	 * dispatchMessage(delay, sender, receiver, msg, null, needsReturnReceipt)}
	 * 
	 * @param delay the delay in seconds
	 * @param sender the sender of the telegram
	 * @param receiver the receiver of the telegram; if it's {@code null} the telegram is broadcasted to all the receivers
	 *           registered for the specified message code
	 * @param msg the message code
	 * @param needsReturnReceipt whether the return receipt is needed or not
	 * @throws IllegalArgumentException if the sender is {@code null} and the return receipt is needed */
	public void dispatchMessage (float delay, Telegraph sender, Telegraph receiver, int msg, boolean needsReturnReceipt) {
		dispatchMessage(delay, sender, receiver, msg, null, needsReturnReceipt);
	}

	/** Sends a message to the specified receiver, with the specified delay but no extra info. The receiver doesn't need to be a
	 * register listener for the specified message code.
	 * <p>
	 * This is a shortcut method for {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object, boolean)
	 * dispatchMessage(delay, sender, receiver, msg, extraInfo, false)}
	 * 
	 * @param delay the delay in seconds
	 * @param sender the sender of the telegram
	 * @param receiver the receiver of the telegram; if it's {@code null} the telegram is broadcasted to all the receivers
	 *           registered for the specified message code
	 * @param msg the message code
	 * @param extraInfo an optional object */
	public void dispatchMessage (float delay, Telegraph sender, Telegraph receiver, int msg, Object extraInfo) {
		dispatchMessage(delay, sender, receiver, msg, extraInfo, false);
	}

	/** Given a message, a receiver, a sender and any time delay, this method routes the message to the correct agents (if no delay)
	 * or stores in the message queue to be dispatched at the correct time.
	 * @param delay the delay in seconds
	 * @param sender the sender of the telegram
	 * @param receiver the receiver of the telegram; if it's {@code null} the telegram is broadcasted to all the receivers
	 *           registered for the specified message code
	 * @param msg the message code
	 * @param extraInfo an optional object
	 * @param needsReturnReceipt whether the return receipt is needed or not
	 * @throws IllegalArgumentException if the sender is {@code null} and the return receipt is needed */
	public void dispatchMessage (float delay, Telegraph sender, Telegraph receiver, int msg, Object extraInfo,
		boolean needsReturnReceipt) {
		if (sender == null && needsReturnReceipt)
			throw new IllegalArgumentException("Sender cannot be null when a return receipt is needed");

		// Get a telegram from the pool
		Telegram telegram = POOL.obtain();
		telegram.sender = sender;
		telegram.receiver = receiver;
		telegram.message = msg;
		telegram.extraInfo = extraInfo;
		telegram.returnReceiptStatus = needsReturnReceipt ? Telegram.RETURN_RECEIPT_NEEDED : Telegram.RETURN_RECEIPT_UNNEEDED;

		// If there is no delay, route telegram immediately
		if (delay <= 0.0f) {

			// TODO: should we set the timestamp here?
			// telegram.setTimestamp(GdxAI.getTimepiece().getTime());

			if (debugEnabled) {
				float currentTime = GdxAI.getTimepiece().getTime();
				GdxAI.getLogger().info(
					LOG_TAG,
					"Instant telegram dispatched at time: " + currentTime + " by " + sender + " for " + receiver
						+ ". Message code is " + msg);
			}

			// Send the telegram to the recipient
			discharge(telegram);
		} else {
			float currentTime = GdxAI.getTimepiece().getTime();

			// Set the timestamp for the delayed telegram
			telegram.setTimestamp(currentTime + delay);

			// Put the telegram in the queue
			boolean added = queue.add(telegram);

			// Return it to the pool if has been rejected
			if (!added) POOL.free(telegram);

			if (debugEnabled) {
				if (added)
					GdxAI.getLogger().info(
						LOG_TAG,
						"Delayed telegram from " + sender + " for " + receiver + " recorded at time " + currentTime
							+ ". Message code is " + msg);
				else
					GdxAI.getLogger().info(LOG_TAG,
						"Delayed telegram from " + sender + " for " + receiver + " rejected by the queue. Message code is " + msg);
			}
		}
	}

	/** Dispatches any delayed telegrams with a timestamp that has expired. Dispatched telegrams are removed from the queue.
	 * <p>
	 * This method must be called regularly from inside the main game loop to facilitate the correct and timely dispatch of any
	 * delayed messages. Notice that the message dispatcher internally calls {@link Timepiece#getTime()
	 * GdxAI.getTimepiece().getTime()} to get the current AI time and properly dispatch delayed messages. This means that
	 * <ul>
	 * <li>if you forget to {@link Timepiece#update(float) update the timepiece} the delayed messages won't be dispatched.</li>
	 * <li>ideally the timepiece should be updated before the message dispatcher.</li>
	 * </ul> */
	public void update () {
		float currentTime = GdxAI.getTimepiece().getTime();

		// Peek at the queue to see if any telegrams need dispatching.
		// Remove all telegrams from the front of the queue that have gone
		// past their time stamp.
		Telegram telegram;
		while ((telegram = queue.peek()) != null) {

			// Exit loop if the telegram is in the future
			if (telegram.getTimestamp() > currentTime) break;

			if (debugEnabled) {
				GdxAI.getLogger().info(LOG_TAG,
					"Queued telegram ready for dispatch: Sent to " + telegram.receiver + ". Message code is " + telegram.message);
			}

			// Send the telegram to the recipient
			discharge(telegram);

			// Remove it from the queue
			queue.poll();
		}

	}

	/** Scans the queue and passes pending messages to the given callback in any particular order.
	 * <p>
	 * Typically this method is used to save (serialize) pending messages and restore (deserialize and schedule) them back on game
	 * loading.
	 * @param callback The callback used to report pending messages individually. **/
	public void scanQueue (PendingMessageCallback callback) {
		float currentTime = GdxAI.getTimepiece().getTime();
		int queueSize = queue.size();
		for (int i = 0; i < queueSize; i++) {
			Telegram telegram = queue.get(i);
			callback.report(telegram.getTimestamp() - currentTime, telegram.sender, telegram.receiver, telegram.message,
				telegram.extraInfo, telegram.returnReceiptStatus);
		}
	}

	/** This method is used by {@link #dispatchMessage(float, Telegraph, Telegraph, int, Object) dispatchMessage} for immediate
	 * telegrams and {@link #update(float) update} for delayed telegrams. It first calls the message handling method of the
	 * receiving agents with the specified telegram then returns the telegram to the pool.
	 * @param telegram the telegram to discharge */
	private void discharge (Telegram telegram) {
		if (telegram.receiver != null) {
			// Dispatch the telegram to the receiver specified by the telegram itself
			if (!telegram.receiver.handleMessage(telegram)) {
				// Telegram could not be handled
				if (debugEnabled) GdxAI.getLogger().info(LOG_TAG, "Message " + telegram.message + " not handled");
			}
		} else {
			// Dispatch the telegram to all the registered receivers
			int handledCount = 0;
			Array<Telegraph> listeners = msgListeners.get(telegram.message);
			if (listeners != null) {
				for (int i = 0; i < listeners.size; i++) {
					if (listeners.get(i).handleMessage(telegram)) {
						handledCount++;
					}
				}
			}
			// Telegram could not be handled
			if (debugEnabled && handledCount == 0) GdxAI.getLogger().info(LOG_TAG, "Message " + telegram.message + " not handled");
		}

		if (telegram.returnReceiptStatus == Telegram.RETURN_RECEIPT_NEEDED) {
			// Use this telegram to send the return receipt
			telegram.receiver = telegram.sender;
			telegram.sender = this;
			telegram.returnReceiptStatus = Telegram.RETURN_RECEIPT_SENT;
			discharge(telegram);
		} else {
			// Release the telegram to the pool
			POOL.free(telegram);
		}
	}

	/** Handles the telegram just received. This method always returns {@code false} since usually the message dispatcher never
	 * receives telegrams. Actually, the message dispatcher implements {@link Telegraph} just because it can send return receipts.
	 * @param msg The telegram
	 * @return always {@code false}. */
	@Override
	public boolean handleMessage (Telegram msg) {
		return false;
	}

	/** A {@code PendingMessageCallback} is used by the {@link MessageDispatcher#scanQueue(PendingMessageCallback) scanQueue} method
	 * of the {@link MessageDispatcher} to report its pending messages individually.
	 * 
	 * @author davebaol */
	public interface PendingMessageCallback {

		/** Reports a pending message.
		 * @param delay The remaining delay in seconds
		 * @param sender The message sender
		 * @param receiver The message receiver
		 * @param message The message code
		 * @param extraInfo Any additional information that may accompany the message
		 * @param returnReceiptStatus The return receipt status of the message */
		public void report (float delay, Telegraph sender, Telegraph receiver, int message, Object extraInfo,
			int returnReceiptStatus);
	}

}
public void addListeners ( Telegraph listener , int ... msgs ) { for ( int msg : msgs ) addListener ( listener , msg ) ; } public void addProvider ( TelegramProvider provider , int msg ) { Array < TelegramProvider > providers = msgProviders . get ( msg ) ; if ( providers == null ) { providers = new Array < TelegramProvider > ( false , 16 ) ; msgProviders . put ( msg , providers ) ; } providers . add ( provider ) ; } public void addProviders ( TelegramProvider provider , int ... msgs ) { for ( int msg : msgs ) addProvider ( provider , msg ) ; } public void removeListener ( Telegraph listener , int msg ) { Array < Telegraph > listeners = msgListeners . get ( msg ) ; if ( listeners != null ) { listeners . removeValue ( listener , true ) ; } } public void removeListener ( Telegraph listener , int ... msgs ) { for ( int msg : msgs ) removeListener ( listener , msg ) ; } public void clearListeners ( int msg ) { msgListeners . remove ( msg ) ; } public void clearListeners ( int ... msgs ) { for ( int msg : msgs ) clearListeners ( msg ) ; } public void clearListeners ( ) { msgListeners . clear ( ) ; } public void clearProviders ( int msg ) { msgProviders . remove ( msg ) ; } public void clearProviders ( int ... msgs ) { for ( int msg : msgs ) clearProviders ( msg ) ; } public void clearProviders ( ) { msgProviders . clear ( ) ; } public void clearQueue ( ) { for ( int i = 0 ; i < queue . size ( ) ; i ++ ) { POOL . free ( queue . get ( i ) ) ; } queue . clear ( ) ; } public void clear ( ) { clearQueue ( ) ; clearListeners ( ) ; clearProviders ( ) ; } public void dispatchMessage ( int msg ) { dispatchMessage ( 0f , null , null , msg , null , false ) ; } public void dispatchMessage ( Telegraph sender , int msg ) { dispatchMessage ( 0f , sender , null , msg , null , false ) ; } public void dispatchMessage ( Telegraph sender , int msg , boolean needsReturnReceipt ) { dispatchMessage ( 0f , sender , null , msg , null , needsReturnReceipt ) ; } public void dispatchMessage ( int msg , Object extraInfo ) { dispatchMessage ( 0f , null , null , msg , extraInfo , false ) ; } public void dispatchMessage ( Telegraph sender , int msg , Object extraInfo ) { dispatchMessage ( 0f , sender , null , msg , extraInfo , false ) ; } public void dispatchMessage ( Telegraph sender , int msg , Object extraInfo , boolean needsReturnReceipt ) { dispatchMessage ( 0f , sender , null , msg , extraInfo , needsReturnReceipt ) ; } public void dispatchMessage ( Telegraph sender , Telegraph receiver , int msg ) { dispatchMessage ( 0f , sender , receiver , msg , null , false ) ; } public void dispatchMessage ( Telegraph sender , Telegraph receiver , int msg , boolean needsReturnReceipt ) { dispatchMessage ( 0f , sender , receiver , msg , null , needsReturnReceipt ) ; } public void dispatchMessage ( Telegraph sender , Telegraph receiver , int msg , Object extraInfo ) { dispatchMessage ( 0f , sender , receiver , msg , extraInfo , false ) ; } public void dispatchMessage ( Telegraph sender , Telegraph receiver , int msg , Object extraInfo , boolean needsReturnReceipt ) { dispatchMessage ( 0f , sender , receiver , msg , extraInfo , needsReturnReceipt ) ; } public void dispatchMessage ( float delay , int msg ) { dispatchMessage ( delay , null , null , msg , null , false ) ; } public void dispatchMessage ( float delay , Telegraph sender , int msg ) { dispatchMessage ( delay , sender , null , msg , null , false ) ; } public void dispatchMessage ( float delay , Telegraph sender , int msg , boolean needsReturnReceipt ) { dispatchMessage ( delay , sender , null , msg , null , needsReturnReceipt ) ; } public void dispatchMessage ( float delay , int msg , Object extraInfo ) { dispatchMessage ( delay , null , null , msg , extraInfo , false ) ; } public void dispatchMessage ( float delay , Telegraph sender , int msg , Object extraInfo ) { dispatchMessage ( delay , sender , null , msg , extraInfo , false ) ; } public void dispatchMessage ( float delay , Telegraph sender , int msg , Object extraInfo , boolean needsReturnReceipt ) { dispatchMessage ( delay , sender , null , msg , extraInfo , needsReturnReceipt ) ; } public void dispatchMessage ( float delay , Telegraph sender , Telegraph receiver , int msg ) { dispatchMessage ( delay , sender , receiver , msg , null , false ) ; } public void dispatchMessage ( float delay , Telegraph sender , Telegraph receiver , int msg , boolean needsReturnReceipt ) { dispatchMessage ( delay , sender , receiver , msg , null , needsReturnReceipt ) ; } public void dispatchMessage ( float delay , Telegraph sender , Telegraph receiver , int msg , Object extraInfo ) { dispatchMessage ( delay , sender , receiver , msg , extraInfo , false ) ; } public void dispatchMessage ( float delay , Telegraph sender , Telegraph receiver , int msg , Object extraInfo , boolean needsReturnReceipt ) { if ( sender == null && needsReturnReceipt ) throw new IllegalArgumentException ( "Sender cannot be null when a return receipt is needed" ) ; Telegram telegram = POOL . obtain ( ) ; telegram . sender = sender ; telegram . receiver = receiver ; telegram . message = msg ; telegram . extraInfo = extraInfo ; telegram . returnReceiptStatus = needsReturnReceipt ? Telegram . RETURN_RECEIPT_NEEDED : Telegram . RETURN_RECEIPT_UNNEEDED ; if ( delay <= 0.0f ) { if ( debugEnabled ) { float currentTime = GdxAI . getTimepiece ( ) . getTime ( ) ; GdxAI . getLogger ( ) . info ( LOG_TAG , "Instant telegram dispatched at time: " + currentTime + " by " + sender + " for " + receiver + ". Message code is " + msg ) ; } discharge ( telegram ) ; } else { float currentTime = GdxAI . getTimepiece ( ) . getTime ( ) ; telegram . setTimestamp ( currentTime + delay ) ; boolean added = queue . add ( telegram ) ; if ( ! added ) POOL . free ( telegram ) ; if ( debugEnabled ) { if ( added ) GdxAI . getLogger ( ) . info ( LOG_TAG , "Delayed telegram from " + sender + " for " + receiver + " recorded at time " + currentTime + ". Message code is " + msg ) ; else GdxAI . getLogger ( ) . info ( LOG_TAG , "Delayed telegram from " + sender + " for " + receiver + " rejected by the queue. Message code is " + msg ) ; } } } public void update ( ) { float currentTime = GdxAI . getTimepiece ( ) . getTime ( ) ; Telegram telegram ; while ( ( telegram = queue . peek ( ) ) != null ) { if ( telegram . getTimestamp ( ) > currentTime ) break ; if ( debugEnabled ) { GdxAI . getLogger ( ) . info ( LOG_TAG , "Queued telegram ready for dispatch: Sent to " + telegram . receiver + ". Message code is " + telegram . message ) ; } discharge ( telegram ) ; queue . poll ( ) ; } } public void scanQueue ( PendingMessageCallback callback ) { float currentTime = GdxAI . getTimepiece ( ) . getTime ( ) ; int queueSize = queue . size ( ) ; for ( int i = 0 ; i < queueSize ; i ++ ) { Telegram telegram = queue . get ( i ) ; callback . report ( telegram . getTimestamp ( ) - currentTime , telegram . sender , telegram . receiver , telegram . message , telegram . extraInfo , telegram . returnReceiptStatus ) ; } } private void discharge ( Telegram telegram ) { if ( telegram . receiver != null ) { if ( ! telegram . receiver . handleMessage ( telegram ) ) { if ( debugEnabled ) GdxAI . getLogger ( ) . info ( LOG_TAG , "Message " + telegram . message + " not handled" ) ; } } else { int handledCount = 0 ; Array < Telegraph > listeners = msgListeners . get ( telegram . message ) ; if ( listeners != null ) { for ( int i = 0 ; i < listeners . size ; i ++ ) { if ( listeners . get ( i ) . handleMessage ( telegram ) ) { handledCount ++ ; } } } if ( debugEnabled && handledCount == 0 ) GdxAI . getLogger ( ) . info ( LOG_TAG , "Message " + telegram . message + " not handled" ) ; } if ( telegram . returnReceiptStatus == Telegram . RETURN_RECEIPT_NEEDED ) { telegram . receiver = telegram . sender ; telegram . sender = this ; telegram . returnReceiptStatus = Telegram . RETURN_RECEIPT_SENT ; discharge ( telegram ) ; } else { POOL . free ( telegram ) ; } } @ Override public boolean handleMessage ( Telegram msg ) { return false ; } public interface PendingMessageCallback { public void report ( float delay , Telegraph sender , Telegraph receiver , int message , Object extraInfo , int returnReceiptStatus ) ; } }
Registers a listener for a selection of message types. Messages without an explicit receiver are broadcasted to all its
registered listeners.

@param listener the listener to add
@param msgs the message codes