/*
  Copyright (C) 2006  Pierre ANDREWS

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

function printfire()
{
    if (document.createEvent)
    {
        printfire.args = arguments;
        var ev = document.createEvent("Events");
        ev.initEvent("printfire", false, true);
        dispatchEvent(ev);
    }
}

if((typeof Prototype=='undefined'))
	throw("This script requires the prototype library.");

Object.extend(Object.prototype, {
	clone: function() {
		var newO = new Object();
		for (i in this) {
			newO[i] = this[i];
		}
		return newO;
	}
});

var ObjectiveDegradation = {
	//all the object that can be initialised from the xhtml
	registeredObjects: new Array(),

		/* Constructor:
	 *    - initialise the registeredObjects array
	 *	 - set the onLoad event for the document to initialiase the script
	 */
	initialize: function() {
		Event.observe(window, 'load', ObjectiveDegradation.initPage.bindAsEventListener(ObjectiveDegradation), false);
	},

	/* initialise the page:
	 * - remove all the events from <a> and <submit> to use our own
	 *   event. This is in fact the degradation part as it will only
	 *   remove default html events if javascript is enabled. 
	 */
	initPage: function() {
		
		var links = document.getElementsByTagName("a");
		
		for (i=0; i<links.length; i++){
			var link = links[i];
			if(link.className != "") {
				if(!link.oldOnClick) link.oldOnClick = link.onclick;
				link.onclick = ObjectiveDegradation.callFunction.bindAsEventListener(ObjectiveDegradation);
			}
		}
		var submits = document.getElementsByTagName("input");
		
		for (i=0; i<submits.length; i++){
			var submit = submits[i];
			if((submit.type == 'submit') && (submit.className != "")) {
				submit.type = 'button';
				if(!submit.oldOnClick)  submit.oldOnClick = submit.onclick;
				submit.onclick = ObjectiveDegradation.callFunction.bindAsEventListener(ObjectiveDegradation);
			}
		}
	},
	
	/* call the function corresponding to the element clicked.
	 * This is our main function, the event handler, it will try to build the
	 * correct object and call the function on it.
	 */
	callFunction: function(ev) {
		var element = Event.element(ev);
		var called = false;
		if(element && element.className) {
			var initiatedObject = ObjectiveDegradation.mapClass(element);
			if(initiatedObject) {
				var allClasses = element.className.split(' ');
				for(var i=0;i<allClasses.length;i++) {
					if(typeof initiatedObject[allClasses[i]] == 'function') {
						called = true;
						initiatedObject[allClasses[i]](ev);
					}
				}
			}
			
			//if no function were called, then we have to call the default behaviour.
			if(!called) { 
				if(element.oldOnClick) element.oldOnClick();
				else if(element.form) element.form.submit();
				else if(element.href) location.replace(element.href);
			} else {
				//we have to redo that as some function can have inserted links or forms...
				ObjectiveDegradation.initPage(); 
				return false;
			}
		}
	},

	/* Map an element to a class. This is a recursive function that will go 
	 *  up the DOM tree to find a block corresponding to a registered class 
	 */
	mapClass: function(element) {
		if(element._odObject) { 
			// the element already have a cached class
			// we only need to update its variables.
			ObjectiveDegradation.setVariables(element,element._odObject);
			return element._odObject;
		}
		var matchedClass = false;
		if(element.className) {
			var allClasses = element.className.split(' ');
			for(var i=0;i<allClasses.length;i++) {
				if(ObjectiveDegradation.registeredObjects[allClasses[i]]) {
					matchedClass = true;
					ObjectiveDegradation.createObject(allClasses[i],element);
				}
			}
		}
		if(!matchedClass && element.parentNode) return ObjectiveDegradation.mapClass(element.parentNode);
		return element._odObject;
	},
	
	/* create an object from an element. parameters are the name of the class
	 * and the element that represents that class in the document.
	 */
	createObject: function(classname,element) {
		if(!element._odObject) element._odObject = new Object();
		element._odObject._element = element;
		for(var member in ObjectiveDegradation.registeredObjects[classname]) {
			if(member != 'prototype')
				element._odObject[member] =  ObjectiveDegradation.registeredObjects[classname][member];
		}
		for(var member in ObjectiveDegradation.registeredObjects[classname].prototype) {
			element._odObject[member] =  ObjectiveDegradation.registeredObjects[classname].prototype[member];
		}
		ObjectiveDegradation.setVariables(element,element._odObject);
	},
	
	/* go throught the child of an element (recursively) to initialise 
	 * the variable of the object ir represents.
	 */
	setVariables: function(element,object) {
		var childs = element.childNodes;
		if(childs)
		for(var i=0;i<childs.length;i++) {
			var child = childs[i];
			if(child.className) {
				var classNames = child.className.split(' ');
				var nodeValue;
				for(var j=0;j<classNames.length;j++) {
					if(ObjectiveDegradation.registeredObjects[classNames[j]]) {
						//if we can instanciate this node, we need to do it before everything 
						//(this is where inheritance happens).
						ObjectiveDegradation.createObject(classNames[j],child);
						nodeValue = child._odObject;
					} else if(!nodeValue && ((typeof object[classNames[j]]) != 'undefined')) {
						//check if it is needed to compute a value for this node.
						if(child.form) {
							//if this element is a member of a form
							nodeValue = Form.Element.getValue(child);
						} else if(child.href) {
							//if the element is a link, it could represent a link to another object
							var matches= /^.*#(.+)$/.exec(child.href);
							if(matches) {
								var rel = $(matches[1]);
								if(rel) {
									var allClasses = rel.className.split(' ');
									for(var k=0;k<allClasses.length;k++) {
										if(ObjectiveDegradation.registeredObjects[allClasses[k]]) {
											if(!rel._odObject && (rel != element)) {
												ObjectiveDegradation.createObject(allClasses[k],rel);
											}
											nodeValue = rel._odObject;
										}
									}
								}
							} else {
								nodeValue = child.href;
							}
						} else {
							//if this is a simple node, its value is its html content (beware)
							object[classNames[j]] = child.innerHTML;
							nodeValue = child.innerHTML;
						}
					}
					//we are done setting the node value, lets asign it to something if 
					//this attribute exists in the object.
					if(((typeof object[classNames[j]]) != 'undefined')
					   && (typeof object[classNames[j]] != 'function')) {
						object[classNames[j]] = nodeValue;
					} else if(typeof object[classNames[j]] != 'function'){
						//if the element is not a variable/property of our object, 
						//go down the tree to look for variables.
						ObjectiveDegradation.setVariables(child,object);
					}
				}
				nodeValue = undefined;
			} else {
				//if the element have no class, 
				//go down the tree to look for variables.
				ObjectiveDegradation.setVariables(child,object);					
			}
		}
	},
	
	/*Public static: */

	copyToNode: function(obObject, node) {
		node._odObject = obObject.clone();
		node._odObject._element = node;		
	},

	register: function(list) {
		for(objectID in list)
		    ObjectiveDegradation.registeredObjects[objectID] = list[objectID];
	}
}

ObjectiveDegradation.initialize();
