package sfs3.extensions.examples.spacewar2.handlers.requests;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import com.smartfoxserver.SmartFoxServer;
import com.smartfoxserver.annotations.Instantiation;
import com.smartfoxserver.annotations.MultiHandler;
import com.smartfoxserver.api.ISFSApi;
import com.smartfoxserver.api.ISFSGameApi;
import com.smartfoxserver.bitswarm.data.TransportType;
import com.smartfoxserver.entities.Room;
import com.smartfoxserver.entities.User;
import com.smartfoxserver.entities.data.ISFSObject;
import com.smartfoxserver.entities.data.SFSObject;
import com.smartfoxserver.entities.invitation.Invitation;
import com.smartfoxserver.entities.invitation.InvitationCallback;
import com.smartfoxserver.entities.invitation.SFSInvitation;
import com.smartfoxserver.entities.variables.SFSUserVariable;
import com.smartfoxserver.entities.variables.UserVariable;
import com.smartfoxserver.exceptions.SFSJoinRoomException;
import com.smartfoxserver.extensions.BaseClientRequestHandler;
import com.smartfoxserver.extensions.SFSExtension;

import sfs3.extensions.examples.spacewar2.SW2RoomExtension;
import sfs3.extensions.examples.spacewar2.util.Constants;

@Instantiation
@MultiHandler
public class InitRequestHandler extends BaseClientRequestHandler
{
	@Override
	public void handleClientRequest(User sender, ISFSObject params, TransportType transportType)
	{
		// Get the request id
		String requestId = params.getString(SFSExtension.MULTIHANDLER_REQUEST_ID);
		
		// CLIENT READY TO PLAY 
		if (requestId.equals(Constants.REQ_INIT_READY))
			onUserReady(sender);
		
		// SHIP SELECTED BY PLAYER
		else if (requestId.equals(Constants.REQ_INIT_SHIP))
			onShipSelected(sender, params);
		
		// USER INVITE BUDDY
		else if (requestId.equals(Constants.REQ_INIT_INVITE))
			onBuddyInvited(sender, params);
	}
	
	/**
	 * Checks if game should start.
	 * If the game is not yet started, checks if the minimum number of players is reached; if yes, sends the start countdown notification to all clients.
	 */
	private void onUserReady(User user)
	{
		SW2RoomExtension roomExt = (SW2RoomExtension) this.getParentExtension();
		ISFSApi sfsApi = roomExt.getApi();
		Room room = roomExt.getParentRoom();
		
		//----------------------------------------
		
		// Mark user as ready by means of User properties
		user.setProperty("ready", true);
		
		// Send level, starships and weapons configuration to client
		ISFSObject configuration = new SFSObject();
		configuration.putSFSObject(Constants.CONFIG_LEVEL, roomExt.getLevelCfg());
		configuration.putSFSObject(Constants.CONFIG_STARSHIPS, roomExt.getStarshipsCfg());
		configuration.putSFSObject(Constants.CONFIG_WEAPONS, roomExt.getWeaponsCfg());
		
		sfsApi.sendExtensionResponse(Constants.RESP_CONFIG, configuration, user, room, TransportType.TCP);
		
		// Check if game is already started, as set in Room Variables
		boolean gameStarted = room.getVariable(Constants.ROOMVAR_GAME_STATE).getIntValue() == Constants.GAMESTATE_RUNNING;
		
		if (!gameStarted)
		{
			// Get reference to countdown task from Room Extension
			ScheduledFuture<?> countdownTask = roomExt.getCountdownTask();
			
			// Check if final countdown is already in progress
			if (countdownTask != null)
			{
				// Get remaining time
				int delay = (int) countdownTask.getDelay(TimeUnit.SECONDS);
				
				// Send countdown start notification to user
				ISFSObject resParams = new SFSObject();
				resParams.putInt("delay", delay);
				
				sfsApi.sendExtensionResponse(Constants.RESP_COUNTDOWN, resParams, user, room, TransportType.TCP);
			}
			else
			{
				// Get game settings
				ISFSObject settings = roomExt.getSettings();
				
				// Retrieve minimum number of players to start the game from game settings
				int minPlayers = settings.getInt(Constants.SETTING_MIN_PLAYERS);
				
				// Get list of ready users
				List<User> readyUsers = roomExt.getReadyUsers();
				
				if (readyUsers.size() >= minPlayers)
				{
					// Start countdown
					roomExt.startCountdown();
					
					// Send countdown start notification to ready users
					ISFSObject resParams = new SFSObject();
					resParams.putInt("delay", settings.getInt(Constants.SETTING_GAME_START_SECS));
					
					sfsApi.sendExtensionResponse(Constants.RESP_COUNTDOWN, resParams, readyUsers, room, TransportType.TCP);
				}
			}
		}
		else
		{
			// Nothing to do; the user will be added to the game as soon as they select the starship (see onShipSelected method below)
		}
	}
	
