var DHTML = new function() {

	this.get = this.bind = function(e) { 
		if (!(e = DOM.get(e))) return null;

		OO.apply(e, this.Base);
		
		for (var superClass,index = 1;(superClass = arguments[index]);index++) {
			e.inherit(superClass);
		}
		
		e.ooInitSelf.apply(e);
		return e;
	}

	this.create = function(type) {
		var e = document.createElement(type);
		if (!e) return null;
		
		OO.apply(e, this.Base);
		
		for (var superClass,index = 1;(superClass = arguments[index]);index++) {
			e.inherit(superClass);
		}
		
		e.ooInitSelf.apply(e);
		return e;
	}
	
	this._path = function(start, end, time) {
		var time = Math.ceil(time / 25);
		var period = Math.PI / (2 * time);
		var result = [];
		end -= start;
		for (var index = 0; index <= time; index++) { result.push(Math.round(end * Math.sin(period * index) + start)); }
		return result;
	}

	this._path = function(start, end, time) {
		var time = Math.ceil(time / 25);
		var period = Math.PI / (2 * time);
		var result = [];
		end -= start;
		for (var index = 0; index <= time; index++) { result.push(Math.round(end * Math.sin(period * index) + start)); }
		return result;
	}
	
	this.clientHeight = function() {
		return document.body.clientHeight || window.innerHeight;
	}
	
	this.clientWidth = function() {
		return document.body.clientWidth || window.innerWidth;
	}
	
	this.structure = function(e) {
		return this.get(DOM.structure(e));
	}
}

DHTML.Base = function() {
	
	this.Base = { o: 100 };
}


DHTML.Base.prototype = {
	divX: function(x) { res = this.offsetLeft - this.offsetParent.scrollLeft; if (UTIL.def(x)) this.setLeft(x); return res;},
	divY: function(y) { res = this.offsetTop - this.offsetParent.scrollTop; if (UTIL.def(y)) this.setTop(y); return res; },
	
	initSelf: function() {
		if (UTIL.def(this.style.pixelLeft)) { 
			this.setLeft = function(x) { this.style.right = ''; this.style.pixelLeft = x; };
			this.setRight = function(x) { this.style.left = ''; this.style.pixelRight = x; };
			this.setTop = function(y) { this.style.bottom = ''; this.style.pixelTop = y; };
			this.setBottom = function(y) { this.style.top = ''; this.style.pixelBottom = y; };
		} else if (UTIL.def(this.style.left)) {
			this.setLeft = function(x) { this.style.right = ''; this.style.left = x+'px'; };
			this.setRight = function(x) { this.style.left = ''; this.style.right = x+'px'; };
			this.setTop = function(y) { this.style.bottom = ''; this.style.top = y+'px'; };
			this.setBottom = function(y) { this.style.top = ''; this.style.bottom = y+'px'; };
		}		
		
		if (UTIL.def(this.style.filter)) {
			this.setOpacity = function(o) { this.Base.o = o; this.style.filter = 'alpha(opacity='+o+')'; };
		} else if (UTIL.def(this.style.MozOpacity)) {
			this.setOpacity = function(o) { this.Base.o = o; this.style.MozOpacity = Math.min(o / 100, 0.9999); };
		} else {
			this.setOpacity = function(o) { this.Base.o = o; this.style.opacity = Math.min(o / 100, 0.9999); };
		}
	},
	
	hScroll: function(l) { result = this.scrollLeft; if (U.def(l)) this.scrollLeft = l; return result; },
	setWidth: function(w) { this.style.width = w+'px'; },
	setHeight: function(h) { this.style.height = h+'px'; },
	moveTo: function(x, y) { this.setLeft(x); this.setTop(y); },
	sizeTo: function(w, h) { this.setWidth(w); this.setHeight(h); },

	getWidth: function() { return parseInt(this.offsetWidth, 10); },
	getHeight: function() { return parseInt(this.offsetHeight, 10); },
	getOpacity: function() { return this.Base.o; },
	
	fontSize: function(newSize) { var result = parseInt(this.style.fontSize, 10); if (typeof(newSize) != 'undefined') this.style.fontSize = newSize+'px'; return result; },
	
	center: function(h, v) {
		if (h) { this.setLeft(Math.round((this.offsetParent.offsetWidth - this.offsetWidth) / 2)); }
		if (v) { this.setTop(Math.round((this.offsetParent.offsetHeight - this.offsetHeight) / 2)); }
	},
	
	pageX: function() {
		var e = this; var x = this.offsetLeft;
		while (e=e.offsetParent) x += (e.offsetLeft - e.scrollLeft);
		return x;
	},

	pageY: function() {
		var e = this; var y = this.offsetTop;
		while (e=e.offsetParent) y += (e.offsetTop - e.scrollTop);
		return y;
	},
	
	show: function() { this.style.visibility = 'visible'; },
	hide: function() { this.style.visibility = 'hidden'; },
	display: function(d) { this.style.display = d; },
	zIndex: function(z) { r = parseInt(this.style.zIndex, 10); if (U.def(z)) this.style.zIndex = z; return r; },

	pos: function(s) { var key; for (key in s) this[key](s[key]); }
}


