

var gRequestList = [];
var gRequestCount =0;

function addRequest(request) {
	gRequestList.push(request);
	gRequestCount++;
	requestModified();
}

function removeRequest(request) {
	for (var ii in gRequestList) {
		if (gRequestList[ii] === request) {
			gRequestList[ii] = null;
		}
	}
	requestModified();
}

function requestModified() {
	var nbr =0;
	for (var ii in gRequestList) {
		if (gRequestList[ii] !== null) {
			nbr++;
		}
	}
	
	var requestInfoWidget = gWidgets["requestInfo"];
	if (requestInfoWidget) {
		requestInfoWidget.updateInfo(nbr,gRequestCount);
	}
}


//*******************************

function actionDone(request) {
	if (request.readyState == 4) {
		if (request.status == 200) {
			//alert(request.responseText);
			var responseXML = request.responseXML;
			if (!responseXML) {
				if (!request.responseText) {
					alert("Empty response");
				} else {
					alert(request.responseText);
				}
			} else {
				var root = responseXML.documentElement;
				if (root.tagName == "error") {
					alert(root.getAttribute("message"));
				} else if (root.tagName != "ok") {
					alert("error unknown response: "+root.tagName);
				} else {
					//alert("root: "+root.tagName);
					var responseWidgetId = root.getAttribute("response_widget_id");
					var responseMethodName = root.getAttribute("response_method_name");
					if (responseWidgetId && responseMethodName) {
						var widget = gWidgets[responseWidgetId];
						if (widget && widget[responseMethodName]) {
							var isOK = widget[responseMethodName](root);
							if (!isOK) {
								alert("error in reaction");
							}
						}
					}
				}
			}
		} else {
			alert("status: "+request.statusText);
		}
		removeRequest(request);
	}
}



function DowAction() {
}

DowAction.prototype.doAction = function(controlElem) {
	alert("must override doAction");
}

DowAction.prototype.doReaction = function(element , responseXML) {
	return true;
}

DowAction.prototype.createDomDocument = function() {
	if (typeof DOMParser == "function") { //Firefox3 bug with createDocument (never UTF-8 even when document is) IE7 will fail with just if(DOMParser)
		var xmlStr = '<?xml version="1.0" encoding="UTF-8"?><dummy/>';
		var parser = new DOMParser();
		var domDocument = parser.parseFromString(xmlStr,"application/xml");
		domDocument.removeChild(domDocument.firstChild);
		return domDocument;
	} else if (document.implementation && document.implementation.createDocument) {
		return document.implementation.createDocument(null,null, null);
	} else if (window.ActiveXObject) {
		return new ActiveXObject("Microsoft.XMLDOM");
	}
}

DowAction.prototype.createEmptyAction = function(method,doc) {
	var outDoc;
	
	if (doc) {
		outDoc=doc;
	} else {
		outDoc = this.createDomDocument();
	}
	
	var action = outDoc.createElement("action");
	outDoc.appendChild(action);
	
	action.setAttribute("method",method);
	if (typeof player_id != "undefined") action.setAttribute("player_id",player_id);
	if (typeof login_id != "undefined") action.setAttribute("login_id",login_id);
	if (typeof page_path != "undefined") action.setAttribute("page_path",page_path);
	
	return action;
}

DowAction.prototype.sendAction = function(actionDoc,responseMethodName) {
	var request = new XMLHttpRequest();
	try {
		request.open("POST", "/php/action.php", true);
		request.onreadystatechange = function() {actionDone(request)};
		addRequest(request);
		
		if (responseMethodName) {
			actionDoc.documentElement.setAttribute("response_method_name",responseMethodName);
		}
		if (this.uid) {
			actionDoc.documentElement.setAttribute("response_widget_id",this.uid);
		}
	
		request.send(actionDoc);
	} catch (ex) {
		alert(ex);
	}
}



//*******************************



function DomParser() {
	this.type="DomParser";
}
DomParser.prototype = new DowAction;

window.gDomParser = new DomParser();

DomParser.prototype.previousElement = function(rootElem) {
	var cur = rootElem.previousSibling;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE) {
			return cur;
		}
		cur = cur.previousSibling;
	}
	return null;
}

DomParser.prototype.nextElement = function(rootElem) {
	var cur = rootElem.nextSibling;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE) {
			return cur;
		}
		cur = cur.nextSibling;
	}
	return null;
}


