
/**
 * @param {string} par.app lowercase app name: msie|firefox|netscape|opera
 * @param {float} par.ver version of the app
 * 
 */
function getbrowser()
{
	var res= navigator.userAgent.match(/(msie|opera|firefox|netscape)[ \/\\]+([\d.]+)/i);
	//if (!res) res= navigator.userAgent.match(/(mozilla)[ \/\\]+([\d.]+)/i);
	return {app:res[1].toLowerCase(), ver:parseFloat(res[2])};
};



/**
* @fileoverview nebui.js
*/
if (document && (!document.getElementById))
	alert("You are using a very old or not compatible browser. Please try to upgrade, it's usually free and takes some minutes.");

/**
* Base class of nebui
* @constructor
* @class nebui
*/
function nebui()
{

};

nebui.browser= getbrowser();
nebui.isff= nebui.browser.app=="firefox";
nebui.isie= nebui.browser.app=="msie";
nebui.isop= nebui.browser.app=="opera";

/**
* Gets a DOM object from its ID
* @param {string|object} theObj ID or object
* @param {document object} theDoc optional, document holds the object
* @type object
* @returns DOM object
*/
nebui.getobj = function(idObj,theDoc,onlybyid)
{
	if (!idObj) return null;
	if (typeof idObj == "object") return idObj;
	theDoc = theDoc ? theDoc : document;
	var obj= theDoc.getElementById(idObj);
	if (obj || onlybyid) return obj;
	obj= theDoc.getElementsByName(idObj);
	if (obj.length!=1) return null;
	return obj[0];
};


//fighting IE garbage collector bug
nebui.purgelist= [];

nebui.purgeable= function(obj, member){
	var p= nebui.purgelist;
	if (typeof member == "string" || typeof member == "number")
		member= [member];
	for(var j=0; j<member.length; ++j)
	{
		for(var i=0; i<p.length; ++i)
			if (p[i].o == obj && p[i].m == member[j])
				return;	
		nebui.purgelist.push({o: obj, m: member[j]});
	}
};


/**
* Gets the document object of a frame given by name
*
<pre>
Be careful! You have to wait while the content of the frame has loaded.
This function can be safely called only from onload().
</pre>
* @param {string|object} idfrm ID of the frame or the frame object itself
* @type object
* @returns DOM document object
*/
nebui.getframedoc = function(idfrm)
{
	if (document.frames)
		if (document.frames[idfrm])
			if (document.frames[idfrm].document)
				if (document.frames[idfrm].document.body)
					return document.frames[idfrm].document;
	var ofrm= nebui.getobj(idfrm);
	if (ofrm)
	{
		if (ofrm.document)
			if (ofrm.document.body)
				return ofrm.document;
		if (ofrm.contentDocument)
			if (ofrm.contentDocument.body)
				return ofrm.contentDocument;
	}
	return null;
};



/**
* Applies the callbackfunc for all frames of rootwnd.
*
* Remarks
<pre>
Long description
</pre>
* Example code
<code>
</code>
* @param {function} callbackfunc callback function to apply
* @param {object} rootwnd window to walk
* @param {any} defretval default return value
* @param {int} maxlevel maximum depth
* @param {int} level actual depth
* @type return depends
* @return return value of callbackfunc
* @see #getobjex
*/
nebui.postprocesspage = function(callbackfunc, rootwnd, defretval, maxlevel, level)
{
	if (typeof callbackfunc != "function") {alert("Error in nebui.postprocess: nothing to do.");return 1;}
	if (!rootwnd) rootwnd=window;
	if (typeof maxlevel!="number" || maxlevel<0) maxlevel= 5;
	if (!level) level=0;

	//get document of this window
	var doc= rootwnd.document;
	if (!doc || !doc.body)
		doc= rootwnd.contentDocument;

	//apply callback on the doc
	var ret= callbackfunc(doc, level);
	if (ret!=defretval) return ret;

	if (level>=maxlevel)
		return defretval;

	//processing all the frames
	var frms= rootwnd.frames;
	if (frms)
		for(var f=0;f<frms.length;++f)
		{
			var ret= nebui.postprocesspage(callbackfunc, frms[f], defretval, maxlevel, level+1);
			if (ret!=defretval) return ret;
		}

	return defretval;
};


/**
* @type object
* @returns DOM object by ID
*/
nebui.getobjex = function(id, rootwnd, maxlevel)
{
	return this.postprocesspage(new Function("doc","lev","return nebui.getobj('"+id+"',doc)"), rootwnd, null, maxlevel);
};


