package sfs.cluster.lobby.handlers.internal;

import it.gotoandplay.smartfoxserver.SmartFoxServer;
import it.gotoandplay.smartfoxserver.data.Room;
import it.gotoandplay.smartfoxserver.data.User;
import it.gotoandplay.smartfoxserver.events.InternalEventObject;
import it.gotoandplay.smartfoxserver.exceptions.LoginException;
import it.gotoandplay.smartfoxserver.extensions.AbstractExtension;
import it.gotoandplay.smartfoxserver.extensions.ExtensionHelper;

import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;

import org.json.JSONObject;

import sfs.cluster.lobby.ClusterLobbyExtension;
import sfs.cluster.lobby.DataStore;
import sfs.cluster.lobby.data.ClusterEvent;
import sfs.cluster.lobby.data.ClusterUser;

/**
 * Handles the user login in the Lobby room
 */
public class LoginHandler implements InternalHandler
{
	// this is used for creating guest ids
	static AtomicInteger autoId = new AtomicInteger(0);
	
	ClusterLobbyExtension parentExtension;
	Logger log;
	
	
	public LoginHandler(AbstractExtension parentExtension)
    {
	    this.parentExtension = (ClusterLobbyExtension) parentExtension;
	    log = SmartFoxServer.log;
    }
	
	// Handle the event
	public void handleInternalEvent(InternalEventObject ieo) throws Exception
	{
	    String name = ieo.getParam("nick");
	    boolean success = false;
	    
	    // Check empty names
	    if (name.equals(""))
	    	name = "GuestUser__" + autoId.getAndIncrement();
	    	
	    String pass = ieo.getParam("pass");
	    SocketChannel channel = (SocketChannel) ieo.getObject("chan");
	    
	    log.info("Login attempt: " + name + ", pass" + ", " + channel);
	    
	    // Prepare the response for the user in JSON format
	    JSONObject jso = new JSONObject();
	    jso.put("_cmd", "login");
	    
	    try
	    {
	    	// Check duplicate names
		    if (parentExtension.getUserByName(name) != null)
		    	throw new LoginException("Duplicate name!");
	    	
		    // Login user 
	    	User u = ExtensionHelper.instance().canLogin(name, pass, channel, parentExtension.getOwnerZone());
	    	jso.put("name", u.getName());
		    jso.put("id", u.getUserId());
		    jso.put("result", "OK");
		    
		    // Create cluster user
		    ClusterUser newUser = new ClusterUser(name);
		    newUser.setNodeId(parentExtension.getNodeId());
		    newUser.setLocalUID(u.getUserId());
		    
		    parentExtension.addUser(newUser);
		    
		    success = true;
	    }
	    catch (LoginException logError) 
	    {
			jso.put("result", "KO");
			jso.put("error", logError.getMessage());
		}
	    
	    // Send login response
	    LinkedList recipients = new LinkedList();
	    recipients.add(channel);
	    
	    parentExtension.sendResponse(jso, -1, null, recipients);
	    
	    
	    if (success)
	    {
	    	// Update user count for this node
	    	parentExtension.incrementUserCount();
	    	
	    	// Send room list, if success
	    	sendRoomList(channel);
	    	
	    	// parameters
	    	Map params = new HashMap();
	    	params.put("_cmd", "fListUpdate");
	    	params.put("friend", name);
	    	params.put("status", 1);
	    	
	    	// Send friend list update
	    	Map<String, LinkedList<Object>> updates = parentExtension.getFriendListManager().getClientsToUpdate(name);
	    	
	    	// Local update
	    	LinkedList localUsersToUpdate = updates.remove(parentExtension.getNodeId());
	    	
	    	if (localUsersToUpdate != null)
	    	{
	    		JSONObject fListUpdate = new JSONObject(params);
	    		parentExtension.sendResponse(fListUpdate, -1, null, localUsersToUpdate);
	    	}
	    	
	    	// Remote update
	    	for (Map.Entry<String, LinkedList<Object>> entry : updates.entrySet())
	    	{
	    		LinkedList<Object> nameList = entry.getValue();
	    		String nodeName = entry.getKey();
	    		
	    		if (nameList != null)
	    		{
	    			ClusterEvent event = new ClusterEvent( ClusterEvent.ON_FRIEND_LIST_UPDATE );
	    			event.getParams().put("recipients", nameList);
	    			event.getParams().put("jso", params);
	    			
	    			DataStore.instance().dispatchClusterEvent(event, nodeName);
	    		}
	    	}
	    }
	}
	
	/**
	 * We send a custom user list
	 * @param who	the recipient
	 */
	private void sendRoomList(SocketChannel who)
	{
		final Room lobbyRoom = parentExtension.getLobbyRoom();
		final StringBuilder response = new StringBuilder("<msg t='sys'><body action='rmList' r='-1'>");
		
		response.append("<rmList>")
		.append("<rm id='").append(lobbyRoom.getId())
        .append("' priv='0'")
        .append(" temp='0'")
        .append(" game='0'")
        .append(" ucnt='0'")
        .append(" lmb='1'")
        .append(" maxu='").append(lobbyRoom.getMaxUsers())
        .append("'>")
        .append("<n><![CDATA[").append(lobbyRoom.getName()).append("]]></n>")
        .append("</rm>")
        .append("</rmList>")
        .append("</body></msg>");
		
		LinkedList recipients = new LinkedList();
		recipients.add(who);
		
		ExtensionHelper.instance().sendGenericMessage(response.toString(), null, recipients);
	}
}