DomParser.prototype.findElement = function(rootElem , tagName,className) {
	var cur = rootElem.firstChild;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE && cur.tagName == tagName) {
			if (!className || this.hasElementClass(cur , className)) {
				return cur;
			}
		}
		cur = cur.nextSibling;
	}
	return null;
}


DomParser.prototype.childIterator = function(rootElem , tagName , callback) {
	var cur = rootElem.firstChild;
	var next;
	while (cur) {
		next = cur.nextSibling; //do be able to delete (or insert) while iterating
		if (cur.nodeType == Node.ELEMENT_NODE && cur.tagName.toLowerCase() == tagName) {
			callback(cur);
		}
		cur = next;
	}
}

DomParser.prototype.getChildElementItem = function(parentElem  , className , index) {
	var resultElem = null;
	var curIndex = 0;
	
	var cur = parentElem.firstChild;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE && this.hasElementClass(cur,className)) {
			if (curIndex==index) {
				resultElem = cur;
			}
			curIndex++;
		}
		cur = cur.nextSibling;
	}
	return resultElem;
}

DomParser.prototype.childElements = function(rootElem , tagName,className) {
	var list = [];
	var cur = rootElem.firstChild;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE && cur.tagName == tagName) {
			if (!className || this.hasElementClass(cur, className)) {
				list.push(cur);
			}
		}
		cur = cur.nextSibling;
	}
	return list;
}

DomParser.prototype.getAllSubElements = function(topElem , tagName , className) {
	var elements = [];
	var subElements = topElem.getElementsByTagName(tagName);
	var ii;
	var curElem;
	for (ii=0 ; ii< subElements.length ; ii++) {
		curElem = subElements.item(ii);
		if (!className || this.hasElementClass(curElem,className)) {
			elements.push(curElem);
		}
	}
	
	return elements;
}

DomParser.prototype.isAncestor = function(element , ancestor) {
	while (element) {
		if (element == ancestor) return true;
		element = element.parentNode;
	}
	return false;
}

DomParser.prototype.findAncestor = function(rootElem , tagName, className) {
	var cur = rootElem;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE && cur.tagName == tagName) {
			if (!className || this.hasElementClass(cur,className)) {
				return cur;
			}
		}
		cur=cur.parentNode;
	}
	return null;
}

DomParser.prototype.findParent = function(rootElem , tagName, className) {
	var cur = rootElem.parentNode;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE && cur.tagName == tagName) {
			if (!className || this.hasElementClass(cur,className)) {
				return cur;
			}
		}
		cur=cur.parentNode;
	}
	return null;
}



DomParser.prototype.findWidgetParent = function(rootElem) {
	return this.findWidgetParentIncludingSelf(rootElem.parentNode);
}


DomParser.prototype.getMultilineTextValue = function(rootElem) {
	var textValue="";
	var cur = rootElem.firstChild;
	while (cur) {
		if (cur.nodeType == Node.TEXT_NODE) {
			textValue += cur.data;
		} else if (cur.nodeType == Node.ELEMENT_NODE && cur.tagName=='BR' ) {
			textValue += "\n";
		}
		cur = cur.nextSibling;
	}
	return textValue;
}

DomParser.prototype.setMultilineTextValue = function(rootElem,textStr) {
	while (rootElem.firstChild) {
		rootElem.removeChild(rootElem.firstChild);
	}
	var curPos = 0;
	var foundPos;
	
	while ( (foundPos = textStr.indexOf("\n",curPos)) != -1 ) {
		rootElem.appendChild(document.createTextNode(textStr.substring(curPos,foundPos)));
		rootElem.appendChild(document.createElement("br"));
		curPos = foundPos+1;
	}

	rootElem.appendChild(document.createTextNode(textStr.substring(curPos)));
}

DomParser.prototype.setTextValue = function(rootElem,textStr) {
	while (rootElem.firstChild) {
		rootElem.removeChild(rootElem.firstChild);
	}
	rootElem.appendChild(document.createTextNode(textStr));
}

DomParser.prototype.getTextValue = function(rootElem) {
	var textValue="";
	var cur = rootElem.firstChild;
	while (cur) {
		if (cur.nodeType == Node.TEXT_NODE) {
			textValue += cur.data;
		} else if (cur.nodeType == Node.ELEMENT_NODE) {
			textValue += this.getTextValue(cur);
		}
		cur = cur.nextSibling;
	}
	return textValue;
}

