/**
 * Handels facebook.
 * Needs EventHandler.js class.
 *
 * @copyright	Daniel Lehmann, DreamMedia, Berlin, Germany (www.dreammedia-bny.com)
 * @author		Daniel Lehmann <code@dreammedia-bny.com>
 * @version		1.0
 * @date        03.10.2011
 */


 
/**
 * The constructor.
 * The page has to have an element (e.g. a div element) with the id of "fb-root"in which the external facebook library will be loaded.
 *
 * @param	api_key			the application key
 * @param	channel_url		the url of the channel file without the protocol (e.g. without http://), optional
 */
function Facebook(api_key, channel_url) {

	this.api_key = api_key;
	this.channel_url = channel_url;
	
	this.initialised = false;
	this.status = "unknown";
	this.session = null;
	this.response = null;
	
	this.event_handler = new EventHandler();
	
}



////////////////////////////////////////////////////////////////////////////////////////
// facebook events

Facebook.ON_INITIALISED = "on_initialised";
Facebook.ON_LOGGED_IN = "on_logged_in";
Facebook.ON_LOGGED_OUT = "on_logged_out";
Facebook.ON_SESSION_CHANGED = "on_session_changed";
Facebook.ON_STATUS_CHANGED = "on_status_changed";
Facebook.ON_RESPONSE = "on_response";
Facebook.ON_RESPONSE_ERROR = "on_response_error";



////////////////////////////////////////////////////////////////////////////////////////
// facebook status

Facebook.UNKNOWN = "unknown";
Facebook.CONNECTED = "connected";
Facebook.NOT_CONNECTED = "notConnected";
Facebook.NOT_AUTHORIZED = "not_authorized";



////////////////////////////////////////////////////////////////////////////////////////
// facebook call methods

Facebook.POST = "post";
Facebook.GET = "get";
Facebook.DELETE = "delete";



////////////////////////////////////////////////////////////////////////////////////////
// facebook parameters

Facebook.prototype.isInitialised = function() { return this.initialised; }
Facebook.prototype.getStatus = function() { return this.status; }
Facebook.prototype.getSession = function() { return this.session; }
Facebook.prototype.getResponse = function() { return this.response; }
Facebook.prototype.getAccessToken = function() { return (this.session) ? this.session.accessToken : null; }
Facebook.prototype.getSignedRequest = function() { return (this.session) ? this.session.signedRequest : null; }
Facebook.prototype.getUserID = function() { return (this.session) ? this.session.userID : null; }
Facebook.prototype.getSessionExpiretion = function() { return (this.session) ? this.session.expiresIn : null; }



////////////////////////////////////////////////////////////////////////////////////////
// facebook init functions


/**
 * Establishes a facebook connection.
 * Fires Facebook.ON_INITIALISED
 *
 */
Facebook.prototype.init = function() {
	
	var me = this;
	var onInit = function(response) { me.onInit(response); }
	
	window.fbAsyncInit = function() {
		
		if (me.channel_url) FB.init({appId: me.api_key, status: true, cookie: true, xfbml: true, oauth: true, channelURL: document.location.protocol + "//" + me.channel_url});
		else FB.init({appId: me.api_key, status: true, cookie: true, xfbml: true, frictionlessRequests : true,oauth: true});
		
		FB.Event.subscribe('auth.login', function(response) {
		
			me.response = response;
			if (response.status) me.status = response.status;
			if (response.authResponse) me.session = response.authResponse;
			if (!me.status || me.status == null) me.status = "unknown";
		
			me.event_handler.fireEvent(Facebook.ON_LOGGED_IN);
		});
	
		FB.Event.subscribe('auth.logout', function(response) {
		
			me.response = response;
			me.status = "unknown";
			me.session = null;
		
			me.event_handler.fireEvent(Facebook.ON_LOGGED_OUT);
		});
	
		FB.Event.subscribe('auth.authResponseChange.', function(response) {
		
			me.response = response;
			if (response.status) me.status = response.status;
			if (response.authResponse) me.session = response.authResponse;
			if (!me.status || me.status == null) me.status = "unknown";
		
			me.event_handler.fireEvent(Facebook.ON_SESSION_CHANGED);
		
		});
	
		FB.Event.subscribe('auth.statusChange', function(response) {
		
			me.response = response;
			if (response.status) me.status = response.status;
			if (response.authResponse) me.session = response.authResponse;
			if (!me.status || me.status == null) me.status = "unknown";
		
			me.event_handler.fireEvent(Facebook.ON_STATUS_CHANGED);
		
		});
	
		FB.getLoginStatus(onInit, true);
	
		FB.Canvas.setSize();
	
	};
	
	var e = document.createElement('script'); 
	e.async = true;
	e.src = document.location.protocol + '//connect.facebook.net/de_DE/all.js';
	document.getElementById("fb-root").appendChild(e);
	
}



