/**
 * WORKSPACE NAVIGATION TOOLS
 *
 * Depends on YAHOO.util.History. See also: 
 * - http://developer.yahoo.com/yui/docs/YAHOO.util.History.html
 * - http://developer.yahoo.com/yui/examples/history/history-navbar.html
 *
 * @copyright 2008 Slik BV
 * @version $Id: Workspace.js 5971 2009-10-28 10:02:35Z walter $
 */


/**
 * Declare namespace objects
 */
if (typeof Slik == "undefined" || !Slik) {
	Slik = new Object();
}
if (typeof Slik.Workspace == "undefined" || !Slik.Workspace) {
	Slik.Workspace = new Object();
}


/**
 * Static variable: true if .initialize() has been called
 * @var boolean
 */
Slik.Workspace._initialized = false;

/**
 * Static variable: elementId of container used as a workspace
 * @var string
 */
Slik.Workspace._containerId = null;

/**
 * Static variable: current workspace's last successfully loaded url (relative,
 * e.g. "home/default/b")
 * @var string
 */
Slik.Workspace._currentUrl = null;

/**
 * Callback to call whenever a navigation request completes.
 * A page can set this to have a certain javascript function called when needed.
 * @var function
 */
Slik.Workspace._callbackFunction = null;

/**
 * Static variable: When true, the parameters will be stripped off and put in the post array (workaround for IE 2050 chars bug)
 */
Slik.Workspace._post = false;

/**
 * Turns an absolute link ("http://server/v11/page/") into a relative link ("page/") by checking
 * the current document's BASE tag. If this is not possible because the url is outside the base
 * scope, returns the full original link.
 *
 * @param string url URL string
 * @return string URL string, made relative to the document BASE if possible
 */
Slik.Workspace.urlMakeRelativeToBase = function(url) {	
	var base_href = Slik.Workspace.getBaseHref();	

	if(base_href) {
		url = url.replace(base_href, "");		
	}
	return url;
}

/**
 * Returns the base href, as defined in this document
 *
 * @return string base href
 */
Slik.Workspace.getBaseHref = function() {
	var baseElements = document.getElementsByTagName('base');
	var base_href;

	if (baseElements.length > 0) {
		base_href = baseElements[0].href;
	}	
	return base_href;
}

/**
 * Appends ?embedded=1 or &embedded=1 to a URL link, depending on if it already has query parameters.
 * If the URL already has an "embedded" query parameter, return the original URL.
 *
 * @param string url URL string
 * @return string URL string with embedded=1 parameter added
 */
Slik.Workspace.urlAppendEmbedParameter = function(url) {
	if (url.indexOf("embedded=") == -1) {
		if (url.indexOf("?") == -1) {
			url += "?embedded=1";
		} else {
			url += "&embedded=1";
		}
	}
	return url;
}


/**
 * Throws an Exception if a Slik.Workspace function is called without first initializing it.
 *
 * @return void
 */
Slik.Workspace.assertInitialized = function() {
	if (!Slik.Workspace._initialized) {
		throw new Exception("wsp 001 Workspace not initialized");
	}
}


/**
 * Tries to navigate the workspace to the link provided, adding the navigation action to the
 * browser's history list. Stores the new workspace location in the url hash, e.g. #workspace=page/
 * The function returns false, so that the browser will not follow the original <a href> tag.
 *
 * To use this function, add an onclick event to links using unobtrusive Javascript, or add it
 * directly, for example: <a href="page/" onclick="Slik.Workspace.navigateTo(this)">test</a>
 *
 * @param mixed link Link tag containing the HREF to navigate to, or a link URL string
 * @return boolean false
 */
Slik.Workspace.navigateTo = function(link) {
	
	var url = null;
	if (typeof link == "string") {
		url = link;
	} else if (link.getAttribute) {
		url = link.getAttribute("href");
	} else {
		throw new Exception("wsp 002 Weird link!" + link);
	}
	
	if (url) {
		Slik.Workspace.navigateToUrl(url);
	}
	return false;
}