nebui.noselect= function(obj, bremove, doc)
{
	if (!(obj = nebui.getobj(obj, doc))) return false;
	obj.ondrag = bremove ? "" : function(e){return false;};
	obj.onselectstart = bremove ? "" : function(e){return false;};
	nebui.purgeable(obj, ["ondrag","onselectstart"]);
	obj.style.MozUserSelect = obj.style.userSelect = bremove ? "" : "none";
};

nebui.mydoc= function(obj)
{
	if (typeof obj != "object") return null;
	return obj.getElementById ? obj : (obj.ownerDocument ? obj.ownerDocument : obj.document);
};

nebui.mywin= function(obj)
{
	var doc= nebui.mydoc(obj);
	var w= !doc ? null : (doc.parentWindow || doc.defaultView);
	return w;
};

/**
* Gets a session cookie value to the given key
* @param {string} key cookie key
* @param {doc} document object the cookie belongs to
* @type string
* @returns the cookie value
*/
nebui.getcookie = function(key, doc)
{
	doc= doc || document;
	ck= doc.cookie.split(/ *; */);
	for(var i=0;i<ck.length;++i)
	{
		var vk= ck[i].split(/ *= */);
		if (vk[0] == key)
			return vk[1] ? vk[1].toString() : "";
	}//i
	return false;
};

/**
* Sets a session cookie value to the given key
*
* A session cookie set from javascript lives till all the instance of the browser have closed.
* @param {string} key cookie key
* @param {string} val cookie value
* @param {doc} document object the cookie belongs to
* @type string
* @returns the cookie value
*/
nebui.setcookie = function(key, val, doc)
{
	doc= doc || document;
	doc.cookie= key+"="+val + "; expires=Fri, 1 Jan 2010 0:00:00 UTC; path=/";
	return true;
};

nebui.delcookie = function(key, doc)
{
	doc= doc || document;
	if (key)
	{
		doc.cookie = key + "=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT";
		doc.cookie = key + "; expires=Thu, 01-Jan-1970 00:00:01 GMT";
		return;
	}

	ck= doc.cookie.split(/ *;+ */);
	for(var i=0;i<ck.length;++i)
	{
		key= ck[i].replace(/\=.*/,"");
		if (key)
			nebui.delcookie(key, doc);
	}
};

//nebui.cookieext = function(bset, key, basekey, val, doc)
/**
* @param {boolean} par.bset       set(1) or get(0) the cookie
* @param {string} par.scookie     whole cookie string, may be empty
* @param {string} par.basekey     cookie name
* @param {string} par.key         inner cookie key
* @param {string} par.val
* @param {string} par.sep_keyval
* @param {string} par.sep_cookies
*/
nebui.cookieext = function(par)
{
	par.sep_keyval= par.sep_keyval || "~&~";//eg. x~&~1
	par.sep_cookies= par.sep_cookies || "~@~";//eg. x~&~1~@~y~&~2

	var sc0= par.sep_cookies.substr(0,1);

	var sc1= "";
	if (par.sep_cookies.length>1)
		sc1= "(" + sc0 + "(?!" + par.sep_cookies.substr(1) + "))|";

	var rgx_keyval= "\\b" + par.key.replace(/([\[\]])/g, "\\$1") + "" + par.sep_keyval + "(" + sc1 + "[^" + sc0 + "])*";
	//\bMYKEY\b~~((#(?!#))|[^#])*
	//prompt("",rgx_keyval);

	par.doc= par.doc || document;

	//whole cookie string
	var scookie= (typeof par.scookie == "undefined" || par.scookie===null) ? nebui.getcookie(par.basekey, par.doc) : par.scookie;
	if (!scookie) scookie="";
	//eg. keyval[0] = "name~~laci"
	var keyval= scookie.match(new RegExp(rgx_keyval));
	
	//get mode
	if (!par.bset)
	{
		if (keyval && keyval[0])
			return keyval[0].substr((par.key + par.sep_keyval).length);
		else
			return false;
	}
	//set mode
	else
	{	
		var newscookie="";
		var part= par.key + par.sep_keyval + par.val;

		if (!scookie)
			newscookie= part;
		else
		{
			if (keyval)
				newscookie= scookie.replace(new RegExp(rgx_keyval), part);
			else
				newscookie= scookie + par.sep_cookies + part;
		}
		
		return (typeof par.scookie == "undefined" || par.scookie===null) ? nebui.setcookie(par.basekey, newscookie, par.doc) : newscookie;
	}
	return false;
};