DomParser.prototype.setStyleProperty = function(element,name,value) {
	if (element.style.setProperty) {
		element.style.setProperty("display","block","");
	} else {
		element.style[name] = value;
	}
}

DomParser.prototype.setTransparentBackgroundImage = function(element,src) {
	if (window.isIE6) {
		if (src) {
			element.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "', sizingMethod='scale')";
		} else {
			element.style.filter = "";
		}
	} else {
		if (src) {
			element.style.backgroundImage="url("+src+")";
		} else {
			element.style.backgroundImage="";
		}
	}
}

DomParser.prototype.getXMLData = function() {
	doc = this.createDomDocument();
	var root = doc.createElement("root");
	this.appendXMLData(root);
	return root;
}

DomParser.prototype.getData = function(data) {
	alert("must override getData: "+this.type);
}

DomParser.prototype.setData = function(data) {
	alert("must override setData: "+this.type);
}

DomParser.prototype.appendXMLData = function(root) {
	alert("must override appendXMLData: "+this.type);
}

DomParser.prototype.reorder = function(fromElem , toElem) {
	if (fromElem == toElem) return;
	var forward=false;
	var curElem = fromElem.nextSibling;
	while (curElem) {
		if (curElem == toElem) {
			forward=true;
			break;
		}
		curElem = curElem.nextSibling;
	}
	
	if (forward) {
		fromElem.parentNode.insertBefore(fromElem,toElem.nextSibling);
	} else {
		fromElem.parentNode.insertBefore(fromElem,toElem);
	}
}

DomParser.prototype.setElementOpacity = function (element , opacity) {
	element.style.opacity = opacity/100;
	if (element.style.filters) {
		element.style.filters.alpha.opacity = opacity;
	}
}

DomParser.prototype.getContentSize = function () {
	var width = document.documentElement.clientWidth;
	var height = document.documentElement.clientHeight;

	return {'width':width,'height':height};
}

DomParser.prototype.getScrollOffset = function () {
	var left = document.body.scrollLeft + document.documentElement.scrollLeft;
	var top = document.body.scrollTop + document.documentElement.scrollTop;
	return {'left':left,'top':top};

}

DomParser.prototype.getEventMousePosition = function (event){
	if(event.pageX || event.pageY){
		return {x:event.pageX, y:event.pageY};
	}
	
	//alert("event.clientY: "+event.clientY);
	//alert("document.body.scrollTop: "+document.body.scrollTop);
	//alert("event.clientY: "+event.clientY);
	return {
		//x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
		//y:ev.clientY + document.body.scrollTop  - document.body.clientTop
		x:event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
		y:event.clientY + document.body.scrollTop  + document.documentElement.scrollTop
	};
}

/*
DomParser.prototype.getPositionReferenceParent = function(element) {
	var parent = element.parentNode;
	var position;
	while (parent) {
		if (!parent.style) return parent;
		position = parent.style.position; //no needs computed
		if (position =="absolute" || position=="relative") {
			return parent;
		}
		parent = parent.parentNode;
	}
	return document; //body?
}

DomParser.prototype.getEventMouseLocalPosition = function (element , event){
	var reference = this.getPositionReferenceParent(element);
	return this.getElementEventMouseOffset(reference,event);
	
}
*/

DomParser.prototype.getElementEventMouseOffset = function (element , event){
	var elementPos    = this.getElementPosition(element);
	var mousePos  = this.getEventMousePosition(event);
	return {'x': mousePos.x - elementPos.x , 'y': mousePos.y - elementPos.y};
}



DomParser.prototype.getEventMouseFixedPosition = function (event){
	var pos = this.getEventMousePosition(event);
	
	return {x: pos.x - window.pageXOffset , y: pos.y - window.pageYOffset}
}


DomParser.prototype.getElementClasses = function(element) {
	var oldClass = element.className;
	if (!oldClass) return [];
	var classes = oldClass.split(' ');
	return classes;
}

DomParser.prototype.getElementPrefixedClass = function(element , prefix) {
	var classes = this.getElementClasses(element);
	for (var ii=0; ii< classes.length ; ii++) {
		var className = classes[ii];
		if (className.indexOf(prefix)==0) {
			result = className.substring(prefix.length);
			return result;
		}
	}
	return null;
}

