FacebookSoapboxConnector.STATUS_IDLE = 0x0;
FacebookSoapboxConnector.STATUS_DETECTING = 0x1;
FacebookSoapboxConnector.STATUS_CONNECTED = 0x2;
FacebookSoapboxConnector.STATUS_NOT_CONNECTED = 0x4;
FacebookSoapboxConnector.STATUS_CANCELLED = 0x8;

FacebookSoapboxConnector.TIMEOUT = 2000;

FacebookSoapboxConnector.instance = null;

function FacebookSoapboxConnector() {
	this.apiKey = null;
	this.receiver = null;
	this.swf = null;
	
	this._status = FacebookSoapboxConnector.STATUS_IDLE;
	this._pendingStatus = null;
	this._timeout = null;
}

FacebookSoapboxConnector.getInstance = function() {
	if(FacebookSoapboxConnector.instance == null) {
		FacebookSoapboxConnector.instance = new FacebookSoapboxConnector();
	}
	return FacebookSoapboxConnector.instance;
}

/**
 * Init Facebook Soapbox Connector and detect existing connection. If an
 * existing connection could be detected, call <code>FacebookSoapboxConnector.onSessionReady()</code>
 * with the current session. Otherwise execute ExternalInterface call <code>onFBNotConnected()</code>
 * in the SWF.
 * 
 * @param	apiKey		Facebook API key
 * @param	receiver	URL of cross domain receiver file
 * @param	swf		 	SWF DOM object
 */
FacebookSoapboxConnector.init = function(apiKey, receiver, swf) {
	var instance = FacebookSoapboxConnector.getInstance();
	if (instance.isInitialised()) {
		return;
	}
	
	instance.apiKey = apiKey;
	instance.receiver = receiver;
	instance.swf = swf;

	instance.setConnectionStatus(FacebookSoapboxConnector.STATUS_IDLE);

	FB_RequireFeatures( [ "Api" ], function() {
		FB.init(instance.apiKey, instance.receiver, {
			"ifUserConnected" : function() {
				if (FB.Facebook.apiClient.get_session()) {
					instance.setConnectionStatus(FacebookSoapboxConnector.STATUS_CONNECTED);
				} else {
					instance.setConnectionStatus(FacebookSoapboxConnector.STATUS_NOT_CONNECTED);
				}
			},
			"ifUserNotConnected" : function() {
				instance.setConnectionStatus(FacebookSoapboxConnector.STATUS_NOT_CONNECTED);
			}
		});
	});
}

/**
 * Check if connector is initialised
 * @return	<code>true</code> if <code>FacebookSoapboxConnector.init()</code>
 * 			has successfully been executed
 */
FacebookSoapboxConnector.prototype.isInitialised = function() {
	return this.apiKey != null && this.swf != null;
}

/**
 * Initiate Facebook connection
 * Once the connection has been established, call <code>FacebookSoapboxConnector.onSessionReady()</code>.
 * If the user cancels the connecting process, the ExternalInterface call
 * <code>onFBConnectCancelled</code> will be triggered.
 */
FacebookSoapboxConnector.connect = function() {
	var instance = FacebookSoapboxConnector.getInstance();
	if (!instance.isInitialised()) {
		return;
	}

	FB.Bootstrap.requireFeatures( [ "Connect" ], function() {
		FB.Connect.requireSession(function(e) {
			instance.setConnectionStatus(FacebookSoapboxConnector.STATUS_CONNECTED);
		}, function(e) {
			instance.setConnectionStatus(FacebookSoapboxConnector.STATUS_CANCELLED);
		});
	});
}

/**
 * Close existing Facebook connection. Triggers ExternalInterface method
 * <code>onFBSessionClosed()</code> when logout is complete.
 */
FacebookSoapboxConnector.disconnect = function() {
	var instance = FacebookSoapboxConnector.getInstance();
	if (!instance.isInitialised()) {
		return;
	}

	FB.Bootstrap.requireFeatures( [ "Connect" ], function() {
		FB.Connect.logout();
	});
}

