package org.ggp.base.player.request.factory;

import java.util.ArrayList;
import java.util.List;

import org.ggp.base.player.gamer.Gamer;
import org.ggp.base.player.request.factory.exceptions.RequestFormatException;
import org.ggp.base.player.request.grammar.AbortRequest;
import org.ggp.base.player.request.grammar.AnalyzeRequest;
import org.ggp.base.player.request.grammar.PingRequest;
import org.ggp.base.player.request.grammar.PlayRequest;
import org.ggp.base.player.request.grammar.Request;
import org.ggp.base.player.request.grammar.StartRequest;
import org.ggp.base.player.request.grammar.StopRequest;
import org.ggp.base.util.game.Game;
import org.ggp.base.util.gdl.factory.GdlFactory;
import org.ggp.base.util.gdl.factory.exceptions.GdlFormatException;
import org.ggp.base.util.gdl.grammar.GdlConstant;
import org.ggp.base.util.gdl.grammar.GdlTerm;
import org.ggp.base.util.symbol.factory.SymbolFactory;
import org.ggp.base.util.symbol.grammar.Symbol;
import org.ggp.base.util.symbol.grammar.SymbolAtom;
import org.ggp.base.util.symbol.grammar.SymbolList;


public final class RequestFactory
{
	public Request create(Gamer gamer, String source) throws RequestFormatException
	{
		try
		{
			SymbolList list = (SymbolList) SymbolFactory.create(source);
			SymbolAtom head = (SymbolAtom) list.get(0);

			String type = head.getValue().toLowerCase();
			if (type.equals("play"))
			{
				return createPlay(gamer, list);
			}
			else if (type.equals("start"))
			{
				return createStart(gamer, list);
			}
			else if (type.equals("stop"))
			{
				return createStop(gamer, list);
			}
			else if (type.equals("abort"))
			{
			    return createAbort(gamer, list);
			}
			else if (type.equals("ping"))
			{
			    return createPing(gamer, list);
			}
			else if (type.equals("analyze"))
			{
				return createAnalyze(gamer, list);
			}
			else
			{
				throw new IllegalArgumentException("Unrecognized request type!");
			}
		}
		catch (Exception e)
		{
			throw new RequestFormatException(source, e);
		}
	}

	private PlayRequest createPlay(Gamer gamer, SymbolList list) throws GdlFormatException
	{
		if (list.size() != 3)
		{
			throw new IllegalArgumentException("Expected exactly 2 arguments!");
		}

		SymbolAtom arg1 = (SymbolAtom) list.get(1);
		Symbol arg2 = list.get(2);

		String matchId = arg1.getValue();
		List<GdlTerm> moves = parseMoves(arg2);

		return new PlayRequest(gamer, matchId, moves);
	}

	private StartRequest createStart(Gamer gamer, SymbolList list) throws GdlFormatException
	{
		if (list.size() < 6)
		{
			throw new IllegalArgumentException("Expected at least 5 arguments!");
		}

		SymbolAtom arg1 = (SymbolAtom) list.get(1);
		SymbolAtom arg2 = (SymbolAtom) list.get(2);
		SymbolList arg3 = (SymbolList) list.get(3);
		SymbolAtom arg4 = (SymbolAtom) list.get(4);
		SymbolAtom arg5 = (SymbolAtom) list.get(5);

		String matchId = arg1.getValue();
		GdlConstant roleName = (GdlConstant) GdlFactory.createTerm(arg2);
		String theRulesheet = arg3.toString();
		int startClock = Integer.valueOf(arg4.getValue());
		int playClock = Integer.valueOf(arg5.getValue());
		
		// TODO: There may be more than five arguments. These may be worth
		// parsing, once we find a meaningful way to handle them. They aren't
		// yet standardized, but, for example, one might be the URL of an XSL
		// stylesheet for visualizing a state of the game, or the URL for the
		// game on a repository server.

		Game theReceivedGame = Game.createEphemeralGame(theRulesheet);
		return new StartRequest(gamer, matchId, roleName, theReceivedGame, startClock, playClock);
	}

	private StopRequest createStop(Gamer gamer, SymbolList list) throws GdlFormatException
	{
		if (list.size() != 3)
		{
			throw new IllegalArgumentException("Expected exactly 2 arguments!");
		}

		SymbolAtom arg1 = (SymbolAtom) list.get(1);
		Symbol arg2 = list.get(2);

		String matchId = arg1.getValue();
		List<GdlTerm> moves = parseMoves(arg2);

		return new StopRequest(gamer, matchId, moves);
	}

    private AbortRequest createAbort(Gamer gamer, SymbolList list) throws GdlFormatException
    {
        if (list.size() != 2)
        {
            throw new IllegalArgumentException("Expected exactly 1 argument!");
        }

        SymbolAtom arg1 = (SymbolAtom) list.get(1);
        String matchId = arg1.getValue();

        return new AbortRequest(gamer, matchId);
    }	
    
    private PingRequest createPing(Gamer gamer, SymbolList list) throws GdlFormatException
    {
        if (list.size() != 1)
        {
            throw new IllegalArgumentException("Expected no arguments!");
        }

        return new PingRequest(gamer);
    }
    
    private AnalyzeRequest createAnalyze(Gamer gamer, SymbolList list) throws GdlFormatException
    {
		if (list.size() != 3)
		{
			throw new IllegalArgumentException("Expected exactly 2 arguments!");
		}

		SymbolAtom arg1 = (SymbolAtom) list.get(1);
		SymbolAtom arg2 = (SymbolAtom) list.get(2);

		String theRulesheet = arg1.toString();
		int analysisClock = Integer.valueOf(arg2.getValue());
		
		Game theReceivedGame = Game.createEphemeralGame(theRulesheet);
		return new AnalyzeRequest(gamer, theReceivedGame, analysisClock);
    }    

	private List<GdlTerm> parseMoves(Symbol symbol) throws GdlFormatException
	{
		if (symbol instanceof SymbolAtom)
		{
			return null;
		}
		else
		{
			List<GdlTerm> moves = new ArrayList<GdlTerm>();
			SymbolList list = (SymbolList) symbol;

			for (int i = 0; i < list.size(); i++)
			{
				moves.add(GdlFactory.createTerm(list.get(i)));
			}

			return moves;
		}
	}
}
@@ -3096,49 +3096,51 @@
 ));%0A
-%09%09
 %0A%09%09// 
-TODO: There may be more than five
+For now, there are only five standard
  arg
@@ -3151,275 +3151,94 @@
 ts. 
-These may be worth%0A%09%09// parsing, once we find a meaningful way to handle them. They aren't%0A%09%09// yet standardized, but, for example, one might be the URL of an XSL%0A%09%09// stylesheet for visualizing a state of the game, or the URL for the%0A%09%09// game on a repository server
+If there are any%0A%09%09// new standard arguments added to START, they should be added here
 .%0A%0A%09

Clean up a TODO in the RequestFactory.