/**
 * $Id: discovery-auth.js 23927 2009-05-05 11:02:04Z alucas $
 * 
 * Project:		DNI User Authentication: Core Javascript Component
 * Version:		2.0.0
 * Author:		alucas
 * 
 */


if (typeof(discovery) == "undefined") var discovery = {};
if (typeof(discovery.authentication) == "undefined") discovery.authentication = {};
if (typeof(discovery.USER) == "undefined") discovery.USER = {};
if (typeof(discovery.PAGE) == "undefined") discovery.PAGE = {};
function augment(obj, args, func) { func.apply(obj, args) }





//#USER AUTH SERVICES

discovery.authentication.getServices = function() {
	
	/**
	 * Returns a mapping of all available
	 * User Authentication Services
	 */
	
	this.getServices = function() {
		
		if (userInfo.isLoggedIn())
			_services['PROFILE_WIDGET'] = _PROFILE_WIDGET
					+ "?CASTGC="
					+ userAuth.getAuthToken();
		else
			_services['PROFILE_WIDGET'] = _PROFILE_WIDGET;	
			
		return _services;
	}
	
	//Private Vars
		
	var page = discovery.PAGE;
	var userInfo = discovery.USER.info;
	var userAuth = discovery.USER.auth;
	var _PREFIX;
	
	if (page.isExternal())
		_PREFIX = "http://login." + page.getRootDomain();
	else
		_PREFIX = "";
	
	var _services = {
		'LOGIN': 			_PREFIX + "/ua-fe/login.shtml",
		'LOGOUT':			_PREFIX + "/ua-fe/logout.shtml",
		'REGISTER':			_PREFIX + "/ua-fe/register-step-1.shtml",
		'UPDATE_PROFILE':	_PREFIX + "/ua-fe/cas/update-profile.shtml",
		'UPGRADE_PROFILE':	_PREFIX + "/ua-fe/upgrade-profile.shtml",
		
		'FACEBOOK':			{
			'LOGIN':			_PREFIX + "/ua-fe/facebook/login.shtml",
			'CONNECT':			"/ua-fe/facebook/connect.shtml",
			'DISCONNECT':		"/ua-fe/facebook/disconnect.shtml",
			'LOGIN_ASYNC':		"/ua-fe/facebook/login-service.shtml"
		}
	}
	var _PROFILE_WIDGET = "/ua-fe/profile-widget.shtml";
	
	return this.getServices();	
}



//#USER OBJECT

augment({}, [discovery.USER], function(module) {
	
	
	//#PUBLIC INTERFACE
	
	//USER INFO METHODS
	var info = {
	
		isFacebookUser: _isNull,
		isLoggedInOnFacebook: _isNull,
		
		isLoggedIn: function() {
			
			if (document.cookie.match(_CAS_COOKIE)) {
				return true
			} else {
				return false
			}
		},
	
		isLoggedInViaFacebook: function() {
		
			var returnValue = null;
			
			if (info.isLoggedIn()) {
				var type;
				if ((type = document.cookie.match(_COOKIE_TYPE))
						&&(type[1] == "facebook")) 
					returnValue = true;
				else
					returnValue = false;	
			}
			return returnValue;
		}
	}
	
	
	//AUTHENTICATION METHODS
	var auth = {

		getAuthToken: function() {
			
			var cookie = document.cookie.match(_CAS_COOKIE);
			if (cookie)
				cookie = cookie[1];
			
			return cookie;
		},

		setAuthToken: function(value) {
			
			document.cookie = "CASTGC=" + value + "; expires="
				+ new Date(new Date().getFullYear()+20, 1, 1).toUTCString()
				+ "; domain=" + "." + page.getRootDomain() + ";"
				+ "path=/;";
		}
	}
	
	//USER ACTION METHODS
	var action = {
			
		postFacebookStory: function(data) {
		
			var postFeed = function(data) {
				if (authModule.fb.isReady()) {
					var config = authModule.fb.getFacebookAPIConfig();
					
					authModule.fb.connectUser(function() {
						
						FB.Connect.showFeedDialog(
								config.TEMPLATE_BUNDLE_ID,
								data);
					});
				}
			}
			
			this.postFacebookStory = function(data) {
		
				var returnValue = false;

				var fbData = {
					'title':		data.title,
					'body':			data.body,
					'full_body':	data.full_body
				}
				
				if (data.image)
					fbData.images = [{
						src: data.image.src,
						href: data.image.url
					}];
				
				if (!info.isLoggedIn())
					authModule.fb.logUserInAsync(function() {
						postFeed(fbData);
					});
				else
					postFeed(fbData);
			}
			
			return this.postFacebookStory(data);
		}
	}
	
	//#END PUBLIC INTERFACE
		
	module.info = info;
	module.auth = auth;
	module.action = action;
	
	//STUBS	
	var _isNull = function() { return null }
	
	//EXTERNALS
	
	var page = discovery.PAGE;	
	var authModule = discovery.authentication;
	
	//PRIVATE VARS
	
	var _COOKIE_TYPE = /^.*CASTGC=.*?#([^;]*)/;
	var _CAS_COOKIE = /^.*CASTGC=([^;]*)(?:;|$)/;
	
});



