package it.gotoandplay.smartfoxclient.data;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * The Room class stores the properties of each server room.
 * <p>
 * This class is used internally by the {@link it.gotoandplay.smartfoxclient.SmartFoxClient} class;
 * also, Room objects are returned by various methods and events of the SmartFoxServer API.
 * </p>
 * 
 * <p>
 * <b>NOTE</b>: in the provided examples, {@code room} always indicates a Room instance.
 * </p>
 * 
 * @version 1.0.0
 * 
 * @author The gotoAndPlay() Team<br>
 *         <a href="http://www.smartfoxserver.com">http://www.smartfoxserver.com</a><br>
 *         <a href="http://www.gotoandplay.it">http://www.gotoandplay.it</a><br>
 */
public class Room
{
    private int id;
    private String name;
    private int maxUsers;
    private int maxSpectators;
    private boolean temp;
    private boolean game;
    private boolean priv;
    private boolean limbo;
    private int userCount;
    private int specCount;

    private int myPlayerIndex;

    private Map<Integer, User> userList;
    private Map<String, SFSVariable> variables;

    /*
     * Room contructor.
     * 
     * @param id the room id.
     * @param name the room name.
     * @param maxUsers the maximum number of users that can join the room simultaneously.
     * @param maxSpectators the maximum number of spectators in the room (for game rooms only).
     * @param isTemp {@code true} if the room is temporary.
     * @param isGame {@code true} if the room is a "game room".
     * @param isPrivat {@code true} if the room is private (password protected).
     * @param isLimbo {@code true} if the room is a "limbo room".
     * @param userCount
     * @param specCount
     */
    public Room(int id, String name, int maxUsers, int maxSpectators, boolean isTemp, boolean isGame, boolean isPrivate, boolean isLimbo, int userCount, int specCount)
    {
        this.id = id;
        this.name = name;
        this.maxSpectators = maxSpectators;
        this.maxUsers = maxUsers;
        this.temp = isTemp;
        this.game = isGame;
        this.priv = isPrivate;
        this.limbo = isLimbo;

        this.userCount = userCount;
        this.specCount = specCount;
        this.userList = new ConcurrentHashMap<Integer, User>();
        this.variables = new ConcurrentHashMap<String, SFSVariable>();
    }

    /*
     * Add a user to the room.
     * 
     * @param u the {@link User} object.
     * @param id the user id.
     */
    public void addUser(User u, int id)
    {
        userList.put(id, u);

        if(this.game && u.isSpectator())
        {
                specCount++;
        }
        else
        {
                userCount++;
        }
    }

    /*
     * Remove a user from the room.
     * 
     * @param id the user id.
     */
    public void removeUser(int id)
    {
        User u = userList.remove(id);
        
        if(u != null)
        {
            if(this.game && u.isSpectator())
            {
                    specCount--;
            }
            else
            {
                    userCount--;
            }
        }
    }

    /**
     * Get the list of users currently inside the room.
     * The returned list is an java.util.Map with user id(s) as keys.
     * 
     * @return	A Map of {@link User} objects.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * Map&lt;Integer, User&gt; users = room.getUserList();
     *
     * for(int userId : users.keySet())
     * {
     *     System.out.println(users.get(userId));
     * }
     * </pre>
     * 
     * @see #getUser
     * @see User
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public Map<Integer, User> getUserList()
    {
        return this.userList;
    }

    /**
     * Retrieve a user currently in the room.
     * 
     * @param userName the user name of the user to retrieve.
     * 
     * @return A {@link User} object.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * User user = room.getUser("jack");
     * </pre>
     * 
     * @see #getUserList
     * @see User
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */ 
    public User getUser(String userName)
    {
        User user = null;

        for(int userId : userList.keySet())
        {
            User u = this.userList.get(userId);

            if (u.getName().equals(userName))
            {
                    user = u;
                    break;
            }
        }
            
        return user;
    }

    /**
     * Retrieve a user currently in the room.
     * 
     * @param userId the user id of the user to retrieve.
     * 
     * @return A {@link User} object.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * User user = room.getUser("jack");
     * </pre>
     * 
     * @see #getUserList
     * @see User
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */ 
    public User getUser(int userId)
    {
        User user = null;

        user =  userList.get(userId);
        return user;
    }

    /*
     * Reset users list.
     */
    public void clearUserList()
    {
        this.userList = new ConcurrentHashMap<Integer, User>();
        this.userCount = 0;
        this.specCount = 0;
    }

    /**
     * Retrieve a Room Variable.
     * 
     * @param varName the name of the variable to retrieve.
     * 
     * @return The Room Variable.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * String location = room.getVariable("location").getValue();
     * </pre>
     * 
     * @see #getVariables
     * @see SFSVariable
     * @see it.gotoandplay.smartfoxclient.SmartFoxClient#setRoomVariables
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public SFSVariable getVariable(String varName)
    {
        return variables.get(varName);
    }

    /**
     * Retrieve all Room Variables.
     * 
     * @return A {@code Map} containing Room Variables, where the key is the variable name.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * Map&lt;String, RoomVariable&gt; roomVars = room.getVariables();
     *
     * for(String varName : roomVars.keySet())
     * {
     *     System.out.println("Name: " + varName + " | Value: " + roomVars.get(varName));
     * }
     * </pre>
     * 
     * @see #getVariable
     * @see it.gotoandplay.smartfoxclient.SmartFoxClient#setRoomVariables
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public Map<String, SFSVariable> getVariables()
    {
        return variables;
    }

    /*
     * Set the Room Variables.
     * 
     * @param vars Map of Room Variables.
     */
    public void setVariables(Map<String, SFSVariable> vars)
    {
        this.variables = new ConcurrentHashMap<String, SFSVariable>(vars);
    }