/**
 * Tries to navigate the workspace to the URL provided, adding the navigation action to the
 * browser's history list. Stores the new workspace location in the url hash, e.g. #workspace=page/
 *
 * @param string url URL string
 * @return void
 */ 
Slik.Workspace.navigateToUrl = function(url) {
	
	Slik.Workspace.assertInitialized();
	
	relativeUrl = Slik.Workspace.urlMakeRelativeToBase(url);
	Slik.log("navigateToUrl: User requested url: '" + url + "', relative url: '" + relativeUrl + "'", "info", "Slik.Workspace");
	try {
		YAHOO.util.History.navigate("workspace", relativeUrl);
	} catch (e) {
		//	We were unable to add our new state to the browser history using YAHOO.util.History.
		//	We will load the new content with XHR into the workspace directly, so the content
		//	is shown always, but the browser back/forward buttons will not work as intended.
		Slik.log("Caught exception: '" + e + "', calling loadInWorkspace directly, but back button will not work", "error", "Slik.Workspace");
		Slik.Workspace.loadInWorkspace(relativeUrl);
	}
	// go to the top of the page again to avoid seeing only the bottom of the new page when
	// the previous page was scrolled down
	scroll(0,0);
}


/**
 * Reloads the current workspace url.
 * 
 * Note: YUI will refuse reloading the same url, so a timestamp is crudely
 * added to the url. Multiple reloads will add multiple ts's
 * @return void
 */
Slik.Workspace.reload = function() {
	var currentUrl = Slik.Workspace.getCurrentUrl();
	if (currentUrl.indexOf("?") == -1) {
		currentUrl += "?";
	} else {
		currentUrl += "&";
	}
	currentUrl += "ts=" + Math.floor(Math.random()*1000000);
	Slik.Workspace.navigateTo(currentUrl);
}


/**
 * Performs a GET request using XHR to fetch the new content at URL.
 *
 * @param string url URL string
 * @return void
 */ 
Slik.Workspace.loadInWorkspace = function(url) {
	function onSuccess(obj) {
		Slik.log("onSuccess: Received content from server, now writing it into container: '" + Slik.Workspace._containerId + "'", "debug", "Slik.Workspace");
		
		//	Set _currentUrl to the new url; during writeElement we may run or include
		//	javascripts that depend on it.
		var originalUrl = url.replace(/\?embedded=1/, "");
		originalUrl = originalUrl.replace(/&embedded=1/, "");
		Slik.Workspace._currentUrl = originalUrl;
		
		Slik.Workspace._cleanupWorkspace();
		Slik.HTTP.writeElement(obj, Slik.Workspace._containerId);
		
		//	Call the callback with true as first parameter for success
		if (Slik.Workspace._callbackFunction) {
			Slik.Workspace._callbackFunction(true, obj);
		}
	}
	
	function onFailure(obj) {
		//	There was a problem performing the XHR call. We redirect the browser to the URL
		//	manually, so they will still see the new content, even though the whole page is
		//	being rebuilt.
		//
		//	This is also called when a user cancels the XHR request because they are
		//	navigating away to another page... Is it possible to detect that and *not*
		//	interfere in that case?
		//
		//	Another problem is that YUI (arbitrarily, sometimes) URI-encodes the URL part
		//	after the "#" character, so *sometimes* we have to decode it...
		//
		//	Disable this code for now... It's more trouble than it's worth.
		//
		//	redirectUrl = url.replace(/embedded=1/, "embedded=0");
		//	Slik.log("onFailure: Failure retrieving content from server, falling back to redirect: " + redirectUrl, "error", "Slik.Workspace");
		//	location.href = redirectUrl;
		
		//	Call the callback with false as first parameter for failure
		if (Slik.Workspace._callbackFunction) {
			Slik.Workspace._callbackFunction(false, obj);
		}
	}
	
	url = Slik.Workspace.urlAppendEmbedParameter(url);
	
	if(Slik.Workspace._post) {
		
		var url_parts = new Array();
		url_parts = url.split('?');
		var uri = url_parts[0];
		var params = (url_parts.length > 0) ? url_parts[1] : '';
		uri += "?ts=" + Math.floor(Math.random()*1000000);
		
		Slik.log("loadInWorkspace: Performing asyncRequest (POST) to url: '" + url + "'", "debug", "Slik.Workspace");
		YAHOO.util.Connect.asyncRequest("POST", uri, {
			success: onSuccess,
			failure: onFailure,
			timeout: 5000
		}, params);	
	} else {
		Slik.log("loadInWorkspace: Performing asyncRequest (GET) to url: '" + url + "'", "debug", "Slik.Workspace");
		YAHOO.util.Connect.asyncRequest("GET", url, {
			success: onSuccess,
			failure: onFailure,
			timeout: 5000
		});	
	}	
}


