/**
 * This file must be included for using Widget-in-JavaScript support.
 * 
 * @version 2011-02-13
 * @author <a href="mailto:r.tennapel@griponservice.nl?SUBJECT=widget.js">R. ten Napel, ing.</a>
 * 
 * @param element			The element to place the response of the request in.
 * @param name				The widget name to use (not the ID, but the type!).
 * @param params			The widget parameters.
 * @param callBack			The callBack function.
 * @param onLoad			Called before the actual request.
 * @param onSuccess			Called when the request was successfull.
 * @param onFailure			Called when the request has failed.
 * @param async				If the Ajax request should be asynchronous or not. 
 **/
function Widget(element, name, params, callBack, onLoad, onSuccess, onFailure, async) {
	// TODO JS:
	// 1. Find all occurences of widget placeholders
	// 2. Create for each placeholder a JS widget
	//    a. Load the CSS (if not loaded yet)
	//    b. Load the JS (if not loaded yet) and retrieve all widget callBacks from the JS
	// 3. Do an Ajax-request to the widget placeholder (deploy widget) and handle all callBacks
	// 4. Check if new widget placeholders are in the widget and go to step 1.
	
	// TODO PHP:
	// 1. Create the PHP widget
	// 2. Load the CSS (if not loaded yet)
	// 3. Write the html (deploy widget)
	// 4. Create a JS widget
	//    a. Load the CSS (if not loaded yet)
	//    b. Load the JS (if not loaded yet) and retrieve all widget callBacks from the JS
	
	// If the element doesn't have a widget create it, else retrieve it:
	var widget;
	if (!element.widget) {
		widget = new function() {
			this.element = element;
			this.name = name;
			this.params = params;
			this.widgetRoot = "./Framework/Widgets/" + name + "/";
			
			// When name is undefined, show debug message:
			if (name == "undefined") { Debugger.write("Name is undefined in widget (" + this.widgetRoot + ") creation!").show(); }
			
			// Load the CSS & JS:
			//GlobalKit.loadCSS(this.widgetRoot + "style.css");
			//GlobalKit.loadJS(this.widgetRoot + "script.js");
			
			// Define the Ajax request URL:
			var url = this.widgetRoot + "index.php";
			if (params != null) {
				url = url + "?" + params;
			}
			
			// Create the Ajax-object:
			var ajax = new Ajax(element, url, callBack, onLoad, onSuccess, onFailure);
			ajax.addCallBack(function() { Widget.handleCallBack(name, params); });
			this.ajax = ajax;
		};
	} else {
		widget = element.widget;
	}
	
	// Store the new name:
	if (name != null) {
		widget.name = name;
	}
	
	// Store the new parameters:
	if (params != null) {
		widget.params = params;
	}
	
	// Store everything:
	element.widget = widget;
	this.element = element;
}

/**
 * Call the Ajax-request for this widget and handle all callBacks.
 **/
Widget.prototype.deploy = function() {
	this.element.widget.ajax.request();
};

/**
 * Refresh the widget contents and alter the parameters if set.
 * 
 * @param params			The new parameters.
 **/
Widget.prototype.refresh = function(params) {
	// Store the new params:
	if (params != null) {
		this.element.widget.params = params;
	}
	
	// Define the Ajax request-URL:
	var url = this.element.widget.widgetRoot + "index.php";
	if (params != null) {
		url = url + "?" + params;
	}
	
	// Alter the URL:
	this.element.widget.ajax.url = url;
	
	// Refresh the widget contents:
	this.deploy();
};

/** The widgets callback, name and class. **/
Widget.widgetNames = new Array();
Widget.callBacks = new Array();
Widget.classes = new Array();

/**
 * Add a callback function to the stack for a specific widget, overwrite if exists.
 * 
 * @param widgetName		The name of the widget where the callback function belongs to.
 * @param callBack			The callback function that must be run when the corresponding widget is loaded / deployed.
 **/