/**
* Gets the runtime style value of the object to the given css key
*
*
* @param {string|object} obj DOM object
* @param {string} csskey css key
* @param {doc} document document object contains the obj
* @type string
* @returns the css value
*/
nebui.getCurrentStyle= function(obj, csskey, doc)
{
	if (!(obj=nebui.getobj(obj,doc||document))) return "";
	if (!obj.style) return "";
	if (obj.style[csskey])// && obj.style[csskey]!="auto")
	{
		//if (csskey == "left") document.title= "["+obj.style[csskey]+"] ";
		return obj.style[csskey];
	}

	if (obj.currentStyle)
		return obj.currentStyle[csskey];
	
	if (!doc) doc= nebui.mydoc(obj);
	if (doc.defaultView && doc.defaultView.getComputedStyle)
		return (doc.defaultView.getComputedStyle(obj,null))[csskey];

	return "";
};

/**
* Special function to get integer dimension styles
*
*
* @param {string|object} obj DOM object
* @param {string} csskey css key
* @param {doc} document document object contains the obj
* @type int
* @returns the css value
*/
nebui.getCurrentIntStyle= function(obj, csskey, doc)
{
	var v= parseInt(nebui.getCurrentStyle(obj, csskey, doc));
	return isNaN(v) ? 0 : v;
};

nebui.getw = function(obj, doc)
{
	if (!(obj=nebui.getobj(obj,doc||document))) return -1;
	if (obj.getBoundingClientRect)
	{
		//var bcr= obj.getBoundingClientRect();
		//return bcr.right - bcr.left + 1;
	}
	return parseInt(obj.offsetWidth);
};

nebui.geth = function(obj, doc)
{
	if (!(obj=nebui.getobj(obj,doc||document))) return -1;
	if (obj.getBoundingClientRect)
	{
		//var bcr= obj.getBoundingClientRect();
		//return bcr.bottom - bcr.top + 1;
	}
	return parseInt(obj.offsetHeight);
};

nebui.setw = function(obj, w, doc)
{
	if (!(obj=nebui.getobj(obj,doc||document))) return -1;
	try{
		obj.style.width = parseInt(w)+"px";
	}
	catch(err){
		alert("Error in nebui.setw()! obj="+obj);
	}
};

nebui.seth = function(obj, h, doc)
{
	if (!(obj=nebui.getobj(obj,doc||document))) return -1;
	try{
		obj.style.height = parseInt(h)+"px";
	}
	catch(err){
		alert("Error in nebui.seth()! obj="+obj);
	}
};




nebui.getx = function(obj, doc)
{
	if (!(obj=nebui.getobj(obj,doc||document))) return -1;
	if (!doc) doc= nebui.mydoc(obj);
	//if (!obj.offsetParent && !obj.offsetLeft) return nebui.getCurrentIntStyle(obj,"left",doc);
	if (nebui.getCurrentStyle(obj, "display", doc) == "none") return nebui.getCurrentIntStyle(obj,"left",doc);

	if (obj.getBoundingClientRect)//ie
	{
		var ret= obj.getBoundingClientRect().left;
		if (doc.documentElement && doc.body)
			ret+= Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
		return ret;
	}
	
	var x=0;
	var level=0;
	
	var parentobj=null;
	var nn=null, pos="", borderleft=0, marginleft=0;
	var nnparent=null, posparent="", borderleftparent=0, marginleftparent=0;
	while(obj){

		if (!nebui.isop)
		{
			if (!parentobj)
			{
				nn= obj.nodeName.toLowerCase();
				pos= nebui.getCurrentStyle(obj, "position");
				//borderleft= nebui.getCurrentIntStyle(obj, "borderLeftWidth", doc);
				marginleft= nebui.getCurrentIntStyle(obj, "marginLeft", doc);
			}
	
			if (nn=="table")
	  		x+= marginleft;
		}

		x += obj.offsetLeft;
	  parentobj = obj.offsetParent;

		if (!nebui.isop)
	  if (parentobj)
		{
			//calculating parent's stuffs
			var nnparent= parentobj.nodeName.toLowerCase();
			var posparent= nebui.getCurrentStyle(parentobj, "position");			
			var borderleftparent= nebui.getCurrentIntStyle(parentobj, "borderLeftWidth", doc);
			var marginleftparent= nebui.getCurrentIntStyle(parentobj, "marginLeft", doc);

			if (!nebui.isop && nnparent != "table" && nnparent != "td")
				x+= borderleftparent;

			if (nnparent == "table" && posparent!="relative" && posparent==pos)
				x-= marginleftparent;

			nn= nnparent;
			pos=posparent;
			borderleft= borderleftparent;
			marginleft= marginleftparent;
			
	  }
	  else break;
		
		obj= parentobj;
		level++;
	}
	
	return x;
};