FacebookSoapboxConnector.prototype.setConnectionStatus = function(status) {
	if(this._status == status || this._pendingStatus == status) {
		return;
	}
	
	if(this._timeout) {
		window.clearTimeout(this._timeout);
	}

	this._pendingStatus = status;
	
	/*
	 * When setting the status for the first time, apply the status
	 * immediately. Start timeout otherwise.
	 */
	if(this._status == FacebookSoapboxConnector.STATUS_IDLE) {
		this._applyStatus();
	} else {
		this._timeout = window.setTimeout("FacebookSoapboxConnector.getInstance()._applyStatus()", FacebookSoapboxConnector.TIMEOUT);
	}
}

FacebookSoapboxConnector.showFriendsInvitation = function() {
	var instance = FacebookSoapboxConnector.getInstance();
	if (!instance.isInitialised()) {
		return;
	}
	
	var fb_getInviteFBML = function() {
	    var uid = FB.Facebook.apiClient.get_session().uid;
	    var fbml = "";
	    fbml = 
	    '<fb:fbml>\n' +
	        '<fb:request-form\n'+
	                            //Redirect back to this page
	                            ' action="'+ document.location +'"\n'+
	                            ' method="POST"\n'+
	                            ' invite="true"\n'+
	                            ' type="Red Bull Soapbox Racer"\n' +
	                            ' content="Join Red Bull Soapbox Racer'+
	                            ' <fb:req-choice url=\'http://www.redbullsoapboxracer.com/\' label=\'Check out Red Bull Soapbox Racer\' />"\n'+
	                       '>\n'+
	                       ' <fb:multi-friend-selector\n'+
	                            ' rows="3"\n'+
	                            ' cols="4"\n'+
	                            ' bypass="cancel"\n'+
	                            ' showborder="false"\n'+
	                            ' actiontext="Use this form to invite your friends to connect with Red Bull Soapbox Racer."/>\n'+
	                ' </fb:request-form>'+
	        ' </fb:fbml>';
	    return fbml;
	};

	FB.Bootstrap.requireFeatures( [ "Connect" ], function() {
		var fbml = fb_getInviteFBML() ;
		var dialog = new FB.UI.FBMLPopupDialog("Invite your friends", fbml) ;
		dialog.setContentWidth(630);
		dialog.setContentHeight(600);
		dialog.show();
	});

}

FacebookSoapboxConnector.prototype._applyStatus = function() {
	if(!this.isInitialised()) {
		return;
	}
	
	this._status = this._pendingStatus;

	switch(this._status) {
	case FacebookSoapboxConnector.STATUS_NOT_CONNECTED:
		if (this.swf.onFBNotConnected) {
			this.swf.onFBNotConnected();
		}
		break;
		
	case FacebookSoapboxConnector.STATUS_CONNECTED:
		var session = FB.Facebook.apiClient.get_session();
		if (this.swf.onFBSessionReady) {
			this.swf.onFBSessionReady(session.secret, session.session_key);
		}
		break;
		
	case FacebookSoapboxConnector.STATUS_CANCELLED:
		if (this.swf.onFBConnectCancelled) {
			this.swf.onFBConnectCancelled();
		}
		break;
	}
 }

/**
 * Show Facebooks permission dialogue for the given permissions. Triggers the
 * ExternalInterface method <code>onFBPermissionsGranted()</code> with the
 * granted permissions once the dialoguge has been closed.
 * 
 * @param	permissions	A comma separated list of Facebook permissions the
 * 			application asks for
 */
FacebookSoapboxConnector.showGrantExtendedPermissions = function(permissions) {
	var instance = FacebookSoapboxConnector.getInstance();
	if (!instance.isInitialised()) {
		return;
	}

	FB.Bootstrap.requireFeatures( [ "Connect" ], function() {
		FB.Connect.showPermissionDialog(permissions, function(permissionsGranted) {
			if (instance.swf.onFBPermissionsGranted) {
				instance.swf.onFBPermissionsGranted(permissionsGranted);
			}
		});
	});
}