//#PAGE OBJECT

augment({}, [discovery.PAGE, discovery], function(module, namespace) {
	
	
	
	/**
	 * Returns the domain of the current page
	 * 
	 * @return	{String}
	 */
	module.getDomain = function() {
		
		var returnValue = document.location.href
				.replace(/^.*\/\/([^\\/]*).*$/, "$1");
		
		module.getDomain = function() { return returnValue }
				
		return returnValue;
	}
	
	
	/**
	 * Returns the root domain of the current domain
	 * [ Domain Detection (MUST BE UPDATED FOR NEW TLDS) ]
	 * 
	 * @return	{String}
	 */
	module.getRootDomain = function() {
		
		var returnValue = module.getDomain()
				.replace(/^.*\.([^\.]+)(\.co\.uk|\.com|\.de)$/, "$1$2");
		
		module.getRootDomain = function() { return returnValue }
				
		return returnValue;
	}
	
	
	/**
	 * Returns the current subdomain
	 * 
	 * @return	{String}
	 */
	module.getSubdomain = function() {
		
		var returnValue;
		
		if (!module.isStaging())
			returnValue = module.getDomain()
					.replace(/^(?:origin(?:\.|\-)|)(.*)\.[^\.]+(?:\.co\.uk|\.com|\.de)$/, "$1");
		else
			returnValue = module.getDomain()
					.replace(/^(?:origin\-|)(.*)\-[^\-]+(?:\-co\-uk|\-com|\-de).*$/, "$1");
			
		
		module.getSubdomain = function() { return returnValue }
				
		return returnValue;
	}
	
	
	/**
	 * Returns the domain of the
	 * parent site
	 */
	module.getSiteDomain = function() {
		
		var returnValue, domain = module.getDomain();
		
		if (!module.isSubdomain()) {
			returnValue = domain;
		} else {
			
			if (!module.isStaging())
				returnValue = domain
						.replace(/^(?:origin(?:\.|\-)|).*\.([^\.]+(\.co\.uk|\.com|\.de))$/,
								"www.$1");
			else
				returnValue = domain
						.replace(/^(?:origin\-|).*\-([^\-]+(\-co\-uk|\-com|\-de).*)$/,
								"www-$1");
		}
		
		module.getSiteDomain = function() { return returnValue }
		
		return returnValue;
	}
	
	
	/**
	 * Checks whether the current page is
	 * hosted externally
	 * 
	 * @return	{Boolean}
	 */
	module.isExternal = function() {
		
		var returnValue;
		
		switch(module.getSubdomain()) {
			case "www":
			case "login":
				returnValue = false;
				break;
			default:
				returnValue = true;
		}
		
		module.isExternal = function() { return returnValue }
				
		return returnValue;
	}
	
	
	/**
	 * Check whether the current page is a discovery
	 * subdomain or the main domain
	 * [ Domain Detection (MUST BE UPDATED FOR NEW TLDS) ]
	 * 
	 * @return	{Boolean}
	 */
	module.isSubdomain = function() {
		
		var returnValue;
		
		if (module.getSubdomain() == "www")
			returnValue = false;
		else
			returnValue = true;
		
		module.isSubdomain = function() { return returnValue }
		
		return returnValue;
	}
	
	
	/**
	 * Checks whether the current environment
	 * is staging
	 * 
	 * @return	{Boolean}
	 */
	module.isStaging = function() {
		
		var returnValue = null;
		
		if (module.getRootDomain()
				== "discoveryisispreview2.com")
			returnValue = true;
		else
			returnValue = false;
		
		return returnValue;
	}
	
	
	/**
	 * @void
	 * Takes action to reload the current page
	 * [ STUB. In future may notify user for decision ]
	 */
	module.needsReload = function() { document.location.reload() }
	
	
	/**
	 * @void
	 * Reloads the discovery hat asynchronously
	 * 
	 * @param	{Function}	_callback
	 */
	module.reloadHat = function(_callback) {
		
		if ((namespace.site)&&(namespace.site.ui)
				&&(namespace.site.ui.hat))
			namespace.site.ui.hat
					.reloadProfileInfo(_callback);
	}
	
	//Stubs
	
	var _isTrue = function() { return true }
	var _isFalse = function() { return false }
	var _isNull = function() { return null }
	
})