	/**
	 * Saves the selected starship model in User Variables.
	 * If the game is already started, adds user to the game.
	 */
	private void onShipSelected(User user, ISFSObject params)
	{
		SW2RoomExtension roomExt = (SW2RoomExtension) this.getParentExtension();
		ISFSApi sfsApi = roomExt.getApi();
		Room room = roomExt.getParentRoom();
		
		//----------------------------------------
		
		// Save selected starship model in User Variables
		UserVariable shipModelUV = new SFSUserVariable(Constants.USERVAR_SHIP_MODEL, params.getString("model"));
		List<UserVariable> userVars = new ArrayList<UserVariable>();
		userVars.add(shipModelUV);
		
		sfsApi.setUserVariables(user, userVars);
		
		// Check if game is already started; if yes add user to the game
		boolean gameStarted = room.getVariable(Constants.ROOMVAR_GAME_STATE).getIntValue() == Constants.GAMESTATE_RUNNING;
		
		if (gameStarted)
		{
			// Send start notification to all ready clients
			sfsApi.sendExtensionResponse(Constants.RESP_START, null, user, room, TransportType.TCP);
			
			// Add user to game
			roomExt.addStarship(user);
		}	
	}
	
	/**
	 * Invites user's buddy to join the game.
	 */
	private void onBuddyInvited(User user, ISFSObject params)
	{
		SW2RoomExtension roomExt = (SW2RoomExtension) this.getParentExtension();
		ISFSGameApi sfsGameApi = SmartFoxServer.getInstance().getAPIManager().getGameApi();
		Room room = roomExt.getParentRoom();
		
		//----------------------------------------
		
		// Retrieve user to be invited (buddy name = user name)
        User invitee = room.getZone().getUserByName(params.getString("buddy"));
        
        if (invitee != null)
        {
        	Invitation invitation = new SFSInvitation(user, invitee, 15);
        	
        	ISFSObject invParams = new SFSObject();
        	invParams.putInt("roomId", room.getId());
        	invParams.putInt("zoneId", room.getZone().getId());
        	invParams.putString("level", room.getVariable("gameLevel").getStringValue());
        	
        	invitation.setParams(invParams);
        	
        	// Send the invitation 
        	sfsGameApi.sendInvitation(invitation, new InvitationCallback()
			{
				@Override
				public void onRefused(Invitation invObj, ISFSObject params)
				{
					// Nothing to do; we could notify the inviter
				}
				 
				@Override
				public void onExpired(Invitation invObj)
				{
					// Nothing to do; we could notify the inviter
				}
				
				@Override
				public void onAccepted(Invitation invObj, ISFSObject params)
				{
					ISFSApi sfsApi = SmartFoxServer.getInstance().getAPIManager().getSFSApi();
					int zoneId = invObj.getParams().getInt("zoneId");
					int roomId = invObj.getParams().getInt("roomId");
					
					Room room = SmartFoxServer.getInstance().getZoneManager().getZoneById(zoneId).getRoomById(roomId);
					
					// Join invited player in Room
					try
					{
						sfsApi.joinRoom(invObj.getInvitee(), room);
					}
					catch (SFSJoinRoomException e)
					{
						// Nothing to do
					}
				}
			 });
        }
	}
}