DomParser.prototype.setElementPrefixedClass = function(element , prefix, value) {
	var oldName = this.getElementPrefixedClass(element , prefix);
	var newName = value;
	if (oldName != newName) {
		this.unsetElementClass(element,prefix+oldName);
		this.setElementClass(element,prefix+newName);
	}
}

DomParser.prototype.hasElementClass = function(element , className) {
	var classes = this.getElementClasses(element);
	var ii,curClass;
	var found = false;
	for (ii in classes) {
		curClass = classes[ii];
		if (curClass == className) {
			//alert("found: "+curClass);
			found=true;
		}
	}
	return found;
}

DomParser.prototype.setElementClass = function(element , className) {
	if (!this.hasElementClass(element , className)) {
		element.className += ' ' + className;
	}
}

DomParser.prototype.unsetElementClass = function(element , className) {
	var oldArray = this.getElementClasses(element);
	var newArray = [];
	for (var ii in oldArray) {
		var curClass = oldArray[ii];
		if (curClass != className) {
			newArray.push(curClass);
		}
	}
	element.className=newArray.join(" ");
}

//*****

DomParser.prototype.getElementActionName = function(element) {
	var classes = this.getElementClasses(element);
	var regExp = new RegExp("^do_(.*?)( |$)");
	var actionName = null;
	
	for (var ii in classes) {
		var curClass = classes[ii];
		var match = regExp.exec(curClass);
		if (match) {
			actionName = match[1];
			break; //first one
		}
	}
	
	return actionName;
}


//*****

DomParser.prototype.setSelectionToElement = function(element , aWindow) {
	if (!aWindow) aWindow=window;
	var body = aWindow.document.body;
	if (body.createTextRange) {
		var ieRange = body.createTextRange();
		ieRange.moveToElementText(element);
		ieRange.select();
	} else if (aWindow.getSelection) {
		aWindow.getSelection().selectAllChildren(element);
	}
}



DomParser.prototype.setSelectionHTML = function(html , aWindow) {
	if (!aWindow) aWindow=window;
	var ieSelection = aWindow.document.selection;

	if (ieSelection && ieSelection.createRange) {
		var ieRange = ieSelection.createRange();
		ieRange.pasteHTML(html); 
		ieRange.collapse(false);
		ieRange.select();
	} else {
		aWindow.document.execCommand('insertHTML', false, html);
	}
}

DomParser.prototype.getSelectionHTML = function(aWindow) {
	if (!aWindow) aWindow=window;
	
	//aWindow.focus();
	var ieSelection = aWindow.document.selection;
	var html=null;
	
	if (ieSelection && ieSelection.createRange) {
		var ieRange = ieSelection.createRange();
		html = ieRange.htmlText; 
	} else if (aWindow.getSelection) {
		var selObj = aWindow.getSelection(); 
		if (!selObj.rangeCount) {
			return "";
		}
		var selRange = selObj.getRangeAt(0);
		var fragment = selRange.cloneContents();
		var aDiv = aWindow.document.createElement("div");
		aDiv.appendChild(fragment);
		html = aDiv.innerHTML;
	}
	
	return html;
}

DomParser.prototype.insertElementAfterSelection = function(aWindow , element) {
	if (!aWindow) aWindow=window;

	var ieSelection = aWindow.document.selection;
	if (ieSelection && ieSelection.createRange) { //IE
		var ieRange = ieSelection.createRange();
		ieRange.collapse(false);
		var htmlText = element.outerHTML;
		ieRange.pasteHTML(htmlText); 
		ieRange.select();
	} else {
		var selObj = aWindow.getSelection(); 
		selObj.collapseToEnd();
		var selRange = selObj.getRangeAt(0);
		selRange.insertNode(element);
		selObj.selectAllChildren(element)
	}
}


DomParser.prototype.getSelectionRange = function(aWindow) {
	var selRange;
	
	if (!aWindow) aWindow=window;
	
	
	if (aWindow.getSelection) {
		var selObj = aWindow.getSelection(); 
		selRange = selObj.getRangeAt(0);

	} else if (aWindow.document.selection) {
		selRange = aWindow.document.selection.createRange(); 
	}
	
	return selRange;
}


