//<![CDATA[

var dragger = function(elem, cont, opac) {
	this.initialize(elem, cont, opac);
}
var dp = dragger.prototype;

dp.initialize = function(elem, cont, opac) {
	this.elem = elem;
	this.cont = cont;
	this.resetDrag();
	addListener(this.cont, "mousedown", fn(this, "startDrag"));
	addListener(this.elem, "mousedown", fn(this, "startDrag"));
	addListener(window.document, "mouseup", fn(this, "stopDrag"));
	addListener(window.document, "mousemove", fn(this, "doDrag"));
	if(opac)
		setCSSOpacity(this.elem, opac);
}

dp.unbind = function() {
	removeListener(this.cont, "mousedown", fn(this, "startDrag"));
	removeListener(this.elem, "mousedown", fn(this, "startDrag"));
	removeListener(this.cont, "mouseup", fn(this, "stopDrag"));
	removeListener(window.document, "mousemove", fn(this, "doDrag"));
}

dp.resetDrag = function() {
	this.dragging = false;
	this.pos = {cont:undefined, elem:undefined, mouse:{x:undefined, y:undefined}}
}

dp.resetElem = function() {
	setElementSize(this.elem, 0, 0);
}

dp.startDrag = function(e) {
	var evt = getEventObject(e);
	evt.preventDefault();
	evt.stopPropagation();

	var p = getElementPosition(this.cont);
	this.pos = {cont:p, mouse:{x:evt.mouse.x, y:evt.mouse.y}};

	setElementPosition(this.elem, this.pos.mouse.x, this.pos.mouse.y);
	this.resetElem();

	this.dragging = true;
}

dp.stopDrag = function(e) {
	var o, or, pr, c, p, x, y, evt;
	if(this.dragging) {
		this.resetDrag();
		evt = getEventObject(e);
		evt.stopPropagation();
		o = getElementPosition(this.elem);
		c = getElementPosition(this.cont);

		if(o.width) {
			or = {};
			for(pr in o)
				or[pr] = o[pr];
			or.left -= c.left;
			or.top -= c.top;
			or.right -= c.left;
			or.bottom -= c.top;
			this.onenddrag({abs:o, rel:or});
		}
		else {
			p = evt.mouse;
			x = p.x - c.left;
			y = p.y - c.top;
			this.onclick({abs:p, rel:{x:x, y:y}});
		}
	}
}

dp.onenddrag = function(o) {};
dp.onclick = function(p) {};

dp.doDrag = function(e) {
	if(this.dragging) {
		var evt = getEventObject(e);
		evt.preventDefault();
		var pos = this.pos.mouse;

		var p = evt.mouse;
		var c = this.pos.cont;
		var o = this.elem;

		var maxx = c.right;
		var maxy = c.bottom;

		var curx = Math.min(Math.max(c.left, p.x), maxx);
		var cury = Math.min(Math.max(c.top, p.y), maxy);

		var dx = Math.min(curx, pos.x);
		var dy = Math.min(cury, pos.y);

		var w = Math.abs(Math.max(pos.x, curx) - dx);
		var h = Math.abs(Math.max(pos.y, cury) - dy);

		setPosition(o, dx, dy);
		setElementSize(o, w, h);
	}
}

var slider = function(elem, cont, ratio) {
	this.elem = elem;
	this.cont = cont;
	this.steps = ratio;
	this.pos = getElementPosition(this.cont);
	this.cont.style.cursor = "pointer";
	addListener(this.cont, "mousedown", fn(this, "startMove"));
	addListener(this.cont, "mousemove", fn(this, "doMove"));
	addListener(document.body, "mouseup", fn(this, "endMove"));
}

var sp = slider.prototype;

sp.getX = function(evt) {
	return this.fixX(evt.mouse.x - this.pos.left);
}

sp.getRange = function(p) {
	return Math.round(p / this.pos.width * this.steps);
}

sp.fixX = function(x) {
	return Math.max(Math.min(x, this.pos.width), 0);
}

sp.moveElem = function(evt) {
	if(this.steps)
		this.moveToRange(this.getRange(this.getX(evt)));
	else
		this.moveToPix(this.getX(evt));
}

sp.startMove = function(e) {
	var evt = getEventObject(e);
	evt.preventDefault();
	evt.stopPropagation();

	this.moving = true;
	this.moveElem(evt);
}

sp.endMove = function(e) {
	if(this.moving) {
		this.moving = false;
		var evt = getEventObject(e);
		evt.stopPropagation();
		var abs = this.getX(evt);
		var perc = abs / this.pos.width;
		var rng = this.getRange(abs);
		this.onmove({abs:abs, perc:perc, rng:rng});
	}
}

sp.doMove = function(e) {
	if(this.moving) {
		var evt = getEventObject(e);
		evt.preventDefault();
		this.moveElem(evt);
		this.onmoving(evt.mouse, this.getRange(this.getX(evt)), this.steps);
	}
}

sp.moveToRange = function(rng) {
	this.moveToPix(this.pos.width / this.steps * rng);
}

sp.moveToPix = function(p) {
	this.elem.style.width = px(p);
}

sp.onmove = function(o) {};
sp.onmoving = function(m) {};

//]]>