Widget.addCallBack = function(widgetName, callBack) {
	// Retrieve where the widget name is stored:
	var i = this.widgetNames.indexOf(widgetName);
	
	// Add the widget name and callback if not yet stored, else overwrite the callback:
	if (i == -1) {
		this.widgetNames.add(widgetName);
		this.callBacks.add(callBack);
		this.classes.add(function() {});
	} else {
		this.callBacks[i] = callBack;
	}
};

/**
 * Handles the callback function that belongs to the widget with the given widget name. The parameters that the callback function uses are also passed.
 * 
 * @param widgetName		The name of the widget to call the callback function from.
 * @param parameters		The parameters to use with the callback function
 **/
Widget.handleCallBack = function(widgetName, parameters) {
	// Retrieve where the widget name is stored:
	var i = this.widgetNames.indexOf(widgetName);
	
	// If the widget name is stored run the callback:
	if (i > -1 && (typeof this.callBacks[i] == "function")) {
		this.callBacks[i].apply(this, [parameters.url2obj()]);
	}
};

/**
 * Add a class to the stack for a specific widget. The class contains all the JavaScript functions necessary for the widget.
 * 
 * @param widgetName		The name of the widget where the handler belongs to.
 * @param clazz				The class itself with all the widget functions.
 **/
Widget.addClass = function(widgetName, clazz) {
	// Retrieve where the widget name is stored:
	var i = this.widgetNames.indexOf(widgetName);
	
	// Add the widget name, callback and handler if not yet stored, else overwrite the handler:
	if (i == -1) {
		this.widgetNames.add(widgetName);
		this.callBacks.add(function() {});
		this.classes.add(clazz);
	} else {
		this.classes[i] = clazz;
	}
};

/**
 * Retrieve the class with widget functions for a particular widget.
 * 
 * @param widgetName		The name of the widget to retrieve the class for.
 * 
 * @return					The class belonging to the given widget.
 **/
Widget.getClass = function(widgetName) {
	// Retrieve where the widget name is stored:
	var i = this.widgetNames.indexOf(widgetName);
	
	// Return the handler if the widget name exists:
	if (i > -1) {
		return this.classes[i];
	}
	
	alert("No class defined for '" + widgetName + "-Widget'!");
	
	return null;
};

/**
 * Replace an element dummie with an actual widget.
 * 
 * @param element			The element to replace with an actual widget.
 * @param value				The value that holds the widget name and params seperated by a '?'.
 **/
Widget.replace = function(element, value) {
	// If the browser doesn't support element creation & childnodes exit with an error:
	if (!document.createElement || !document.childNodes ) {
		alert("Your browser is not DOM compliant!");
		
		return;
	}
	
	// Split the widget name from the params:
	var parts = value.split("?");
	var widgetName = parts[0];
	var widgetParams = parts.remove(widgetName).join("");
	
	// Create the widget wrapper:
	var widgetWrapper = document.createElement("div");
	widgetWrapper.setAttribute("class", "widget_wrapper");
	
	// Remove the element to replace and place the widget wrapper:
	element.parentNode.insertBefore(widgetWrapper, element);
	element.parentNode.removeChild(element);
	
	// Deploy the widget:
	new Widget(widgetWrapper, widgetName, widgetParams, function() { Widget.replaceAll(document.getElementsByName("widget")); }).deploy();
};

/**
 * Replace (all) widget dummie(s) with actual widget(s).
 * 
 * @param ... widgets			The place holder(s) (array) (<input type="hidden" name="widget" value="name_of_widget?widget_params">).
 **/
Widget.replaceAll = function(widgets) {
	// If widgets is not set, autodetect all elements with name "widget":
	if (widgets == null) {
		widgets = document.getElementsByName("widget");
	// If widgets is a string, use it as the name to detect:
	} else if (typeof(widgets) == "string") {
		widgets = document.getElementsByName(widgets);
	}
	
	// Iterate through all widgets:
	while (widgets.length > 0) {
		var i = widgets.length - 1;
		
		Widget.replace(widgets[i], widgets[i].value);
	}
};