/**
* Gets the y-coordinate of a DOM object on the screen
* @param {string|object} obj object or id
* @param {object} doc document object (optional)
* @type int
* @returns y-coordinate of the DOM object
*/
nebui.gety = function(obj, doc)
{
	if (!(obj=nebui.getobj(obj,doc||document))) return -1;
	if (!doc) doc= nebui.mydoc(obj);
	
	//if (!obj.offsetParent && !obj.offsetTop) return nebui.getCurrentIntStyle(obj,"top",doc);
	if (nebui.getCurrentStyle(obj, "display", doc) == "none") return nebui.getCurrentIntStyle(obj,"top",doc);

	if (obj.getBoundingClientRect)//ie
	{
		var ret= obj.getBoundingClientRect().top;
		if (doc.documentElement && doc.body)
			ret+= Math.max(doc.documentElement.scrollTop, doc.body.scrollTop);
		return ret;
	}
	
	var y=0;
	var level=0;
	
	var parentobj=null;
	var nn=null, pos="", bordertop=0, margintop=0;
	var nnparent=null, posparent="", bordertopparent=0, margintopparent=0;
	while(obj){

		if (!nebui.isop)
		{
			if (!parentobj)
			{
				nn= obj.nodeName.toLowerCase();
				pos= nebui.getCurrentStyle(obj, "position");
				//bordertop= nebui.getCurrentIntStyle(obj, "borderTopWidth", doc);
				margintop= nebui.getCurrentIntStyle(obj, "marginTop", doc);
			}

			if (nn=="table")
				y+= margintop;
		}

		y += obj.offsetTop;
	  parentobj = obj.offsetParent;
		
		if (!nebui.isop)
	  if (parentobj)
		{
			//calculating parent's stuffs
			var nnparent= parentobj.nodeName.toLowerCase();
			var posparent= nebui.getCurrentStyle(parentobj, "position");			
			var bordertopparent= nebui.getCurrentIntStyle(parentobj, "borderTopWidth", doc);
			var margintopparent= nebui.getCurrentIntStyle(parentobj, "marginTop", doc);
			
			if (nnparent != "table" && nnparent != "td")
				y+= bordertopparent;
		
			if (nnparent == "table" && posparent!="relative" && posparent==pos)
				y-= margintopparent;

			nn= nnparent;
			pos=posparent;
			bordertop= bordertopparent;
			margintop= margintopparent;
	  }
	  else break;
		
		obj= parentobj;
		level++;
	}
	
	return y;
};



/**
* Sets the x-coordinate of a DOM object on the screen
* @param {string|object} obj object or id
* @param {int} x the coordinate
* @param {object} doc document object (optional)
* @type bool
* @returns bool
*/
nebui.setx = function(obj, x, doc)
{
	if (!(obj=nebui.getobj(obj,doc||document))) return -1;
	if (!doc) doc= nebui.mydoc(obj);
	var pos= nebui.getCurrentStyle(obj, "position", doc);
	if (pos == "static") obj.style.position=pos="relative";
	var delta=0;
	try{
		delta-= nebui.getx(obj, doc);
		var dx= parseInt(nebui.getCurrentStyle(obj, "left", doc));
		if (isNaN(dx)) dx= (pos=="relative" ? 0 : obj.offsetLeft- nebui.getCurrentIntStyle(obj,"marginLeft",doc));
		delta+= dx;
		obj.style.left = (parseInt(x) + delta) + "px";
	}	
	catch(err){
		alert("Error in nebui.setx()! obj="+obj+" delta="+delta+"");
		return false;
	}
	return true;
};

/**
* Sets the y-coordinate of a DOM object on the screen
* @param {string|object} obj object or id
* @param {int} y the coordinate
* @param {object} doc document object (optional)
* @type bool
* @returns bool
*/
nebui.sety = function(obj, y, doc)
{
	if (!(obj=nebui.getobj(obj,doc||document))) return -1;
	if (!doc) doc= nebui.mydoc(obj);
	var pos= nebui.getCurrentStyle(obj, "position", doc);
	if (pos == "static") obj.style.position=pos="relative";
	var delta=0;
	try{
		delta-= nebui.gety(obj, doc);//current absolute y
		var dy= parseInt(nebui.getCurrentStyle(obj, "top", doc));
		if (isNaN(dy)) dy= (pos=="relative" ? 0 : obj.offsetTop - nebui.getCurrentIntStyle(obj,"marginTop",doc));
		delta+= dy;
		obj.style.top = (parseInt(y) + delta) + "px";
	}
	catch(e){
		alert("Error in nebui.sety()! obj="+obj);
		return false;
	}
	return true;
};




