package cz.cuni.amis.pogamut.ut2004.bot;

import com.google.inject.Inject;

import cz.cuni.amis.pogamut.base.agent.exceptions.AgentException;
import cz.cuni.amis.pogamut.base.communication.commands.ICommandSerializer;
import cz.cuni.amis.pogamut.base.exceptions.PogamutException;
import cz.cuni.amis.pogamut.base.exceptions.PogamutRuntimeException;
import cz.cuni.amis.pogamut.base.factory.guice.AgentScoped;
import cz.cuni.amis.pogamut.base.utils.logging.AgentLogger;
import cz.cuni.amis.pogamut.ut2004.agent.worldview.UT2004SyncLockableWorldView;

@AgentScoped
public abstract class SyncUT2004Bot<WorldView extends UT2004SyncLockableWorldView> extends ThreadedUT2004Bot<WorldView> {
	
	@Inject
	public SyncUT2004Bot(AgentLogger logger, WorldView worldView, ICommandSerializer commandSerializer) {
		super(logger, worldView, commandSerializer);
		// because the world view will always wait for the next END message
		// we can run as fast as possible
		setLogicPeriodMillis(0);
	}
	
	/**
	 * Should be implemented by the bot developer.
	 * <p><p>
	 * The world view is locked during the method call, you don't have to fear
	 * that the information from the world view (or any bot module) will change during the
	 * reasoning. 
	 * <p><p>
	 * This method is called IFF the bot is alive!
	 */
	protected abstract void doLogic() throws PogamutException;
	
	/**
	 * Locks the world view before calling doLogic(). 
	 */
	protected void doBotLogic() throws PogamutException {
		try {
			getWorldView().lock();
		} catch (InterruptedException e2) {
			// we have been interrupted during the wait on the END message
			throw new AgentException("Interrupted during the waiting for the EndMessage, termination of tha agent has been probably requested.", getLogger().platform(), this);
		}
		try {
			if (!getBotAlive().getFlag()) {
				// bot is dead, unlock the world view and wait for the bot respawn
				getWorldView().unlock();
				return;
			}
			doLogic();
		} catch (PogamutException e) {
			e.logExceptionOnce(getLogger().platform());
			throw e;
		} catch (PogamutRuntimeException e) {
			e.logExceptionOnce(getLogger().platform());
			throw e;
		} catch (Exception e) {
			throw new AgentException("doLogic(): " + e.getMessage(), e, getLogger().user());
		} finally {
			try {
				getWorldView().unlock();
			} catch (Exception e) {
			}
			
		}
	}

}