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

import cz.cuni.amis.pogamut.base.agent.AgentState;
import cz.cuni.amis.pogamut.base.agent.AgentStateType;
import cz.cuni.amis.pogamut.base.agent.IAgent;
import cz.cuni.amis.pogamut.base.exceptions.PogamutException;
import java.util.logging.Level;

import java.util.logging.Logger;
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.ut2004.bot.MindlessSyncBot;
import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
import cz.cuni.amis.pogamut.ut2004.testbase.ServerTestBase;
import cz.cuni.amis.pogamut.ut2004.factory.guice.UT2004ServerModule;
import cz.cuni.amis.pogamut.ut2004.factory.guice.UTGuiceSyncFactory;
import cz.cuni.amis.utils.Job;

import cz.cuni.amis.utils.collections.ElementListener;
import cz.cuni.amis.utils.flag.FlagListener;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import static org.junit.Assert.*;

public class TestCase01_ServerConnectTest extends ServerTestBase {

    UT2004Server tempServer;

    @Before
    public void startUp() {
        IAgentFactory<ISocketConnectionAddress> factory = new GuiceAgentFactory(new UT2004ServerModule());

        try {
            tempServer = (UT2004Server) factory.newAgent(new SocketConnectionAddress("localhost", 3001));
        } catch (Exception e) {
            e.printStackTrace();
            fail("Can't create new agent: " + e.getMessage());
        }
        tempServer.getLogger().addConsoleHandlersToAllCategories();
        tempServer.getLogger().setLevel(Level.ALL);

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

    @After
    public void tearDown() {
        final UT2004Server server = tempServer;

        Job<Boolean> stopServer = new Job() {

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

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

  @Test
    public void test01_ServerConnect() {
        AgentStateType state = tempServer.getAgentState().getFlag().getType();
        if (!state.isOKState()) {
            fail("Server not initialized properly. Server is in wrong state " + state.toString());
        }
    }
  
    @Test
    public void testDataProvidedByServer() {
        if (tempServer.getAvailableMaps() == null || tempServer.getAvailableMaps().size() == 0) {
            fail("No maps received.");
        }
        if (tempServer.getPlayers() == null) {
            fail("Player list not initialized.");
        }

// TODO test other data

    }

    @Test
    public void eventListening() throws InterruptedException, PogamutException {

        final CountDownLatch latch = new CountDownLatch(1);

        ElementListener<Player> playerConnected = new ElementListener<Player>() {
            @Override
            public void elementChanged(Player elem, boolean added) {
                latch.countDown();
            }
        };
        tempServer.getPlayers().addCollectionListener(playerConnected);
        final long start = System.currentTimeMillis();
        
        tempServer.getAgentState().addListener(new FlagListener<AgentState>() {

            public void flagChanged(AgentState changedValue) {
                if (changedValue.getType().isOKState()) {
                    long dif = System.currentTimeMillis() - start;
                    System.out.print(dif);
                }
            }
        });
        IAgent agent = new UTGuiceSyncFactory(MindlessSyncBot.class).newAgent(new SocketConnectionAddress("localhost", 3000));
        agent.start();
        latch.await(5, TimeUnit.SECONDS);
        if (latch.getCount() != 0) {
            fail("No player connected event received in 5 seconds.");
        }
    // connect player and try if we will receive the event

    }
}