DomParser.prototype.getRangeFragment = function(range) {
	var documentFragment=null;
	
	if (range.cloneContents) {
		documentFragment = range.cloneContents();
	} else {
		var parentElement = range.parentElement();
		if (parentElement && parentElement.ownerDocument) {
			documentFragment = parentElement.ownerDocument.createDocumentFragment();
			var htmlText = range.htmlText;
			
			var aDiv = parentElement.ownerDocument.createElement("DIV");
			aDiv.innerHTML = htmlText;
			
			var curElem = aDiv.firstChild;
			while(curElem) {
				if (curElem.nodeType == Node.ELEMENT_NODE) {
					documentFragment.appendChild(curElem);
				} else if (curElem.nodeType == Node.TEXT_NODE) {
					documentFragment.appendChild(curElem);
				}
				curElem=curElem.nextSibling;
			}
		}
	}
	return documentFragment;
}


DomParser.prototype.setRangeFragment = function(range , frag) {
	if (range.insertNode) {
		//alert("setRangeFragment1: "+range);
		range.deleteContents();
		range.insertNode(frag);
		

	} else {
		var htmlText = frag.innerHTML;
		range.pasteHTML(htmlText);
	}
}

DomParser.prototype.getSelectionFragment = function(aWindow) {
	return this.getRangeFragment(this.getSelectionRange(aWindow));
}


DomParser.prototype.getFragmentHTML = function(fragment) {
	var aDoc = fragment.ownerDocument;
	
	var aDiv = aDoc.createElement("div");
	aDiv.appendChild(fragment);
	var html = aDiv.innerHTML;
	
	return html;
}

DomParser.prototype.setSelectionFragment = function(aWindow , fragment) {
	this.setSelectionHTML(this.getFragmentHTML(fragment),aWindow);
}

DomParser.prototype.getSelectionHTML2 = function(aWindow) {
	var fragment = this.getSelectionFragment(aWindow);
	var html ="";
	if (fragment) {
		html = this.getFragmentHTML(fragment);
	}
	return html;
}


DomParser.prototype.setSelectionStyle = function(aWindow , styleName , styleValue) {
	var fragment = this.getSelectionFragment(this.frameElem.contentWindow);
	if (fragment) {
		this.setFragmentStyle(fragment , styleName , styleValue);
		this.setSelectionFragment(this.frameElem.contentWindow,fragment);
	}
}


DomParser.prototype.getRangeContainer = function(range) {
	var container = range.commonAncestorContainer;
	
	if (!container && range.parentElement) {
		container = range.parentElement()
	} else {
		while (container && container.nodeType != Node.ELEMENT_NODE) {
			container = container.parentNode;
		}
	}
	return container;
}

DomParser.prototype.setElementStyle = function(element , styleName , styleValue) { 
	if (element.style[styleName] != styleValue) {
		element.style[styleName] = styleValue;
	}
}

DomParser.prototype.unsetElementStyle = function(element , styleName) { 
	if (element.style[styleName]) {
		element.style[styleName] = "";
	}
}

DomParser.prototype.setFragmentStyle = function(fragment , styleName , styleValue) { 
	var curElem = fragment.firstChild;
	while(curElem) {
		var nextElem = curElem.nextSibling;
		if (curElem.nodeType == Node.ELEMENT_NODE) {
			this.removeChildrenElementStyleRecursive(curElem,styleName);
			this.setElementStyle(curElem,styleName , styleValue);
		} else if (curElem.nodeType == Node.TEXT_NODE) {
			if (curElem.nodeValue != "") {
				var newSpan = fragment.ownerDocument.createElement("SPAN");
				fragment.replaceChild(newSpan,curElem);
				newSpan.appendChild(curElem);
				this.setElementStyle(newSpan,styleName , styleValue);
			} else {
				fragment.removeChild(curElem); //reason for var nextElem 
			}
		}
		curElem=nextElem;
	}

}


DomParser.prototype.removeChildrenElementStyleRecursive = function(element , styleName) { 
	var curElem = element.firstChild;
	while(curElem) {
		if (curElem.nodeType == Node.ELEMENT_NODE) {
			this.unsetElementStyle(curElem , styleName);
			this.removeChildrenElementStyleRecursive(curElem,styleName);
		} 
		curElem=curElem.nextSibling;
	}
}



DomParser.prototype.getEventChar = function(event) {
	return String.fromCharCode(event.charCode ? event.charCode : event.keyCode);
}


