package cz.cuni.amis.pogamut.ut2004.communication.parser;

import java.io.PrintWriter;

import org.junit.Test;

import com.google.inject.Guice;
import com.google.inject.Injector;

import cz.cuni.amis.pogamut.base.communication.connection.IWorldConnection;
import cz.cuni.amis.pogamut.base.communication.connection.socket.ISocketConnectionAddress;
import cz.cuni.amis.pogamut.base.communication.connection.socket.SocketConnectionAddress;
import cz.cuni.amis.pogamut.base.communication.exceptions.CommunicationException;
import cz.cuni.amis.pogamut.base.communication.exceptions.ConnectionException;
import cz.cuni.amis.pogamut.base.communication.exceptions.ParserException;
import cz.cuni.amis.pogamut.base.communication.messages.InfoMessage;
import cz.cuni.amis.pogamut.base.communication.parser.IWorldMessageParser;
import cz.cuni.amis.pogamut.base.communication.parser.IYylexObserver;
import cz.cuni.amis.pogamut.ut2004.communication.connection.CommunicationTestBase;
import cz.cuni.amis.pogamut.ut2004.communication.connection.Server;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InfoMessages;

import static org.junit.Assert.*;

public class TestCase01_ParserTest extends CommunicationTestBase {

	private String[] responses = null;
	
	private String lineEnd = IWorldConnection.DEFAULT_LINE_END;
	
	public String[] getResponses() {
		if (responses != null) return responses;
		responses = InfoMessages.PROTOTYPES;
		return responses;
	}	
	
	@Test
	public void test01_Parser() {
		
		assertTrue("server not started correctly", getServer().consume("Server started"));
		
		Injector injector = Guice.createInjector(new TestModule());
		IWorldMessageParser parser = injector.getInstance(IWorldMessageParser.class);
		YylexObserver yylexObserver = (YylexObserver) injector.getInstance(IYylexObserver.class);
		 
		IWorldConnection<ISocketConnectionAddress> connection = injector.getInstance(IWorldConnection.class);
		
		try {
			connection.connect(new SocketConnectionAddress("127.0.0.1", getServer().getPort()));
		} catch (CommunicationException e) {
			fail("can't connect to the server: " + e.getMessage());
		}
		
		PrintWriter out = null;
		try {
			out = new PrintWriter(connection.getWriter());
		} catch (ConnectionException e) {
			fail("can't get writer for the connection: " + e.getMessage());
		}
		
		out.println(Server.GET_COMMAND);
		out.flush();
		try {
			Thread.sleep(80);
		} catch (InterruptedException e1) {
		}
		assertTrue("server didn't receive GET command", getServer().consume("Received: " + Server.GET_COMMAND));
		
		try {
			parser.start();
		} catch (CommunicationException e1) {
			e1.printStackTrace();
			fail("parser start() error");
		}
		
		for (String message : getResponses()) {
			if (message == null) continue;
			try {
				InfoMessage obj = parser.parse();
				assertTrue("Parser returned null", obj != null);
				assertTrue("Parser parsed wrong message, expected type: "+InfoMessages.PROTOTYPE_MAP.get(message).getName() + ", got: " + obj.getClass().getName(), InfoMessages.PROTOTYPE_MAP.get(message).isInstance(obj));
				assertTrue("server wrong reply", getServer().consume("Sent: " + message));
				assertTrue("parser produced errors", yylexObserver.isClear());
			} catch (CommunicationException e) {
				fail("can't parse next message: " + e.getMessage());
			}			
		}
		
		out.println(Server.QUIT_COMMAND);
		out.flush();
		
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
		}
				
		assertTrue("server didn't receive QUIT command", getServer().consume("Received: " + Server.QUIT_COMMAND));
		assertTrue("server didn't terminate", getServer().consume("Server terminated"));
		
		assertTrue("some server output left", getServer().isClear(true));
		
		
	}
	
	
	

}
