var ElementStyler = Class.create();

DC = function(x) { return document.createElement(x); }
IDme = function(e) { return parseInt((Event.element(e).id.match(/[0-9]+$/))[0]) }
IDpe = function(element) { return parseInt(element.id.match(/[0-9]+$/)[0]) }

findAnchestor = function (element, ClassName) {
	var parent = element;
	while (parent.className != ClassName && parent.parentNode != null) {
		parent = parent.parentNode;
	}	
	return parent;
}

findParent = function(e, ClassName) {
	
	var parent = Event.element(e);
	return findAnchestor(parent, ClassName);
}

makeAlpha = function (target, value) {
	if (document.all) {
		target.style.filter = 'alpha(opacity=' + value + ')';
	} else
		target.style.opacity = value/100;
}
	
ElementStyler.prototype = {
	
	initialize : function () {
		
		this.shortstr	= [	'L=left',
							'T=top',
							'bc=backgroundColor',
						    'bg=background',
							'bi=backgroundImage',
							'bo=border',
							'boB=borderBottom',
							'boL=borderLeft',
							'boR=borderRight',
							'boT=borderTop',
							'bp=backgroundPosition',
							'cl=color',
							'cu=cursor',
							'dis=display',
							'f=float',
							'fl=float',
							'fs=fontSize',
							'fw=fontWeight',
							'hg=height',
							'lh=lineHeight',
							'mL=marginLeft',
							'mrg=margin',
							'mrgT=marginTop',
							'ov=overflow',
							'pd=padding',
							'ps=position',
							'ta=textAlign',
							'vs=visibility',
							'wd=width',
							'zi=zIndex'
						  ];
		
		this.shortcut 		= Array();
		this.styleinfo 		= Array();
		
		var total = 0;
		for (i=0; i < this.shortstr.length; i++) {
			s = this.shortstr[i].split('=');
			if (s.length != 2) continue;
			this.shortcut[total] = s[0];
			this.styleinfo[total++] = s[1];
		}
		
	},
	
	searchStyle : function (itemSearch) {
		low = 0;
		high = this.shortcut.length - 1;
		while (low <= high) { 
			mid = Math.floor((low + high) / 2);
			if ((''+itemSearch).length = this.shortcut[mid].length && (''+itemSearch).match(''+this.shortcut[mid]))
				return mid;
			else {
				if (itemSearch < this.shortcut[mid])
					high = mid - 1;
				else
					low = mid + 1;
			}
		}
		return -1; 
	},


	stylize : function (htmlelement, style) {
		if (style.length <= 0) return; 
		style = style.split(';');

		element = $(htmlelement);
		
		for(i=0;i<style.length;i++) {
			s = style[i].split(':');
			if (s.length != 2) continue;
			if (s[0].length == 0 || s[1].length == 0) continue;
			var p = this.searchStyle(s[0]);
			if (p == -1) continue
			if (s[1].indexOf('//') == -1) {
				element.style[this.styleinfo[p]] = s[1];
			} else {
				alt = s[1].split('//');
				var bl = element.style[this.styleinfo[p]] == alt[1];
				if (bl) element.style[this.styleinfo[p]] = alt[0];
				else element.style[this.styleinfo[p]] = alt[1];
			}
				
		}
		
	},
	
	addAttribute : function (element, attr) {
		
		attrs = attr.split('&'); 
		for(var i=0;i<attrs.length;i++) { 
			attr = attrs[i]; 
			attr = attr.split('='); 
			element[attr[0]] = attr[1]; 
		}  
	
	}

}

var styler = new ElementStyler;

var elementLinker = function (parentNode, arrayNode) {
	
	// parentNode will be the node where element in arrayNode being attached
	var lastElement = null;
	
	for (var i = 0; i < arrayNode.length; i++) {
		
		if (typeof arrayNode[i] == 'string') {
			if (arrayNode[i] == ':') { 
				continue; // we do not process the separator string
			} else {
				lastElement = elementBuilder(arrayNode[i]);
				$(parentNode).appendChild( lastElement );
			}
		} else {
			if (arrayNode[i] == null) continue;
			
			if (lastElement != null) {
				elementLinker(lastElement, arrayNode[i]);
				lastElement = null;
			} else {
				// check if there is any separator exists, last time we check using isArray method, unfortunately it cannot work in stupid ie
				if (i < arrayNode.length-1 && typeof arrayNode[i+1] == 'string' ) {
					lastElement = arrayNode[i];
				}
				$(parentNode).appendChild($(arrayNode[i]));
			}

		}
		
	}
	
}