DomParser.prototype.bindElementEvent = function (element,eventName,callback) {
	var self = this;
	
	function eventCaught(event) {
		
		if (!event) event=window.event; //IE6
		if (!event.target && event.srcElement) { //IE6
			event.target = event.srcElement;
		}
		if (!event.preventDefault) {//IE6
			event.preventDefault = function() {event.returnValue=false;}
		}
		if (!event.stopPropagation) {//IE6
			event.stopPropagation = function() {event.cancelBubble=true;}
		}
		
		if (event.toElement && !event.relatedTarget) event.relatedTarget=event.toElement;
		if (event.fromElement && !event.relatedTarget) event.relatedTarget=event.fromElement;
		
		//alert("eventCaught: "+ event.target.id + " -> " + event.target.parentNode.id);
		callback(event);
	}
	
	if (element) {
		if (element.addEventListener) { //DOM
			element.addEventListener(eventName, eventCaught , false);
		} else if (element.attachEvent) { //IE
			element.attachEvent('on'+eventName, eventCaught );
		}
	}
	return {'func':eventCaught , 'name':eventName , 'element':element};
}

DomParser.prototype.unbindElementEvent = function(bindInfo) {
	if (bindInfo.element.removeEventListener) { //DOM
		bindInfo.element.removeEventListener(bindInfo.name, bindInfo.func , false);
	} else if (bindInfo.element.detachEvent) { //IE
		bindInfo.element.detachEvent('on'+bindInfo.name, bindInfo.func );
	}
	return null;
}


DomParser.prototype.getElementPosition = function (e ){
	var left = 0;
	var top  = 0;

	while (e.offsetParent){
		left += e.offsetLeft;
		top  += e.offsetTop;
		e     = e.offsetParent;
	}

	left += e.offsetLeft;
	top  += e.offsetTop;

	var pos = {x:left, y:top};
	//window.status = "("+pos.x+","+pos.y+")";

	return pos;
}

DomParser.prototype.getElementSize = function (element) {
	var width,height;
	
	if (document.defaultView && document.defaultView.getComputedStyle) {
		var computedStyleBuffer = document.defaultView.getComputedStyle(element, null);
		
		widthValue = computedStyleBuffer.getPropertyCSSValue("width");
		heightValue = computedStyleBuffer.getPropertyCSSValue("height");

		try {
			width = widthValue.getFloatValue(CSSPrimitiveValue.CSS_PX);
			height = heightValue.getFloatValue(CSSPrimitiveValue.CSS_PX);
		} catch(ex) {
			//alert("type: "+widthValue.primitiveType);
			//alert("value: "+widthValue.getStringValue());
		
			//alert("widthValue: "+widthValue);
			//alert("heightValue: "+heightValue);
			alert(element.id +" -> "+ex);
		}
		
		//height = computedStyleBuffer.getPropertyValue("height");
	} else {
		width = element.offsetWidth;
		height = element.offsetHeight;
	}
	
	//window.status = "("+width+","+height+"): "+element.id;
	
	return {'width':width , 'height':height};
}

DomParser.prototype.getElementArea = function (element) {
	var pos = this.getElementPosition(element);
	var size = this.getElementSize(element);
	var bottom = pos.y + size.height;
	var right = pos.x + size.width;
	
	var area = {'left': pos.x , 'top': pos.y , 'bottom': bottom , 'right': right};
	
	//window.status = "("+area.top+","+area.left+","+area.bottom+","+area.right+")";
	return area;
}


window.gDOMHelper = new DomParser();

//****************************

function DowWidget() {
}

DowWidget.prototype = new DomParser;

DowWidget.newWidget = function(widgetId , widgetName) {
	var widgetConstructor = eval (widgetName); //Is eval EVIL here ????
	var newWidget = new widgetConstructor(widgetId);
	newWidget.uid = widgetId; 
	newWidget.widgetName = widgetName; 
	newWidget.preInit();
	newWidget.initParams();
	return newWidget;
}

DowWidget.prototype.preInit = function() {
}

DowWidget.prototype.initParams = function(params) {
	this.params={};

	var params = gWidgetParams[this.uid];
	if (params) {
		for(var key in params) {
			this.params[key] = getAndClearWidgetParam(this.uid , key);
		}
	}
	//delete gWidgetParams[this.uid]; not now needs to be used later in registerAllSubWidgets
}


						
DowWidget.prototype.clone = function(newUid) {
	gWidgetParams[newUid] = this.params; //could also be a deep copy
	var newWidget = DowWidget.newWidget(newUid , this.widgetName);
	return newWidget;
}