DHTML.Anim = function() {
	this.Anim = { };
	this.inherit(OO.Timer);
}


DHTML.Anim.prototype = {
	
	initSelf: function() {
		this.count = 0;
		this.X = this.divX;
		this.Y = this.divY;
		this.F = this.fontSize;
		this.SL = this.hScroll;
		this.oX = function(offset) { if (U.def(offset)) { this.divX(this.divX()+offset); if (this._offsetX) this._offsetX(offset); } return 0;};
		this.oY = function(offset) { if (U.def(offset)) { this.divY(this.divY()+offset); if (this._offsetY) this._offsetY(offset); } return 0;};
		this.W = function(w) { r = this.getWidth(); if (U.def(w)) this.setWidth(w); return r; };
		this.H = function(h) { r = this.getHeight(); if (U.def(h)) this.setHeight(h); return r; };
		this.O = function(o) { r = this.getOpacity(); if (U.def(o)) this.setOpacity(o); return r; };
	},
	
	stopAnimation: function() {
		this.clearInterval('animate');
	},
	
	animate: function(s, t, d) {
		if (U.def(d)) { this.setTimeout('delay_'+this.count, d, this.animate, s, t); this.count++; return; }
		this.Anim = { current: 0, direc: 1, paths: { } };
		var key;
		for (key in s) { 
			this.Anim.paths[key] = DHTML._path(this[key](), s[key], t);  
			if ((key == 'oX') || (key == 'oY')) {
				var total = 0;
				for (index = 0; index < this.Anim.paths[key].length; index++) {
					this.Anim.paths[key][index] -= total;
					total += this.Anim.paths[key][index];
				}
			}
		}
		
		this.setInterval('animate', 25, this._animate);
	},

	_animate: function() {
		var val;
		for (key in this.Anim.paths) {	
			if (!U.def(val = this.Anim.paths[key][this.Anim.current])) { this.clearInterval('animate'); return; }
			this[key](val);
		}
		this.Anim.current += this.Anim.direc;
	}
}

DHTML.Event = function() {
	this.Events = {  }
}

DHTML.Event.prototype = {
	EventHandler: function(e) {
		e = EVENT._event(e);
		var list; 
		if (!(list = this.Events[e.type])) return;
		
		for (var h,i=0;(h = list[i]);i++) if (h.call(this, e)==false) return false;
	},
	
	addListener: function(type, fn) {
		this['on'+type] = this.EventHandler;
		(this.Events[type] = this.Events[type] || [ ]).unshift(fn);
	}
}