htmlbuilder = Class.create();
htmlbuilder.prototype = {
	
	initialize : function (parentElement, callbackFunction) {
		
		this.rootElement = $(parentElement);
		this.level = -1;
		this.rootChildren = [];
		
		this.parentEl = [this.rootElement];
		this.applyCallbackFunction(this.rootElement, callbackFunction);
		
	},
	
	applyCallbackFunction : function (parentElement, callbackFunction) {
			
			/* do some pre callback here */
			this.level++;
			
			if (callbackFunction != undefined) {
				
				this.parentEl[this.level] = parentElement;
				
				/* here.... the secret to localize the 'add' proto function */
				add = this.bindAddElementFunc();
				li = this.bindAddElementFunc('li');
				span = this.bindAddElementFunc('span');
				a = this.bindAddElementFunc('a');
				div = this.bindAddElementFunc('div');
				h1 = this.bindAddElementFunc('h1');
				h2 = this.bindAddElementFunc('h2');
				h3 = this.bindAddElementFunc('h3');
				input = this.bindAddElementFunc('input');
				img = this.bindAddElementFunc('img');
				label = this.bindAddElementFunc('label');
				p = this.bindAddElementFunc('p');
				form = this.bindAddElementFunc('form');
				textarea = this.bindAddElementFunc('textarea');
			
				/* no other choice, have to do this way, otherwise, add function just won't 
				   be recognize by the descendant callback function */
				
				//eval("callbackFunction();");
				callbackFunction();
				
				
				/*
				var callMyAddElementFunc;
				eval("callMyAddElementFunc = "+callbackFunction)
				callMyAddElementFunc();
				*/
				
			}
			
			
			/* some post callback */
			this.level--;
			
	},
	
	bindAddElementFunc : function () {
		
		var obj = this;
		var initParam = $A(this.bindAddElementFunc.arguments);
		
		var addFunc = function () {
			return obj.addElement.apply(obj, initParam.concat($A(addFunc.arguments)) );
		}
		
		return addFunc;
	},
	
	/* for inside func scope add hander, 
			eg. calling add('button', {option:1}, function () {}  ) 
				or add( 'button' );		
	*/
	
	addElement : function () {  // parentElement, elementType, arg_n, arg_n+1, ..........
			
		var args = $A(this.addElement.arguments);
		var parentElement = this.parentEl[this.level];
		var elementType = args.shift();
		
		var content = "";
		if (typeof args[0] == 'string') { // content
			content = args.shift();
		}
		
		var callbackFunction = undefined;
		if (typeof args[args.length-1] == 'function') {
			callbackFunction = args.pop();
		}
		
		
		
		// --------------- execute the callback function
		
		var newElement = DC(elementType);
		if (content.length > 0) {
			newElement.innerHTML = content;
		}
		if (parentElement != undefined) { 
			parentElement.appendChild(newElement);
		}
		if (parentElement == this.rootElement) {
			this.rootChildren[this.rootChildren.length] = newElement;
		}
		
		
		// the className, id, etc.....
		var add_option = [newElement];
		for (var i = 0; i < args.length; i++)
			add_option[add_option.length] = args[i];
		this.applyOption.apply(this, add_option);
		
		
		this.applyCallbackFunction(newElement, callbackFunction);
		
		return newElement;
	
	},
	
	applyOption : function () {
		
		var args = $A(this.applyOption.arguments);
		var element = args[0];
		
		if (args.length <= 1) return;
		
		for (var i in args[1]) {
			element[i] = args[1][i];
		}
		
		if (args.length <= 2) return;
		
		for (var i in args[2]) {
			Event.observe(element, i, args[2][i]);
		}

	}

	

}