//#USER AUTHENTICATION ACTIONS

augment({}, [discovery.authentication, discovery],
		function(module, namespace){
	
	
	//PUBLIC INTERFACE
	
	/**
	 * Initialises package
	 */
	module.init = function() {
	
		module.fb.init();
	}
	
	/**
	 * Sends a user to login and returns them to
	 * the current page or specified return URL
	 * 
	 * @param	{String}	returnUrl
	 */
	module.logUserIn = function(returnUrl) {

		module.gotoService(services().LOGIN,
				returnUrl);
	}
	
	/**
	 * Sends a user to login and returns them to
	 * the current page or specified return URL
	 * 
	 * @param	{String}	returnUrl
	 */
	module.logUserOut = function(returnUrl, force) {
		
		if ((force)||(!userInfo.isLoggedInViaFacebook()))
			module.gotoService(services().LOGOUT,
					returnUrl);
		else
			module.fb.logUserOut(returnUrl);
	}
	
	/**
	 * Sends a user to a service along with
	 * a returnUrl
	 */
	module.gotoService = function(service, returnUrl, cancel) {
		
		var location = document.location.href;
		if (!returnUrl)
			var returnUrl = getReturnUrl(location);
		
		if (!returnUrl)
			returnUrl = location;
		
		var url = buildUrl(
			service, {'returnUrl': returnUrl});
		
		if (!cancel)
			document.location.href = url;
		else
			return url;
	}
	
	/**
	 * Pings a discovery user authentication service
	 */
	module.callService = function(service, callback) {
		
		httpGet(service, callback);
	}
	
	/**
	 * Logs a user in using an asynchronous log in
	 * service
	 */
	module.logUserInAsync = function(asyncService, callback, fallbackService) {
		
		if (!page.isSubdomain()) {
			httpGet(asyncService, function(xhr){
				var codeRange = xhr.status.toString()[0];
				if ((codeRange == 2)||(codeRange == 3)) {
					dynamicLogin(xhr.responseText||null);
					if (callback) callback();
				}
			})
		} else if (fallbackService) {
			module.gotoService(fallbackService);
		}
	}
	
	/**
	 * Adds a function to be called after an asynchronous
	 * login to determine whether to reload the page.
	 * The function must return <code>true</code> if
	 * a full page refresh is needed.
	 * 
	 * @param	{Function}	handler
	 */
	module.addReloadHandler = function(handler) {
		
		_loginCallbacks.push(handler);
	}
	
	
	//PRIVATE METHODS
		
	var dynamicLogin = function(cookie) {
		if (!dynamicLoginDisabled()) {
		
			if (cookie != null) {
				userAuth.setAuthToken(cookie);
			
				switch(processCallbacks(_loginCallbacks)) {
					case true:
						page.needsReload();
						break;				
					case false:
						page.reloadHat();
						break;
				}
			} else {
				disableDynamicLogin();
			}
		}
	}
	
	var processCallbacks = function(callbacks) {
		
		var callbackLen = callbacks.length;
		if (callbackLen > 0) {
			
			for (var i=callbackLen-1,k; k=callbacks[i]; i--)
				if(k()) return true;
		}
		
		return false;
	}
	
	var disableDynamicLogin = function() {
		document.cookie = getDloginDisableCookie();
	}
	
	var dynamicLoginDisabled = function() {
		
		if (document.cookie.indexOf(_DISABLE_DLOGIN_COOKIE) != -1) {
			return true;
			
		} else return false;
	}
	
	var getDloginDisableCookie = function() {
		
		var date = new Date();
		date.setMinutes(date.getMinutes() + 30);
		
		return _DISABLE_DLOGIN_COOKIE + " expires="
				+ date.toUTCString() + ";";
	}
	
	
	//EXTERNALS
	
	var services = module.getServices;
	var httpGet = discovery.common.xhr.httpGet;
	var buildUrl = discovery.common.url.buildUrl;
	var page = namespace.PAGE;
	var userInfo = namespace.USER.info;
	var userAuth = namespace.USER.auth;
	
	
	//PRIVATE VARS
	
	var _DISABLE_DLOGIN_COOKIE = "UA_disableDynamicLogin=1;";
	var _loginCallbacks = [];
	
	
	//STUBS
	
	var getReturnUrl = function(_url) {

		/**
		 * Takes a URL and extracts a returnUrl
		 */
		getReturnUrl = function(url) {
			
			var returnValue;
			if ((returnValue = url.match(regex))
					&&(returnValue[1] !== "")) {
				
				returnValue = unescape(returnValue[1]);
			} else {
				
				returnValue = null;
			}
			
			return returnValue;			
		}
		
		//Private Vars
		
		var regex = /.*\?.*?returnUrl=([^&]*).*/;
		
		return getReturnUrl(_url);
		
	}
	
});