nebui.getpos= function(obj)
{
	return {x:nebui.getx(obj), y:nebui.gety(obj)};
};

nebui.setpos= function(obj, p, y)
{
	if (typeof p == "object")
	{
		nebui.setx(obj, p.x);
		nebui.sety(obj, p.y);
		return;
	}
	nebui.setx(obj, p);
	nebui.sety(obj, y);
};

nebui.getsize= function(obj)
{
	return {w:nebui.getw(obj), h:nebui.geth(obj)};
};

nebui.setsize= function(obj, p, h)
{
	if (typeof p == "object")
	{
		nebui.setw(obj, p.w);
		nebui.seth(obj, p.h);
		return;
	}
	nebui.setw(obj, p);
	nebui.seth(obj, h);
};

/**
* Gets the center of the DOM object
* @param {string|object} obj object or id
* @param {object} doc document object (optional)
* @type array
* @returns [x,y] array
*/
nebui.getcenter = function(obj,doc)
{with(this){
	if (!(obj=getobj(obj,doc||document))) return false;
	if (!doc) doc= nebui.mydoc(obj);
	return [getx(obj) + getw(obj, doc)/2, gety(obj, doc) + geth(obj, doc)/2];
}};

/**
* Determines wether the rect is in the box
* @param {string|object} box container object or id
* @param {string|object} rectobj object or id
* @param {object} doc document object (optional)
* @type bool
* @returns wether the rect is in the box
*/
nebui.rectinbox = function(box, rectobj, bonlyiffull, doc)
{with(this){
	if (!(box=getobj(box,doc||document))) return false;
	if (!doc) doc= nebui.mydoc(box);
	if (!(rectobj=nebui.getobj(rectobj,doc))) return false;
	var TLb = [getx(box,doc),gety(box,doc)];
	var DIMb = [getw(box,doc),geth(box,doc)];
	var TLr = [getx(rectobj,doc),gety(rectobj,doc)];
	var DIMr = [getw(rectobj,doc),geth(rectobj,doc)];
	if (bonlyiffull)
	{
		if (TLr[0] + DIMr[0] < TLb[0]) return false;//out at left
		if (TLr[1] + DIMr[1] < TLb[1]) return false;//out at top
		if (TLr[0] > TLb[0] + DIMb[0]) return false;//out at right
		if (TLr[1] > TLb[1] + DIMb[1]) return false;//out at right
	}
	else
	{
		if (TLr[0] + DIMr[0]/2 < TLb[0]) return false;//out at left
		if (TLr[1] + DIMr[1]/2 < TLb[1]) return false;//out at top
		if (TLr[0] + DIMr[0]/2 > TLb[0] + DIMb[0]) return false;//out at right
		if (TLr[1] + DIMr[1]/2 > TLb[1] + DIMb[1]) return false;//out at right
	}
	return true;
}};

/**
* Determines wether the obj's center is in the box
* @param {string|object} box container object or id
* @param {string|object} obj object or id
* @param {object} doc document object (optional)
* @type bool
* @returns wether the obj's center is in the box
*/
nebui.centerinbox = function(box, obj, doc)
{with(this){
	if (!(obj=getobj(obj,doc||document))) return false;
	if (!doc) doc= nebui.mydoc(obj);
	if (!(box=nebui.getobj(box,doc||document))) return false;
	var c = getcenter(obj);
	var topleft = [getx(box,doc),gety(box,doc)];
	var dimbox = [getw(box,doc),geth(box,doc)];
	if (c[0] < topleft[0]) return false;
	if (c[1] < topleft[1]) return false;
	if (c[0] > topleft[0]+dimbox[0]) return false;
	if (c[1] > topleft[1]+dimbox[1]) return false;
	return true;
}};

/**
* Determines wether the (x,y) is in the box
* @param {string|object} box container object or id
* @param {object} p  
* @param {object} doc document object (optional)
* @type bool
* @returns wether the x,y is in the box
*/
nebui.pointinbox = function(box, p , doc)
{with(this){
	if (!(box=nebui.getobj(box,doc||document))) return false;
	if (!doc) doc= nebui.mydoc(box);
	if (p.nodeName) p= {x:getx(p,doc), y:gety(p,doc)};
	var topleft = [getx(box,doc),gety(box,doc)];
	var dimbox =  [getw(box,doc),geth(box,doc)];
	
	//document.title= topleft[0] + "," + topleft[1] + " | " + p;//p.x + "," + p.y;
	
	if (p.x < topleft[0]) return false;
	if (p.y < topleft[1]) return false;
	if (p.x > topleft[0]+dimbox[0]) return false;
	if (p.y > topleft[1]+dimbox[1]) return false;
	return true;
}};