////////////////////////////////////////////////////////////////////////////////////////
// facebook event functions


/**
 * Adds an event listener.
 *
 * @param	event		the name of the event
 * @param	callback	the callback function for the event
 */
Facebook.prototype.addEventListener = function(event, callback) { this.event_handler.addEventListener(event, callback); }

/**
 * Removes an event listener.
 *
 * @param	event		the name of the event
 * @param	callback	the callback function for the event
 */
Facebook.prototype.removeEventListener = function(event, callback) { this.event_handler.removeEventListener(event, callback); }




/**
 * A facebook connection got established.
 *
 */
Facebook.prototype.onInit = function(response) {
	
	// fires twice for some reason?!?
	if (this.initialised) return;
	
	if (!response || response.error) {
		this.event_handler.fireEvent(Facebook.ON_RESPONSE_ERROR);
		return;
	}
	
	if (response.status) this.status = response.status;
	if (response.authResponse) this.session = response.authResponse;
	if (!this.status || this.status == null) this.status = "unknown";
	
	this.initialised = true;
	this.event_handler.fireEvent(Facebook.ON_INITIALISED);
	
}

/**
 * Facebook responded to a call.
 *
 */
Facebook.prototype.onResponse = function(response) {
	
	//this.alertObject(response);
	
	this.response = response;
	
	if (!response || response.error) {
		this.event_handler.fireEvent(Facebook.ON_RESPONSE_ERROR);
		return;
	}
	
	if (response.status) this.status = response.status;
	if (response.authResponse) this.session = response.authResponse;
	if (!this.status || this.status == null) this.status = "unknown";
	
	this.event_handler.fireEvent(Facebook.ON_RESPONSE);
	
}



////////////////////////////////////////////////////////////////////////////////////////
// facebook core functions

/**
 * Calls for the current login status.
 * Fires Facebook.ON_RESPONSE
 *
 * @param	force	force reloading the login status (default false), optional
 */
Facebook.prototype.getLoginStatus = function(force) {
	
	if (!force) force = false;
	else force = true;
	
	var me = this;
	var onResponse = function(response) { me.onResponse(response); }
	
	FB.getLoginStatus(onResponse, force);
}


/**
 * Calls for the login.
 * Fires Facebook.ON_LOGGED_IN
 *
 * @param	permissions		comma separated list of extended permissions
 */
Facebook.prototype.login = function(permissions) {
	
	var me = this;
	var onResponse = function(response) { }
	
	if (!permissions) FB.login(onResponse);
	else FB.login(onResponse, {scope:permissions});
}

/**
 * Calls for the logout.
 * Fires Facebook.ON_LOGGED_OUT
 *
 */
Facebook.prototype.logout = function() {
	
	var me = this;
	var onResponse = function(response) { }
	
	FB.logout(onResponse);
}

/**
 * Calls the api.
 * Fires Facebook.ON_RESPONSE
 *
 * @param	path		the graph (e.g. "/me")
 * @param	method		the method of the call, either Facebook.POST || Facebook.GET (default) || Facebook.DELETE, optional
 * @param	params		parameter for the call (e.g. { limit: 3 }), optional
 */
Facebook.prototype.apiCall = function(path, method, params) {
	
	var me = this;
	var onResponse = function(response) { me.onResponse(response); }
	
	if (method) {
		if (params) FB.api(path, method, params, onResponse);
		else FB.api(path, method, onResponse);
	} else {
		if (params) FB.api(path, params, onResponse);
		else FB.api(path, onResponse);
	}
}

/**
 * Calls a user interface/dialog.
 * Fires Facebook.ON_RESPONSE
 *
 * @param	params		the parameters for the called dialog
 */
Facebook.prototype.uiCall = function(params) {
	
	var me = this;
	var onResponse = function(response) { me.onResponse(response); }
	
	FB.ui(params, onResponse);
}



////////////////////////////////////////////////////////////////////////////////////////
// facebook helper functions

/**
 * Alerts the nested values of an object.
 *
 * @param	object		the object
 * @param	functions	include functions into the output
 */
Facebook.prototype.alertObject = function(object, functions) {
	
	if (typeof functions == "undefined") functions = false;
	
	var createOutput = function(object, output, level, functions) {
		
		var me = createOutput;
		
		if (typeof object != "object") {
			return output += object;
		}
		
		
		var space = "";
		for (var i=0; i<level; i++) space += "    ";
		
		for (var key in object) {
			if (functions || typeof object[key] != "function") output += "\n"+space+key+"("+(typeof object[key])+") : "+me(object[key], "", level+1, functions);
		}
		
		return output;
		
	}
	
	var output = "Object("+(typeof object)+") : ";
	
	alert(createOutput(object, output, 1, functions));
	
}