DowWidget.prototype.getWidgetElement = function() {
	var hookElem = document.getElementById(this.uid);
	return hookElem;
}

DowWidget.prototype.toString = function() {
	return '<widget id="' + this.uid + '" widgetName="' + this.widgetName + '"/>';
}


DowWidget.prototype.appendChildrenXMLData = function(root) {
	function doSubWidget(subWidget) {
		subWidget.appendXMLData(root);
	}
	
	this.getTopDescendantWidgets(doSubWidget);
}


DowWidget.prototype.findFirstChildWidget = function(parentElem) {
	var cur = parentElem.firstChild;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE) {
			var curId = cur.id;
			if (curId) {
				var curWidget = gWidgets[curId];
				if (curWidget) {
					return curWidget;
				}
			}
		}
		cur = cur.nextSibling;
	}
	return null;
}


DowWidget.prototype.findParentWidget = function() {
	var hookElem = document.getElementById(this.uid);
	var widget = this.findWidgetParent(hookElem);
	return widget;
}

DowWidget.prototype.getFirstParentWidget = function(baseElem , tagName , className) {
	var curElem = baseElem;
	while (curElem) {
		if (curElem.tagName==tagName && (!className || this.hasElementClass(curElem,className))) {
			widget = gWidgets[curElem.id];
			if (widget) {
				return widget;
			}
		}
		curElem = curElem.parentNode;
	}
	return null;
}

DowWidget.prototype.getAllSubWidgets = function(topElem , tagName , className) {
	var widgets = [];
	var subElements = topElem.getElementsByTagName(tagName);
	var ii;
	var curElem,widget;
	for (ii=0 ; ii< subElements.length ; ii++) {
		curElem = subElements.item(ii);
		if (this.hasElementClass(curElem,className)) {
			widget = gWidgets[curElem.id];
			if (widget) {
				widgets.push(widget);
			}
		}
	}
	
	return widgets;
}

DowWidget.prototype.getChildrenWidgets = function(topElem  , className) {
	var widgets = [];
	
	var cur = topElem.firstChild;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE) {
			var curId = cur.id;
			if (curId) {
				var curWidget = gWidgets[curId];
				if (curWidget) {
					if (className) {
						if (this.hasElementClass(cur,className)) {
							widgets.push(curWidget);
						}
					} else {
						widgets.push(curWidget);
					}
				}
			}
		}
		cur = cur.nextSibling;
	}
	
	return widgets;
}

DowWidget.prototype.findWidgetParentIncludingSelf = function(rootElem) {
	var cur = rootElem;
	while (cur) {
		if (cur.nodeType == Node.ELEMENT_NODE && cur.id) {
			var widget = gWidgets[cur.id];
			if (widget) return widget;
		}
		cur=cur.parentNode;
	}
	return null;

}

DowWidget.prototype.getTopDescendantWidgets = function(callback,topElem) {
	if (!topElem) {
		topElem = document.getElementById(this.uid);
	}
	
	function _childWidgets(parentElem) {
		var cur = parentElem.firstChild;
		var widget;
		
		while (cur) {
			widget = null;
			if (cur.nodeType == Node.ELEMENT_NODE) {
				var curId = cur.id;
				if (curId) {
					var curWidget = gWidgets[curId];
					if (curWidget) {
						widget = curWidget;
					}
				}
			}
			
			if (widget) callback(widget); else _childWidgets(cur);
			cur = cur.nextSibling;
		}
	}
	
	_childWidgets(topElem);
}

DowWidget.prototype.sendEventDown = function(who,what,rootElem) {
	function _sendEventDown(widget) {
		var onMethod = widget["on_"+what];
		if (onMethod) {
			onMethod.call(widget,who);
		} else {
			widget.sendEventDown(who,what);
		}
	}
	
	this.getTopDescendantWidgets(_sendEventDown , rootElem);
}


DowWidget.prototype.sendEventUp = function(who,what,param) {
	var parentWidget = this.findParentWidget();
	if (parentWidget) {
		var onMethod = parentWidget["on_"+what];
		if (onMethod) {
			onMethod.call(parentWidget,who,param);
		} else {
			parentWidget.sendEventUp(who,what,param);
		}
	} else {
		alert("end of sendEventUp rope: "+what );
	}
}