/**
 * Perform cleanup of an old workspace before overwriting it.
 */
Slik.Workspace._cleanupWorkspace = function() {
	//	Release TinyMCE editors.
	if (typeof tinyMCE != "undefined" && tinyMCE) {
		for (var editorId in tinyMCE.editors) {
			Slik.log("_cleanupWorkspace: Removing TinyMCE control: " + editorId, "info", "Slik.Workspace");
			tinyMCE.execCommand("mceRemoveControl", false, editorId); 
		}
	}
}


/**
 * This method is called on first load of a workspace page, for instance when a user first browses
 * to the application, they have clicked on a bookmark, or if they manually navigated. We must check
 * if there is a remembered state URL, and load it into the workspace.
 *
 * Note: This means that on bookmarked URLs with a workspace hash, there will be two GET requests, e.g.
 * for "/v11/page1#workspace=page2" first the server will serve "page1", and then this method will
 * request "page2". There is currently no way to prevent this.
 *
 * @return void
 */
Slik.Workspace.onFirstLoad = function() {
	//	"workspace" is the name of the registered YAHOO History module
	bookmarkedWorkspaceUrl = YAHOO.util.History.getCurrentState("workspace");	
	documentRelativeUrl    = Slik.Workspace.urlMakeRelativeToBase(document.location.href);
	if (bookmarkedWorkspaceUrl == documentRelativeUrl) {
		Slik.log("onFirstLoad: History state is empty, not loading any url", "info", "Slik.Workspace");
	} else {
		//	Only load the saved workspace URL when it's actually different from the base page that
		//	we already have on screen.
		Slik.log("onFirstLoad: User browsed to a hashed bookmark directly, loading url: '" + bookmarkedWorkspaceUrl + "'", "info", "Slik.Workspace");
		Slik.Workspace.loadInWorkspace(bookmarkedWorkspaceUrl);	
	}
}


/**
 * Adds required state-keeping elements to the HTML document.
 *
 * @return void
 * @todo MSIE requires an Iframe to a working asset; the location of this asset should be tweakable
 */
Slik.Workspace.writeStateElements = function() {
	if (YAHOO.env.ua.ie > 0) {
		document.write('<iframe id="Slik.Workspace.yuiHistoryIframe" src="gfx2/bullet_logout.gif" style="position:absolute; top:0; left:0; width:1px; height:1px; visibility:hidden;"></iframe>');
	}
	document.write('<input id="Slik.Workspace.yuiHistoryField" type="hidden" />');
}


/**
 * Performs initialization of the workspace history manager.
 *
 * @param string containerId Element Id of the workspace container 
 * @param function callbackFunction Optional function to call on request success or failure
 * @param boolean post Whether or not to send the parameters as a post-array (to avoid creating too long url's)
 * @return void
 */