/**
* Moves the rectobj to get the rectobj be in the box
* @param {string|object} box container object or id
* @param {string|object} rectobj object to move
* @param {object} doc document object (optional)
* @type bool
* @returns true if success
*/
nebui.forcerectinbox = function(box, rectobj, doc)
{with(this){
	if (!(box=nebui.getobj(box,doc|document))) return false;
	if (!doc) doc= nebui.mydoc(box);
	if (!(rectobj=nebui.getobj(rectobj,doc))) return false;

	var TLb = [getx(box,doc),gety(box,doc)];
	var DIMb = [getw(box,doc),geth(box,doc)];
	var TLr = [getx(rectobj,doc),gety(rectobj,doc)];
	var DIMr = [getw(rectobj,doc),geth(rectobj,doc)];
	var x = Math.max(TLb[0], TLr[0]);
	var y = Math.max(TLb[1], TLr[1]);

	x = Math.min(x, TLb[0]+DIMb[0]-DIMr[0]);
	y = Math.min(y, TLb[1]+DIMb[1]-DIMr[1]);
	setx(rectobj, x, doc);
	sety(rectobj, y, doc);
	//YAHOO.util.Dom.setXY(rectobj, [x,y], 1);
	return true;
}};

/**
* Attractes the rectobj into the box if the border distance is less than if_closer_than_it
* @param {string|object} box container object or id
* @param {string|object} rectobj object to move
* @param (int) if_closer_than_it
* @param {object} doc document object (optional)
* @type bool
* @returns true if attracted, false if not or error
*/
nebui.attractrectinbox = function(box, rectobj, if_closer_than_it, doc)
{with(this){
	if (!(box=nebui.getobj(box,doc||document))) return false;
	if (!doc) doc= nebui.mydoc(box);
	if (!(rectobj=nebui.getobj(rectobj,doc))) return false;

	var DIMb = [getw(box),geth(box)];
	var DIMr = [getw(rectobj),geth(rectobj)];
	var dim_ok= (DIMr[0]<=DIMb[0] && DIMr[1]<=DIMb[1]);
	if (!dim_ok) return false;

	var TLb = [getx(box),gety(box)];
	var TLr = [getx(rectobj),gety(rectobj)];
	var BRr= [TLr[0]+DIMr[0],TLr[1]+DIMr[1]];//bottom right of the moving rect
	var BRb= [TLb[0]+DIMb[0],TLb[1]+DIMb[1]];//bottom right of the limiter box

	var in_x= (TLb[0] <= TLr[0]) && (BRr[0] <= BRb[0]);
	var in_y= (TLb[1] <= TLr[1]) && (BRr[1] <= BRb[1]);
	var in_left_margin= (TLr[0] < TLb[0]) && (TLr[0] > TLb[0] - if_closer_than_it);
	var in_right_margin= (BRb[0] < BRr[0]) && (BRr[0] < BRb[0] + if_closer_than_it);
	
	var in_top_margin= (TLr[1] < TLb[1]) && (TLr[1] > TLb[1] - if_closer_than_it);
	var in_bottom_margin= (BRb[1] < BRr[1]) && (BRr[1] < BRb[1] + if_closer_than_it);

	var must_align_x= (in_left_margin || in_right_margin) && (in_y || in_top_margin || in_bottom_margin);
	var must_align_y= (in_top_margin || in_bottom_margin) && (in_x || in_left_margin || in_right_margin);

	if (must_align_x)
	{
		if (in_left_margin)   setx(rectobj, TLb[0]);
		else
		if (in_right_margin)  setx(rectobj, TLb[0]+DIMb[0]-DIMr[0]);
	}
	if (must_align_y)
	{
		if (in_top_margin)    sety(rectobj, TLb[1]);
		else
		if (in_bottom_margin) sety(rectobj, TLb[1]+DIMb[1]-DIMr[1]);
	}

	return (in_x || must_align_x) && (in_y || must_align_y);
}};


/**
* Moves the rectobj's center to be at the box's center
* @param {string|object} box container object or id
* @param {string|object} rectobj object to move
* @param {object} doc document object (optional)
* @type bool
* @returns true if success
*/
nebui.forcecenterinbox = function(box, rectobj, doc)
{with(this){
	if (!(box=nebui.getobj(box,doc||document))) return false;
	if (!doc) doc= nebui.mydoc(box);
	if (!(rectobj=nebui.getobj(rectobj,doc))) return -1;
	setx(rectobj, getx(box,doc) + (getw(box,doc) - getw(rectobj,doc))/2 );
	sety(rectobj, gety(box,doc) + (geth(box,doc) - geth(rectobj,doc))/2 );
	return true;
}};