    /*
     * Reset Room Variables.
     */
    public void clearVariables()
    {
        this.variables = new ConcurrentHashMap<String, SFSVariable>();
    }

    /**
     * Get the name of the room.
     * 
     * @return The name of the room.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * System.out.println("Room name:" + room.getName());
     * </pre>
     * 
     * @see #getId
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public String getName()
    {
        return this.name;
    }

    /**
     * Get the id of the room.
     * 
     * @return The id of the room.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * System.out.println("Room id:" + room.getId());
     * </pre>
     * 
     * @see #getName
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public int getId()
    {
        return this.id;
    }

    /**
     * A boolean flag indicating if the room is dynamic/temporary.
     * This is always true for rooms created at runtime on client-side.
     * 
     * @return {@code true} if the room is a dynamic/temporary room.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * if (room.isTemp())
     * {
     *     System.out.println("Room is temporary");
     * }
     * </pre>
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public boolean isTemp()
    {
        return this.temp;
    }

    /**
     * A boolean flag indicating if the room is a "game room".
     * 
     * @return {@code true} if the room is a "game room".
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * if (room.isGame())
     * {
     *     System.out.println("This is a game room");
     * }
     * 				
     * </pre>
     * 
     * @see #isLimbo
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public boolean isGame()
    {
        return this.game;
    }

    /**
     * A boolean flag indicating if the room is private (password protected).
     * 
     * @return {@code true} if the room is private.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * if (room.isPrivate())
     * {
     *     System.out.println("Password required for this room");
     * }
     * </pre>
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public boolean isPrivate()
    {
        return this.priv;
    }

    /**
     * Retrieve the number of users currently inside the room.
     * 
     * @return The number of users in the room.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * int usersNum = room.getUserCount();
     * System.out.println("There are " + usersNum + " users in the room");
     * </pre>
     * 
     * @see #getSpectatorCount
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public int getUserCount()
    {
        return this.userCount;
    }

    /**
     * Retrieve the number of spectators currently inside the room.
     * 
     * @return The number of spectators in the room.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * int specsNum = room.getSpectatorCount();
     * System.out.println("There are " + specsNum + " spectators in the room");
     * </pre>
     * 
     * @see #getUserCount
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public int getSpectatorCount()
    {
        return this.specCount;
    }

    /**
     * Retrieve the maximum number of users that can join the room.
     * 
     * @return The maximum number of users that can join the room.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * System.out.println("Max users allowed to join the room: " + room.getMaxUsers());
     * </pre>
     * 
     * @see #getMaxSpectators
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public int getMaxUsers()
    {
        return this.maxUsers;
    }

    /**
     * Retrieve the maximum number of spectators that can join the room.
     * Spectators can exist in game rooms only.
     * 
     * @return The maximum number of spectators that can join the room.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * if (room.isGame())
     * {
     *     System.out.println("Max spectators allowed to join the room: " + room.getMaxSpectators());
     * }
     * </pre>
     * 
     * @see #getMaxUsers
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public int getMaxSpectators()
    {
        return this.maxSpectators;
    }


    /*
     * Set the myPlayerId property.
     * Each room where the current client is connected contains a myPlayerId (if the room is a gameRoom).
     * myPlayerId == -1 ... user is a spectator
     * myPlayerId  > 0  ... user is a player
     * 
     * @param id the myPlayerId value.
     */
    public void setMyPlayerIndex(int id)
    {
        this.myPlayerIndex = id;
    }

    /**
     * Retrieve the player id for the current user in the room.
     * This id is 1-based (player 1, player 2, etc.), but if the user is a spectator its value is -1.
     * 
     * @return The player id for the current user.
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * if (room.isGame())
     * {
     *     System.out.println("My player id in this room: " + room.getMyPlayerIndex());
     * }
     * </pre>
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public int getMyPlayerIndex()
    {
        return this.myPlayerIndex;
    }

    /*
     * Set the {@link #isLimbo} property.
     * 
     * @param b {@code true} if the room is a "limbo room".
     */
    public void setIsLimbo(boolean b)
    {
        this.limbo = b;
    }

    /**
     * A boolean flag indicating if the room is in "limbo mode".
     * 
     * @return {@code true} if the room is in "limbo mode".
     * 
     * <p>
     * Example
     * </p>
     * <pre>
     * if (room.isLimbo())
     * {
     *     System.out.println("This is a limbo room");
     * }
     * </pre>
     * 
     * @see #isGame
     * 
     * @since SmartFoxServer Basic / Pro v1.x.x
     */
    public boolean isLimbo()
    {
        return this.limbo;
    }

    /*
     * Set the number of users in the room.
     * 
     * @param n the number of users.
     */
    public void setUserCount(int n)
    {
        this.userCount = n;
    }

    /*
     * Set the number of spectators in the room.
     * 
     * @param n the number of spectators.
     */
    public void setSpectatorCount(int n)
    {
        this.specCount = n;
    }
}