/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bricks;

import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 * <p>Web service manages multiplayer game sessions for Brick Mobile Game.</p>
 * <p>
 * forkflow is the following:
 * <li>init player using {@link #initPlayer(String)}</li>
 * <li>The first initialized player is set into queue.
 * If there is somebody in the queue already, He is removed from the queue and game is started.</li>
 * <li>Get your player order position ( 1, 2)
 * or 0 if there is no opponent yet: {@link #startGame(String)}</li>
 * <li>Post your steps by using {@link #postMove}</li>
 * <li>get opponents noves using {@link #getOppMove}</li>
 * <li>Inform server that game is over: {@link #gameOver}</li>
 * </p>
 * @author avk
 */
@WebService()
public class BricksWebService {

    private List<String> waitingList = new Vector<String>();
    private Map<String, Game> games = new Hashtable<String, Game>();

    /**
     * Inits player Id.
     * @param levelId Is not really used in this version.
     * @return player ID, that will be used in the next methods to authenticate user
     *
     */
    @WebMethod(operationName = "initPlayer")
    public String initPlayer(@WebParam(name = "levelId")
            final String levelId) {
        String id = generatePlayerId();
        if (waitingList.isEmpty()) {
            waitingList.add(id);
        } else {
            String oppId = waitingList.get(0);
            Game game = Game.createInstance(oppId, id);

            waitingList.remove(oppId);
            games.put(oppId, game);
            games.put(id, game);
        }
        return id;
    }

    /**
     * Starts the game
     * @param playerId
     * @return player position in the order:
     * 0 if game is not started and no position yet (@throws Exception
     * @see Game.PLAYER_ORDER_NO_GAME).
     * 1 if the first player (@see Game.PLAYER_ORDER_1),
     * 2 if the second player (@see Game.PLAYER_ORDER_2)
     */
    @WebMethod(operationName = "startGame")
    public int startGame(
            @WebParam(name = "playerId") final String playerId) throws Exception {
        if (games.containsKey(playerId)) {
            return games.get(playerId).getPlayerOrder(playerId);
        } else if (waitingList.contains(playerId)) {
            //player is still waiting for an opponent
            return Game.PLAYER_ORDER_NO_GAME;
        }
        throw new Exception("initPlayer first");
    }

    /**
     *
     * @param playerId
     * @param steps
     * @return
     * @throws java.lang.Exception
     */
    @WebMethod(operationName = "postMove")
    public boolean postMove(
            @WebParam(name = "playerId") final String playerId,
            @WebParam(name = "steps") final String steps) throws Exception {
        Game game = games.get(playerId);
        if (game == null) {
            throw new Exception("startGame first");
        }
        if (!playerId.equals(game.getLastPlayedId())) {
            game.setLastMove(playerId, steps);
            return true;
        }
        return false;
    }

    /**
     *
     * @param playerId
     * @return
     * @throws java.lang.Exception
     */
    @WebMethod(operationName = "getOppMove")
    public String getOppMove(
            @WebParam(name = "playerId") final String playerId) throws Exception {

        Game game = games.get(playerId);
        if (game == null) {
            throw new Exception("startGame first");
        }

        if (!playerId.equals(game.getLastPlayedId())) {
            return game.getLastSteps();
        }
        return null;
    }

    /**
     * Web service operation
     * @param playerId 
     * @throws Exception
     */
    @WebMethod(operationName = "gameOver")
    public void gameOver(
            @WebParam(name = "playerId") final String playerId) throws Exception {
        Game game = games.get(playerId);
        if (game == null) {
            throw new Exception("startGame first");
        }
        boolean remove = game.gameOver();
        if (remove){
            games.remove(game.getPlayer1Id());
            games.remove(game.getPlayer2Id());
        }
    }

    private String generatePlayerId() {
        String rand = generateRandom();
        while (waitingList.contains(rand) || games.containsKey(rand)) {
            rand = generateRandom();
        }
        return rand;
    }

    private static String generateRandom() {
        return String.valueOf(Math.random());
    }
}
