//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/dhtml/drag-library [v1.1]

//=============================================================
// REQUIRES http://www.jsfromhell.com/geral/event-listener v1.4
//=============================================================


addEvent = function(o, e, f, s){
		var r = o[r = "_" + (e = "on" + e)] = o[r] || (o[e] ? [[o[e], o]] : []), a, c, d;
		r[r.length] = [f, s || o], o[e] = function(e){
			try{
				(e = e || event).preventDefault || (e.preventDefault = function(){e.returnValue = false;});
				e.stopPropagation || (e.stopPropagation = function(){e.cancelBubble = true;});
				e.target || (e.target = e.srcElement || null);
				e.key = (e.which + 1 || e.keyCode + 1) - 1 || 0;
			}catch(f){}
			for(d = 1, f = r.length; f; r[--f] && (a = r[f][0], o = r[f][1], a.call ? c = a.call(o, e) : (o._ = a, c = o._(e), o._ = null), d &= c !== false));
			return e = null, !!d;
		}
	};

	removeEvent = function(o, e, f, s){
		for(var i = (e = o["_on" + e] || []).length; i;)
			if(e[--i] && e[i][0] == f && (s || o) == e[i][1])
				return delete e[i];
		return false;
	};
	Dragger = function(o, a, area){
		var $ = this;
		o.style.position = "absolute", $.object = o, $.d = {x: 0, y: 0}, $.f = [];
		a && (addEvent(area, "mousedown", function(){return this.start(), false;}, $),
			addEvent(document, "mouseup", function(){this.stop();}, $));
	}
	/*Dragger = function(o, a){
		var $ = this;
		o.style.position = "absolute", $.object = o, $.d = {x: 0, y: 0}, $.f = [];
		a && (addEvent(o, "mousedown", function(){return this.start(), false;}, $),
			addEvent(document, "mouseup", function(){this.stop();}, $));
	}*/
	with({p: Dragger.prototype, c: Dragger}){
		p._updateMouse = function(e){
			var w = window, b = document.body;
			p.mouse = {x: e.clientX + (w.scrollX || b.scrollLeft || b.parentNode.scrollLeft || 0),
				y: e.clientY + (w.scrollY || b.scrollTop || b.parentNode.scrollTop || 0)};
		};
		addEvent(document, "mousemove", p._updateMouse);
		p.mouse = {x: 0, y: 0};
		p.dragging = false;
		p.start = function(center){
			var r, $ = this, m = $.mouse, o = $.object;
			for(var r = {l: o.offsetLeft, t: o.offsetTop, w: o.offsetWidth, h: o.offsetHeight};
				o = o.offsetParent; r.l += o.offsetLeft, r.t += o.offsetTop);
			!$.dragging && ($.dragging = true, o = $.object, $.d = center &&
				(m.x < r.l || m.x > r.l + r.w || m.y < r.t || m.y > r.t + r.h) ?
				{x: r.w / 2, y: r.h / 2} : {x: m.x - o.offsetLeft, y: m.y - o.offsetTop},
				addEvent(document, "mousemove", $.drag, $),
				this.callEvent("onstart"));
		};
		p.drag = function(e){
			var i, p, $ = this, o = $.object, m = ($._updateMouse(e), (m = $.mouse).x -= $.d.x, m.y -= $.d.y, m);
			for(i = $.f.length; i; $.f[--i] && $.f[i][0].apply(m, $.f[i][1]));
			o.style.left = m.x + "px", o.style.top = m.y + "px";
			return !!this.callEvent("ondrag", e);
		};
		p.stop = function(){
			this.dragging = false;
			removeEvent(document, "mousemove", this.drag, this);
			this.callEvent("onstop");
		};
		p.addFilter = function(f, arg0, arg1, arg2, argN){
			this.f[this.f.length] = [f, [].slice.call(arguments, 1)];
		};
		p.callEvent = function(e){
			return this[e] instanceof Function ? this[e].apply(this, [].slice.call(arguments, 1)) : undefined;
		};
	}

	Dragger.filters = new function(){
		function lineLength(x, y, x0, y0){
			return Math.sqrt((x -= x0) * x + (y -= y0) * y);
		}
		function dotLineLength(x, y, x0, y0, x1, y1, o){
			if(o && !(o = function(x, y, x0, y0, x1, y1){
				if(!(x1 - x0)) return {x: x0, y: y};
				else if(!(y1 - y0)) return {x: x, y: y0};
				var left, tg = -1 / ((y1 - y0) / (x1 - x0));
				return {x: left = (x1 * (x * tg - y + y0) + x0 * (x * - tg + y - y1)) /
					(tg * (x1 - x0) + y0 - y1), y: tg * left - tg * x + y};
			}(x, y, x0, y0, x1, y1), o.x >= Math.min(x0, x1) && o.x <= Math.max(x0, x1)
			&& o.y >= Math.min(y0, y1) && o.y <= Math.max(y0, y1))){
				var l1 = lineLength(x, y, x0, y0), l2 = lineLength(x, y, x1, y1);
				return l1 > l2 ? l2 : l1;
			}
			else{
				var a = y0 - y1, b = x1 - x0, c = x0 * y1 - y0 * x1;
				return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b);
			}
		}
		this.SQUARE = function(x, y, w, h){
			this.x = this.x < x ? x : this.x > x + w ? x + w : this.x,
			this.y = this.y < y ? y : this.y > y + h ? y + h : this.y;
		};
		this.CIRCLE = function(x, y, ray){
			var tg;
			lineLength(this.x, this.y, x += ray, y += ray) > ray &&
				(this.x = Math.cos(tg = Math.atan2(this.y - y, this.x - x)) * ray + x,
				this.y = Math.sin(tg) * ray + y);
		};
		this.LINE = function(x, y, angle){
			if(!(angle % 90))
				return this.x = x;
			var tg = Math.tan(-angle * Math.PI / 180);
			Math.sin(45 * Math.PI / 180) >= Math.sin(angle * Math.PI / 180) ?
				this.y = (this.x - x) * tg + y : this.x = (this.y - y) / tg + x;
		};
		this.POLY = function(x0, y0, x1, y1, etc, etc, etc){
			for(var a = [].slice.call(arguments, 0), lines = []; a.length > 3;
				lines[lines.length] = {y1: a.pop(), x1: a.pop(), y0: a.pop(), x0: a.pop()});
			if(!lines.length)
				return;
			for(var l, i = lines.length - 1, o = lines[i],
				lower = {i: i, l: dotLineLength(this.x,	this.y, o.x0, o.y0, o.x1, o.y1, 1)};
				i--; lower.l > (l = dotLineLength(this.x, this.y,
				(o = lines[i]).x0, o.y0, o.x1, o.y1, 1)) && (lower = {i: i, l: l}));
			this.y < Math.min((o = lines[lower.i]).y0, o.y1) ? this.y = Math.min(o.y0, o.y1)
				: this.y > Math.max(o.y0, o.y1) && (this.y = Math.max(o.y0, o.y1));
			this.x < Math.min(o.x0, o.x1) ? this.x = Math.min(o.x0, o.x1)
				: this.x > Math.max(o.x0, o.x1) && (this.x = Math.max(o.x0, o.x1));
			Math.abs(o.x0 - o.x1) < Math.abs(o.y0 - o.y1) ?
				this.x = (this.y * (o.x0 - o.x1) - o.x0 * o.y1 + o.y0 * o.x1) / (o.y0 - o.y1)
				: this.y = (this.x * (o.y0 - o.y1) - o.y0 * o.x1 + o.x0 * o.y1) / (o.x0 - o.x1);
		};
	};