Slik.Workspace.initialize = function(containerId, callbackFunction, post) {
	//	YAHOO.util.History initialization
	Slik.log("initialize: Starting", "debug", "Slik.Workspace");
	
	if(post) {
		Slik.Workspace._post = true;
	}
	
	Slik.Workspace.writeStateElements();
	
	bookmarkedWorkspaceUrl = YAHOO.util.History.getBookmarkedState("workspace");
	documentRelativeUrl    = Slik.Workspace.urlMakeRelativeToBase(document.location.href);
	defaultUrl             = "";
	initialUrl             = bookmarkedWorkspaceUrl || documentRelativeUrl || defaultUrl;
	
	Slik.log("initialize: Registering YAHOO.util.History module", "debug", "Slik.Workspace");
	YAHOO.util.History.register("workspace", initialUrl, function (url) {
		// This is called after calling YAHOO.util.History.navigate,
		// or after the user has trigerred the back/forward button.
		// We cannot distinguish between these two situations.
		Slik.log("History navigate called or user clicked back/forward, url: '" + url + "'", "debug", "Slik.Workspace");
		Slik.Workspace.loadInWorkspace(url);
	});
	
	// Use the Browser History Manager onReady method to initialize the application.
	YAHOO.util.History.onReady(function () {
		Slik.log("onReady: This is the first invocation, calling onFirstLoad", "debug", "Slik.Workspace");
		Slik.Workspace.onFirstLoad();
	});
	
	Slik.Workspace._containerId = containerId;
	
	if (callbackFunction) {
		Slik.Workspace._callbackFunction = callbackFunction;
		Slik.log("CallbackFunction set", "debug", "Slik.Workspace");
	}
	
	// Initialize the browser history management library.
	try {
		Slik.log("initialize: Initializing YAHOO.util.History", "debug", "Slik.Workspace");
		YAHOO.util.History.initialize("Slik.Workspace.yuiHistoryField", "Slik.Workspace.yuiHistoryIframe");
		Slik.Workspace._initialized = true;
	} catch (e) {
		// The only exception that gets thrown here is when the browser is
		// not supported (Opera, or not A-grade) Degrade gracefully.
		// Note that we have two options here to degrade gracefully:
		//   1) Call onFirstLoad. The page will use Ajax/DHTML,
		//      but the back/forward buttons will not work.
		//   2) Initialize our module. The page will not use Ajax/DHTML,
		//      but the back/forward buttons will work. This is what we
		//      chose to do here:
		Slik.log("initialize: Caught exception in initialize: '" + e + "'", "error", "Slik.Workspace");
		Slik.Workspace.loadInWorkspace(initialUrl);
	}
	
}


/**
 * Returns current url loaded in the workspace, defaults to a relative url
 * but when param absolute is set to true, it returns an absolute url
 *
 * @param boolean absolute Returns an absolute url when set to true, defaults to false
 * @return string Current URL
 */
Slik.Workspace.getCurrentUrl = function(absolute) {
	
	if(absolute < 0) {
		absolute = false;
	}
	
	if (Slik.Workspace._currentUrl == null) {
		var result = document.location.href;
	
		if(!absolute) {
			result = Slik.Workspace.urlMakeRelativeToBase(result);
		}
		var p = result.indexOf("#workspace=");
		if (p > -1) {
			result = result.substring(p + 11);
		}
	} else {
		var result = Slik.Workspace._currentUrl;
		
		if(absolute) {
			result = Slik.Workspace.getBaseHref()+result;
		}
	}
		
	return result;
}


/**
 * Returns the current module name.
 *
 * @return string Current module name
 */
Slik.Workspace.getCurrentModuleName = function() {
	var url         = Slik.Workspace.getCurrentUrl();
	var moduleParam = Slik.Util.getUrlParameter(url, "module");
	var regexp      = /^[a-z_]+$/;
	var regexpMatch = regexp.exec(url);
	var slashPos    = url.indexOf("/");		
	var result      = null;
	
	if (regexpMatch) {
		result = url;
		Slik.log("getCurrentModuleName: Regexp match: '" + result + "'", "debug", "Slik.Workspace");
	} else if (moduleParam) {
		result = Slik.Util.getUrlParameter(url, "module");
		Slik.log("getCurrentModuleName: Module parameter match: '" + result + "'", "debug", "Slik.Workspace");
	} else if (slashPos != -1) {
		result = url.substring(0, slashPos);
		Slik.log("getCurrentModuleName: Slashpos match: '" + result + "'", "debug", "Slik.Workspace");
	} else {
		//	No match...
		Slik.log("getCurrentModuleName: No match", "info", "Slik.Workspace");
	}
	return result;
}