/**
* Prpares a button to be a three-state hover one
* @param {string|object} obutt the button
* @returns 1 if success
*/
nebui.setup3statebutton = function(obutt, state_default, state_hover, state_pressed, exp2eval)
{
	if (!(obutt=nebui.getobj(obutt))) return 0;
	obutt.onselectstart= obutt.ondrag= function(){return 0};
	if (obutt.nodeName == "img")
	{
		obutt.onmouseover= function(){this.src=state_hover;return 1};
		obutt.onmousedown= function(){this.src=state_pressed;return 1};
		obutt.onmouseup= function(){this.src=state_default;eval(exp2eval);return 1};
		obutt.onmouseout= function(){this.src=state_default;return 1};	
	}
	else
	{
		obutt.onmouseover= function(){this.className=state_hover;return 1};
		obutt.onmousedown= function(){this.className=state_pressed;return 1};
		obutt.onmouseup= function(){this.className=state_default;eval(exp2eval);return 1};
		obutt.onmouseout= function(){this.className=state_default;return 1};
	}
	nebui.purgeable(obutt, ["onmouseover","onmousedown","onmouseup","onmouseout"]);
	return 1;
};

/**
* Checks a form wether it changed from the last call of nebui.checkform
* @param (string|object) formobj the form or the id of the form
* @param (bool) check initialize(false) or check(true) the form
* @type bool
* @returns (bool) wether the form has changed
*/
nebui.checkform = function(formobj, check)
{
	if (!(formobj=nebui.getobj(formobj))) return 0;
	for(var i=0; i<formobj.elements.length; ++i)
	{
		var e= formobj.elements[i];
		if (!check)//save old value
		{
			e.old_value= e.value;//for text input
			e.old_checked= e.checked;//for checkbox/radiobutton
			e.old_selectedIndex= e.selectedIndex;//for combobox
		}
		else
			if ( (e.value != e.old_value) || (e.checked != e.old_checked) || (e.old_selectedIndex != e.selectedIndex) )
				return true;
	}//i
	return false;
};

/*
nebui.errmsg= function(par)
{
	alert("Error in " + par.func + ": " + par.reason);
	return false;
};
*/
nebui.padstr= function(s, len, padchar, bafter)
{
	s= s.toString();
	if (!padchar) padchar="_";
	for(var i= s.length; i<len; ++i) if (bafter) s+= padchar;else s= padchar + s;
	return s;
};

/**
* Adds or removes a classname to a (space-concatenated) classname
* @param (string) classname original classname
* @param (string) rg_class2add classname to add/remove (regexp!)
* @param (bool) bremove adding or removing
*/
nebui.addclass= function(classname, rg_class2add, bremove)
{
	var cnames= classname.split(/ +/);
	var bfound=0;
	var res="";
	for(var i=0; i<cnames.length; ++i)
	{
		if (bremove && cnames[i].match(rg_class2add)) continue;
		if (!bremove && cnames[i].match(rg_class2add)) bfound=1;
		res+= cnames[i] + " ";
	}
	if (res!="") res=res.slice(0,-1);
	if (!bremove && !bfound) res+= (res==""?"":" ")+rg_class2add;
	return res;
};

/**
* Object to get the mouse's actual screen coordinates from the event
*/
nebui.getmouse = {
	x:0,y:0,button:"",element:null,//actual mouse coords

/**
* Function to get the mouse cooordinates
* 
* It fills the member vars of nebui.getmouse object
* @param {object} e event - optional in IE
* @type bool
* @returns false
*/
	get:function(e, win){with(nebui.getmouse){
		x=-1;y=-1;button="";element=null;
		
		//window.top.document.title= "x:"+event;
		if (e && (typeof event !="object"))//moz
		{
			x = e.pageX;
			y = e.pageY;
			element= e.originalTarget;
			abutt= ["left","middle","right","",""];
			if (e.button>=0) button= abutt[e.button];//0:left, 1:right
		}
		else//ie
		{
			win= win||window;
			if (!win.event) return false;
			var doc= win.document;

			x = win.event.clientX + doc.body.scrollLeft;
			y = win.event.clientY + doc.body.scrollTop;

			element= win.event.srcElement;
			abutt= ["left","left","right","","middle"];
			if (win.event.button>=0) button= abutt[win.event.button];//0:left, 1:right
		}
		return false;//important for correct behaviour
	}}

};//getmouse


