package cz.cuni.amis.pogamut.base.communication.commands;

import cz.cuni.amis.pogamut.base.communication.exceptions.CommandException;
import cz.cuni.amis.pogamut.base.communication.exceptions.CommunicationException;
import cz.cuni.amis.pogamut.base.communication.messages.CommandMessage;
import cz.cuni.amis.pogamut.base.factory.guice.AgentScoped;
import cz.cuni.amis.pogamut.base.utils.logging.AgentLogger;
import cz.cuni.amis.utils.listener.Listeners;

@AgentScoped
public class Act implements IAct {
	
	private static class MessageListenerNotifier implements Listeners.ListenerNotifier<ICommandListener> {
		
		private CommandMessage msg;
		
		public void setMessage(CommandMessage msg) {
			this.msg = msg;
		}

		@Override
		public void notify(ICommandListener listener) {
			listener.notify(msg);
		}
	}
	
	/**
	 * Used to notify listeners that a certain message has came.
	 */
	private MessageListenerNotifier notifier = new MessageListenerNotifier();
	
	/**
	 * Listeners that should be called upon receiving or before sending the message.
	 * <p><p>
	 * Those listeners are executed before the message is passed to the receiver.
	 */
	protected Listeners<ICommandListener> commandListeners = new Listeners<ICommandListener>();
	
	private ICommandSerializer serializer;
	
	private AgentLogger log;

	public Act(ICommandSerializer serializer, AgentLogger logger) {
		this.serializer = serializer;
		this.log = logger;
	}

	@Override
	public synchronized void act(CommandMessage command) throws CommandException {
		try {
			serializer.sendCommand(command);
		} catch (Exception e) {
			serializer.stop();
			throw new CommandException("Could not serialize the command: " + e.toString(), e, log);
		}
		if (commandListeners.count() > 0) {
			this.notifier.setMessage(command);
			commandListeners.notify(this.notifier);
		}
	}

	@Override
	public void addCommandListener(ICommandListener listener) {
		commandListeners.addWeakListener(listener);
	}

	@Override
	public void removeCommandListener(ICommandListener listener) {
		commandListeners.removeListener(listener);
	}

}
