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

import cz.cuni.amis.pogamut.base.communication.commands.ICommandListener;
import cz.cuni.amis.pogamut.base.communication.messages.CommandMessage;
import java.util.concurrent.Future;
import java.util.logging.Level;


import org.junit.Test;

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.factory.IAgentFactory;
import cz.cuni.amis.pogamut.base.factory.guice.GuiceAgentFactory;
import cz.cuni.amis.pogamut.base.factory.guice.PogamutAgentModule;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.TurnTo;
import cz.cuni.amis.pogamut.ut2004.testbase.ServerTestBase;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
import cz.cuni.amis.utils.Job;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.*;

public class BotTestCase extends ServerTestBase {

    protected PogamutAgentModule module = null;
    protected CountDownLatch commandSendLatch = new CountDownLatch(1);
    /**
     * Listens for Rotation command.
     */
    protected ICommandListener commandListener = new ICommandListener() {

        public void notify(CommandMessage event) {
            if (event instanceof TurnTo) {
                commandSendLatch.countDown();
            }
        }
    };

    @Test
    public void test01_RunMindlessBotAtLocalhost() {
        if (module == null) {
            fail("test case module not specified!");
        }

        IAgentFactory<ISocketConnectionAddress> factory = new GuiceAgentFactory(module);

        AbstractUT2004Bot tempAgent = null;
        try {
            tempAgent = (AbstractUT2004Bot) factory.newAgent(new SocketConnectionAddress("localhost", ucc.getGbPort()));
        //tempAgent = (AbstractUT2004Bot) factory.newAgent(new SocketConnectionAddress("10.0.19.100", 3000));
        } catch (Exception e) {
            e.printStackTrace();
            fail("Can't create new agent: " + e.getMessage());
        }
        final AbstractUT2004Bot agent = tempAgent;

        agent.getLogger().addConsoleHandlersToAllCategories();
        agent.getLogger().setLevel(Level.ALL);

        Future<Boolean> agentStarted = null;

        // register command listener
        agent.getAct().addCommandListener(commandListener);

        try {
            agent.start();
        } catch (Exception e) {
            agent.kill();
            fail("Can't start the agent: " + e.getMessage());
        }

        try {
            //while (true) Thread.sleep(1000);
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            agent.kill();
            fail("Sleep interrupted while giving the agent time to parse Self message: " + e.getMessage());
        }

        if (agent.getWorldView().getAll(Self.class).size() == 0) {
            agent.kill();
            fail("Self not present in the WorldView after 2 secs.");
        }
        try {
            int waitTime = 5;
            if (!commandSendLatch.await(waitTime, TimeUnit.SECONDS)) {
                agent.kill();
                fail("Bot failed to send any command in " + waitTime + " seconds.");
            }
        } catch (InterruptedException ex) {
            
            fail("Sleep interrupted while giving the agent time to send a command: " + ex.getMessage());
        }

        Job<Boolean> stopBot = new Job() {

            @Override
            protected void job() throws Exception {
                agent.stop();
                setResult(true);
            }
        };
        stopBot.startJob();
        try {
            stopBot.await(100000);
        } catch (InterruptedException e) {
            agent.kill();
            fail("Interrupted during waiting for the agent to stop.");
        }

        if (!stopBot.isFinishedOk()) {
            agent.kill();
            fail("Could not stop the agent in 2 secs.");
        }

    }
}