DHTML.Drag = function() {
	
	this.inherit(DHTML.Event);
}
DHTML.Drag.prototype = {

	initSelf: function() {
		this.Drag = { active: false, clone: null, constrain: null };
		this.addListener('mousedown', this._dragMousedown);
		this.setConstrain(this.offsetParent);
		if (this.offsetParent) DHTML.get(this.offsetParent);
	},
	
	setClone: function(clone) { this.Drag.clone = DOM.get(clone);	},

	setScroll: function(scrollEle) { this.Drag.scrollEle = DOM.get(scrollEle);	},
	
	setDragHandle: function(handle) { this.Drag.handle = handle; },
	
	setConstrain: function(constrainEle, t, r, b, l) {
		this.Drag.constrainDelta = { t: (t) ? t : 0, r: (r) ? r : 0, b: (b) ? b : 0, l: (l) ? l : 0 };
		this.Drag.constrainEle = DHTML.get(constrainEle);
	},
	
	_dragMousedown: function(e) {
		var oThis = this;
		if (this.Drag.active) return;
		if (e.target.noDrag) return;
		if (this.Drag.handle && (e.target != this.Drag.handle)) return;
		if (this.Drag.clone) { 
			this.Drag.clone._cloneDrag(this, e);
			
			return;
		}
		
		this.Drag.start = { x: this.X(), y: this.Y(), mX: e.pageX, mY: e.pageY }; 
		this.Drag.current = U.copy(this.Drag.start);
		this.Drag.actual = U.copy(this.Drag.start);
		
		this.Drag.events = {	mousemove:	EVENT.attachEvents(document, 'mousemove', function(e) { oThis._dragMousemove(e); }),
								mouseup: EVENT.attachEvents(document, 'mouseup', function(e) { oThis._dragMouseup(e); }) };
		this.setDragConstraints();
		this.onDragStart();
		this.setInterval('dragging', 100, this.onDrag);
		if (this.Drag.scrollEle) this.setInterval('scrolling', 100, this._scrollCheck);
		
		this.Drag.active = true;
		
		EVENT.stopAll(e);
		return false;
	},
	
	_dragMousemove: function(e) { 
		var dX,dY; 

		dX = e.pageX - this.Drag.current.mX;
		dY = e.pageY - this.Drag.current.mY;
		
		this.Drag.actual.x  = (this.Drag.current.x += dX); 
		this.Drag.actual.y  = (this.Drag.current.y += dY); 
		this.Drag.current.mX = e.pageX;
		this.Drag.current.mY = e.pageY;
				
		this._dragConstrain();
		
		this.moveTo(this.Drag.actual.x, this.Drag.actual.y);

		EVENT.stopAll(e);
		return false;
	},
	
	_dragMouseup: function(e) { 
		EVENT.removeEvents(document, 'mousemove', this.Drag.events.mousemove);
		EVENT.removeEvents(document, 'mouseup', this.Drag.events.mouseup);
		this.clearInterval('dragging');
		this.clearInterval('scrolling');
		
		this.Drag.active = false;
		this.onDragEnd();

		EVENT.stopAll(e);
		return false;
	},

	_dragConstrain: function() {
		this.Drag.actual.x = Math.max(this.Drag.constrain.minX, Math.min(this.Drag.constrain.maxX, this.Drag.actual.x));
		this.Drag.actual.y = Math.max(this.Drag.constrain.minY, Math.min(this.Drag.constrain.maxY, this.Drag.actual.y));
	
	},
	
	_offsetX: function(offset) { if (this.Drag.current) this.Drag.current.x += offset; },
	_offsetY: function(offset) { if (this.Drag.current) this.Drag.current.y += offset; },
	
	_cloneDrag: function(ele, e) {
		this.Drag.dragEle = ele;
		this.innerHTML = '';
		this.appendChild(ele.cloneNode(true));
		this.firstChild.id = '';
		this.moveTo(ele.pageX() - (this.pageX() - this.divX()), ele.pageY() - (this.pageY() - this.divY()));
		this.sizeTo(ele.getWidth(), ele.getHeight());
		xShow(this);
		this._dragMousedown(e);
	},
	
	_scrollCheck: function() {
		var s = this.Drag.scrollEle;
		var px = s.pageX();
		var py = s.pageY();
		var t =  this.Drag.current.mY - py;
		var l =  this.Drag.current.mX - px;
		var b =  py + s.getHeight() - this.Drag.current.mY;
		var r =  px + s.getWidth() - this.Drag.current.mX;

		if (t < 20) s.scrollTop -= (20 - (Math.max(t, 0)))
		else if (b < 20) s.scrollTop += (20 - (Math.max(b, 0)));
		if (l < 20) s.scrollLeft -= (20 - (Math.max(l, 0)))
		else if (r < 20) s.scrollLeft += (20 - (Math.max(r, 0)));
	},
	
	onDrag: function() { },
	onDragStart: function() { },
	onDragEnd: function() { },

	setDragConstraints: function() {
		var d = this.Drag.constrainDelta;
		var x = this.Drag.constrainEle.pageX() - this.offsetParent.pageX();
		var y = this.Drag.constrainEle.pageY() - this.offsetParent.pageY();
		this.setConstraintRect(y + d.t, x + this.Drag.constrainEle.getWidth() - d.r, y + this.Drag.constrainEle.getHeight() - d.b, x + d.l);
	},
	
	setConstraintRect: function(minY, maxX, maxY, minX) {
		this.Drag.constrain = { minX: minX, minY: minY, maxX: maxX - this.W(), maxY: maxY - this.H() };
	}
	
	}
	
DHTML.PageResizer = function() {
	this.inherit(OO.Timer, OO.Broadcaster);
	this.Page = { width: 0, height: 0 };
	}
DHTML.PageResizer.prototype = {
	initSelf: function(controller) {
		this.setInterval('pageResizeCheck', 200, this._resizePage);
		this.addListener(controller); 
	},
	
	_resizePage: function() {
		var width = DHTML.clientWidth();
		var height = DHTML.clientHeight();

		if ((width == this.Page.width) && (height == this.Page.height)) return;
	
		this.Page.width = width;
		this.Page.height = height;
		this.sendMessage('pageResized', { width: width, height: height } );
	}
}

DHTML.EditField = function() {
}
DHTML.EditField.prototype = {
	initSelf: function() {
		EVENT.attachEvents(this, 'dblclick', this.editMode);
		this.inEditMode = false;
		this.disabledMode = false;
		this.useClassName = 'editField';
	},
	
	editMode: function(e) { 
		if (this.inEditMode || this.disabledMode) return;

		var oThis = this;
		var blurFn = function() { oThis.normalMode(); }

		this.fContent = this.innerHTML;
		this.input = DOM.structure( { t: 'input', e: { className: this.useClassName, value: this.fContent, onblur: blurFn, noDrag: 1 } } );
		this.parentNode.replaceChild(this.input, this);
		this.input.select();
		this.inEditMode = true;
		
		EVENT.stopAll(e); return false;
	},
	
	normalMode: function(e) {
		if (!this.inEditMode) return;
		
		this.innerHTML = this.fContent = this.input.value;
		
		this.input.parentNode.replaceChild(this, this.input);
		this.inEditMode = false;
	},
	
	disable: function(d) { this.disabledMode = true; },
	enable: function(d) { this.disabledMode = false; }
}