//#FACEBOOK API MODULE

discovery.authentication.fb = {}


augment({},
		[discovery.authentication.fb, discovery.authentication, discovery],
		function(module, namespace, domain){
	
	
	
	//#FACEBOOK API CONFIG
	
	module.getFacebookAPIConfig = function() {

			module.getFacebookAPIConfig = function() {
				
				var keys = _keyMap[rootDomain];
				
				if (keys)
					return {
						API_KEY:				keys[0], 
						CHANNEL_URL:			_CHANNEL_URL,
						TEMPLATE_BUNDLE_ID:		keys[1]
					}
				else return null;
			}
			
			
			//Private Vars
					
			var _CHANNEL_URL = "/resources/ua/html/fb-channel.shtml";
			
			
			//Domain Mapping
			
			var rootDomain = page.getRootDomain();
			
			var _keyMap = {
				'discoverychannel.co.uk': [
					"8096b3c68f455f4549585aa7d27fba70", "86435115165"
				],
				'tudiscovery.com': [
					"fb0b1b1dc97a0c49ca1d2aa318e3f79c", "69178429227"
				],
				'discoverybrasil.com': [
					"8561c807d559aeb7dac87a173396b178", "74341205215"
				],
				'dmax.de':	[
					"8614b1c0e091256f05f99cd0f9db793a", "71700747969"
				],
				'tudiscoverykids.com': [
					"", ""
				],
				'discoverykidsbrasil.com': [
					"", ""
				],
				'discoveryisispreview2.com': [
					"791b86152b4fa04d1a6b898085e095c0", "76636530934"
				],
				'localhost.com': [
				  	"474ba5fabc091c5d13857f68f9f52294", ""
				]
			}
			
			/* 
			 * if we're on an external page,
			 * make channel url absolute
			 */
			if (page.isExternal())
				_CHANNEL_URL = "http://"
						+ page.getSiteDomain()
						+ _CHANNEL_URL;

			
			return module.getFacebookAPIConfig();	
	}
	
	
	//#MODULE INITIALISATION
	
	module.init = function() {
		
		var config = module.getFacebookAPIConfig();
		
		if (config) {
			
			FB.init(config.API_KEY, config.CHANNEL_URL, {
				'doNotUseCachedConnectState': true
			});
			
			var failFallback = window.setTimeout(InitFailed, 10000);
			
			FB.ensureInit(function(){
				
				module.isReady = _isTrue;
				window.clearTimeout(failFallback);
				getFBStatus(module.syncStatus);
			})
			
		} else {
			
			InitFailed("No Config");
		}
	}
	
	
	//#FB STATUS
	
	var getFBStatus = function(callback) {
		
		FB.Connect.get_status().waitUntilReady(function(result) {
			
			setFBStatus(result);
			callback();
		});
	}
	
	var setFBStatus = function(result) {
		
		switch (result) {
			case 1:
				userInfo.isFacebookUser = _isTrue;
				userInfo.isLoggedInOnFacebook = _isTrue;
				break;
				
			case 2:
				userInfo.isFacebookUser = _isTrue;
				userInfo.isLoggedInOnFacebook = _isFalse;
				break;
				
			default:
				userInfo.isFacebookUser = _isFalse;
		}
	}
	
	
	//#SYNC STATUS
	
	module.syncStatus = function(returnUrl) {
		
		if (userInfo.isFacebookUser()) {
		
			if (userInfo.isLoggedInOnFacebook()) {
				if (!userInfo.isLoggedIn())
					module.logUserInAsync();
			
			} else if (userInfo.isLoggedInViaFacebook() == true) {
				
				namespace.logUserOut(null, true);
			}
		}
	}
	
	
	//# ACTIONS
	
	module.logUserIn = function(returnUrl) {
		
		if (module.isReady())
			FB.Connect.requireSession(function() {
				
				module.hasEmail(function() {
					namespace.gotoService(services().FACEBOOK
							.LOGIN, returnUrl);
				});
			});
	}
	
	module.logUserInAsync = function(callback) {

		if ((userInfo.isFacebookUser())
				&&(module.isReady()))
			FB.Connect.requireSession(function() {
				
				module.hasEmail(function() {
					namespace.logUserInAsync(
							services().FACEBOOK.LOGIN_ASYNC, callback,
							services().FACEBOOK.LOGIN
						);
				});
			});
	}	
	
	module.logUserOut = function(returnUrl) {
		
		if ((userInfo.isLoggedInViaFacebook())
				&&(module.isReady()))
			FB.Connect.logoutAndRedirect(
					namespace.gotoService(services().LOGOUT,
						returnUrl, true));
	}
	
	module.connectUser = function(callback, skipLogin) {
		
		if (module.isReady())
			if (userInfo.isLoggedIn())
				FB.ensureInit(function() {
					
					FB.Connect.requireSession(function() {
						namespace.callService(services().FACEBOOK
								.CONNECT, callback);
					})
				})
			else
				module.logUserInAsync(function() {
					namespace.callService(services().FACEBOOK
							.CONNECT, callback);
				});
	}
	
	module.disconnectUser = function(callback) {
	
		if ((userInfo.isLoggedIn())
				&&(module.isReady()))
			FB.Connect.requireSession(function() {
				
				namespace.callService(services().FACEBOOK
						.DISCONNECT, callback);
			});
	}
	
	module.hasEmail = function(callback) {
		
		if (module.isReady())
			FB.Facebook.apiClient
					.users_hasAppPermission("email", function(result){
						
				if (result == 1)
					callback(true);
				else
					FB.Connect.showPermissionDialog("email",
							function(result){
						if (callback)
							if (result == 1) callback(true);
							else callback(false);
					});
			}, true);
	}
	
	
	//EXCEPTIONS
	
	var InitFailed = function(label) {
		var msg = "Failed to initialise Facebook API";
		if (label) msg += " [" + label + "]";
		throw new Error(msg);
	}
	
	
	//STUBS
	
	var _isTrue = function() { return true }
	var _isFalse = function() { return false }
	var _isNull = function() { return null }
	
	module.isReady = _isFalse;
	
	
	//EXTERNALS
	
	var userInfo = domain.USER.info;
	var userAuth = domain.USER.auth;
	var page = domain.PAGE;
	var services = namespace.getServices;
	
	

});