DowWidget.prototype.getActionName = function() {
	return this.getElementActionName(this.getWidgetElement());
}

DowWidget.prototype.getFirstActionName = function(startElement , stopElement) {
	var actionName = null;
	var target = startElement;
	while (target && !actionName && target!=stopElement) {
		actionName = this.getElementActionName(target);
		target = target.parentNode;
	}
	return actionName;
}


DowWidget.prototype.widgetModified = function(widget,what) {
	var parentWidget = this.findParentWidget();
	
	if (parentWidget) {
		if (parentWidget.onWidgetModified) parentWidget.onWidgetModified(widget);
		else if (parentWidget.widgetModified) parentWidget.widgetModified(widget);
		else alert("Not a widget "+widget.uid+" : "+widget.widgetName+ " at "+ this.uid + " : " +this.widgetName);
	} else {
		alert("End of rope for "+widget.uid+" : "+widget.widgetName+ " at "+ this.uid + " : " +this.widgetName);
	}
}




DowWidget.prototype.cloneWidget = function() {
	var myElem = this.getWidgetElement();
	var clonedElem = this.cloneSubtree(myElem , true);
	
	var myUid = myElem.id;
	var clonedUid = clonedElem.id;
	
	var clonedWidget = this.clone(clonedUid);
	gWidgets[clonedUid] = clonedWidget;

	if (clonedWidget.postInit) { //subs done by this.cloneSubtree(myElem , true);
		clonedWidget.postInit(); 
	}
	
	return clonedElem;
}

DowWidget.prototype.cloneSubtree = function (rootElem , doWidgets) {
	var newUid = generateUid();
	var oldUid = rootElem.id;
	var newElem;
	
	var outerHTML = rootElem.outerHTML;
	if (outerHTML) { //IE copies attachEvent when using cloneNode
		var holder = document.createElement("DIV");
		holder.innerHTML = outerHTML;
		newElem = holder.firstChild;
	} else {
		newElem = rootElem.cloneNode(true);
	}
	newElem.setAttribute("id",newUid);
	
	var regExp = new RegExp("^"+oldUid+"(.*)");
	var newWidgets = [];
	
	var divList = newElem.getElementsByTagName("*");
	for (var ii=0 ; ii<divList.length ; ii++) {
		var curElem = divList.item(ii);
		var curId = curElem.id;
		if (curId) {
			var match = regExp.exec(curId);
			if (match) {
				var postfix = match[1];
				var newCurId = newUid+postfix;
				//alert("newCurId: "+newCurId);
				curElem.setAttribute("id",newCurId);
				
				if (doWidgets) { //NEW BETTER INCOMPATIBLE
					var curWidget = gWidgets[curId];
					if (curWidget) {
						var  newWidget = curWidget.clone(newCurId);
						gWidgets[newCurId] = newWidget;
						newWidgets.push(newWidget);
					}
				}
			}
		}
	}
	
	if (doWidgets) { //NEW BETTER INCOMPATIBLE
		rootElem.parentNode.insertBefore(newElem,rootElem);
		
		for (var index=0 ; index<newWidgets.length ; index++) {
			var curWidget = newWidgets[index];
			if (curWidget.postInit) {
				curWidget.postInit(); //for when you need the other widgets already initialized
			}
		}
	}
	
	return newElem;
}

DowWidget.prototype.unbindEvent = function (domElement,domEventName) {
	domElement.removeAttribute('on'+domEventName);
}

DowWidget.prototype.bindEvent = function (domElement,domEventName,widgetMethod) {
	var self = this;
	function callback(event) {
		gWidgets[self.uid][widgetMethod](event);
	}
	this.bindElementEvent(domElement,domEventName,callback);
}

DowWidget.prototype.dragStart = function (dragger) {
	window.status = "dragging";
}

DowWidget.prototype.dragMove = function (dragger) {
	//var pos = dragger.getDragPosition();  
	//window.status = "("+pos.x +","+pos.y+") : "; 
	//window.status = "drag move";
}

DowWidget.prototype.dragEnd = function (dragger) {
	window.status = "NOT dragging";
}

DowWidget.prototype.canDrop = function (dragWidget) {
	return false;
}





