package cz.cuni.amis.pogamut.base.factory.guice;

import com.google.inject.AbstractModule;

/**
 * Base Pogamut's Guice module that covers the simple bindings for Pogamut's communication
 * chain.
 * <p><p>
 * In fact - only implicit bindings is defined here whatsoever, because they are written in
 * respective interfaces using ImplementedBy annotation.
 * <p><p>
 * Implicit bindings + classes that are used and you might benefit from redefining them:
 * <p><p>
 * <table>
 * <tr><th>Mapped class</th>          <th>  </th> <th>Target of the mapping for this module</th></th></tr>
 * 
 * <tr><td>AgentLogger         </td>  <td>-></td> <td>AgentLogger ... takes care about logging</td></tr>
 * <tr><td>IWorldReaderProvider</td>  <td>-></td> <td>IWorldConnection ... provides a Reader for the world connection, way how to obtain messages</td></tr>
 * <tr><td>IWorldWriterProvider</td>  <td>-></td> <td>IWorldConnection ... provides a Writer for the world connection, way how to send commands to the world</td></tr>
 * <tr><td>ICommandSerializer  </td>  <td>-></td> <td>CommandSerializer ... responsible for serializing commands to strings and sending them to the world</td></tr>
 * <tr><td>IAct                </td>  <td>-></td> <td>Act ... class that is responsible for sending commands to the world</td></tr>
 * <tr><td>IWorldConnection    </td>  <td>-></td> <td>SocketConnection ... as default the world connection is via Sockets using ISocketConnectionAddress</td></tr>
 * <tr><td>IWorldMessageParser </td>  <td>-></td> <td>Parser ... class that parses messages, this implementation requires IYylex implementation (not required though)</td></tr>
 * <tr><td>IYylexObserver      </td>  <td>-></td> <td>IYylexObserver.LogObserver ... as default log everything to AgentLogger.platform() log category</td></tr>
 * <tr><td>IWorldEventOutput   </td>  <td>-></td> <td>WorldMessageTranslator ... takes message from the parser, stuff them to IWorldMessageHandler that should return IWorldEvents, requires implementation as IWorldMessageHandler</td></tr>
 * <tr><td>IMediator           </td>  <td>-></td> <td>Mediator ... wraps the communication thread, that is periodically reading messages from the IWorldEventOutput and passes them to IWorldEventInput</td></tr>
 * <tr><td>IMediatorOutput     </td>  <td>-></td> <td>IWorldView ... specify where the messages should go from the Mediator</td></tr>
 * <tr><td>IStartableWorldView </td>  <td>-></td> <td>EventDriverWorldView ... what world to use for the agent</td></tr>
 * </table>
 * <p>
 * To have successful module the descendant must specify those missing bindings:
 * <ol>
 * <li>IAgent - to know what agent to instantiate, note that when running agent we do not use this instance directly but using AgentInstanceDescriptor instance instead</li>
 * <li>IWorldMessageHandler - that represents a protocol between world -> agent</li>
 * <li>IYylex - to provide custom based parser for the world messages or change implementation of IWorldMessageParser not to use IYylex</li>
 * </ol>
 * ... thus don't forget to call super.configure() ;-)
 * <p><p>
 * Additionaly - if you need to alter the way your agent is started, you have to extend classes
 * and redifine those in the module (basically the IDE will instantiate those classes not the IAgent directly,
 * because we needn't to know only what IAgent we will run, but also HOW to start it):
 * <ol>
 * <li>AgentInstanceDescriptor - this is a class, which instance we will obtain before starting the agent, not the IAgent itself, it's a data class containing all useful object the AgentRunner may deal with</li>
 * <li>AgentRunner - used to startup the agent (connect it, start the mediator, start the agent)</li>
 * </ol>  
 * <p><p>
 * If you want to bind your custom class to one of the base classes, do it this way:
 * <ul>
 * <li>BE TOTALY SURE WHAT YOU'RE DOING :-) or it will fail horribly or you may cripple IDE...</li>
 * <li>Create wrapper for the base class with dependency injection of the previous class and annotate it with Inject<p>
 *     Change the implementation slightly...
 * </li>
 * <li>always make those new classes <b>AgentScoped</b>!</li>
 * </ul> 
 * <p><p>
 * <b>NOTICE</b> that you need to call getAgentScope().clearScope() if you want to instantiate
 * more then one agent with the same injector!
 * 
 * @author Jimmy
 */
public abstract class PogamutAgentModule extends AbstractModule {
	
	private AgentScope agentScope;
	
	public PogamutAgentModule() {
		this.agentScope = createAgentScope();
	}
	
	public PogamutAgentModule(AgentScope agentScope) {
		this.agentScope = agentScope;
	}
	
	protected AgentScope createAgentScope() {
		return new AgentScope();
	}
	
	public AgentScope getAgentScope() {
		return agentScope;
	}

	@Override
	protected void configure() {
		bindScope(AgentScoped.class, getAgentScope());
	}

}