nebui.pusheventhandler= function(object, eventname, handlerfunc, scopeobj, captphase)
{
	if (!handlerfunc || !(object=nebui.getobj(object))) return false;
	scopeobj= scopeobj || object;
	var f= function(e){
		return (typeof event == "object") ? handlerfunc.call(scopeobj) : handlerfunc.call(scopeobj, e);
	};

	if (window.addEventListener)
		object.addEventListener(eventname.replace(/^on/i,""), f, captphase);
	else
	if (window.attachEvent)
		object.attachEvent(eventname.replace(/^(on)*/,"on"), f);

	//var harr= "object." + eventname.replace(/^(on)*/,"on") + "s" + (captphase?1:0);
	//eval("if (!" + harr + ") " + harr + "=[];");
	//eval(harr + ".push(f);");

	return f;
};

nebui.deleventhandler= function(object, eventname, handlerfunc, captphase)
{
	if (!(object=nebui.getobj(object))) return false;

	if (window.removeEventListener)
		object.removeEventListener(eventname.replace(/^on/i,""), handlerfunc, captphase);
	else
	if (window.detachEvent)
		object.detachEvent(eventname.replace(/^(on)*/,"on"), handlerfunc);
	/*
	eventname= eventname.replace(/^(on)* /,"on");
	var harr= object[eventname + "s" + (captphase?1:0)];
	if (!harr) return null;
	var harr2=[];
	for(var i=0;i<harr.length;++i)
		if (harr[i] != handlerfunc) harr2.push(harr[i]);
	harr= harr2;
	*/
};

nebui.popeventhandler= function(object, eventname, captphase)
{
	if (!(object=nebui.getobj(object))) return false;
	eventname= eventname.replace(/^(on)*/,"on");
	eval("var harr= object." + eventname + "s" + (captphase?1:0));
	if (!harr) return null;
	var popped= harr.pop();//alert(popped);
	nebui.deleventhandler(object, eventname, popped, captphase);
	return popped;
};



/**
 *
 *
 *
 *   
 **/
nebui.mask= function(par)
{
	par= par || {};
	var win= par.win || window;
	this.doc= win.document;
	
	this.parent= nebui.getobj(par.parent, this.doc) || this.doc.body;
	this.zIndex= par.zIndex ? parseInt(par.zIndex) : 0;
	this.className= par.className || "nebui-mask";
	this.ballowscroll= par.ballowscroll ? true : false;
	this._mask= null;

	if (par.bshow)
		this.show();

	//return this;
};

nebui.mask.prototype.hide= function()
{
	if (!this._mask) return;
	this._mask.style.display= "none";
	if (this.parentpos && this.parentpos.owf)
		this.parent.style.overflow= this.parentpos.owf;
};

nebui.mask.prototype.show= function()
{
	//removing the mask from its parent if needed
	this.hide();

	var bfull= (this.parent == this.doc.body);

	this.parentpos= {x:nebui.getx(this.parent), y:nebui.gety(this.parent)};
	if (!this.ballowscroll)
	{
		if (this.parent.scrollIntoView)
			this.parent.scrollIntoView(true);
		if (this.parent.doScroll)
		{
			this.parent.doScroll("top");
			this.parent.doScroll("left");
		}
	}

	this.parentpos.owf= nebui.getCurrentStyle(this.parent,"overflow");
	if (!this.ballowscroll)
		this.parent.style.overflow= "hidden";
	
	var bnew=0, st=null;
	if (!this._mask)
	{
		bnew=1;
		this._mask= this.doc.createElement("div");
		st= this._mask.style;
		st.position= "absolute";
		st.width= (this.ballowscroll || !document.all) ? "150%" : (parseInt(this.doc.body.clientWidth) + 20) + "px";
		st.height= "120%";
		this._mask.className= this.className;
	}
	if (!st) st= this._mask.style;
	st.zIndex= this.zIndex;
	st.left= (this.ballowscroll ? this.parent.scrollLeft : 0) + "px";//"0px";
	st.top= (this.ballowscroll ? this.parent.scrollTop : 0) + "px";//"0px";
	st.display="block";
	if (bnew)
		this.parent.appendChild(this._mask);
};













/**
 * fights IE garbage collector bug
 *
**/
nebui.pusheventhandler(window, "onunload", function(e){
	var p= nebui.purgelist;
	//alert(p.length);
	for(var i=0; i<p.length; ++i)
	{
		if (!p[i] || !p[i].o || !p[i].o[p[i].m]) continue;
		p[i].o[p[i].m]=null;
		p[i].o=null;
	}
});

