function moveable(elem, relative, IDLE, allowed_x, allowed_y){
	this.elem = elem;
	this.type = relative ? 'relative' : 'absolute';
	this._events = [
		{name: "move", func_name: "_moveBy"}	
	];
	this.onaftermove = new DOMEvent(this);
	this.STOP_X = false;
	this.STOP_Y = false;
	this.STOP = false;
	this.movedX = 0;
	this.movedY = 0;
	this.moveX = 0;
	this.moveY = 0;
	this.saveFloatX = new Nums.SaveFloatPoint();
	this.saveFloatY = new Nums.SaveFloatPoint();
	this.limits = {};
	this.PREVENT_DOUBLE_FIRE = true;
	this.directions = {
		X: true,
		Y: true
	};
	this.allowed = {
		X: (allowed_x || true),
		Y: (allowed_y || true)
	};
	this._IDLE = IDLE || false;
	this.init();
	if(this.constructor._TO_INSTANCES){
		this.constructor._instances.push(this);
	}
}
moveable.prototype.init = function(){
	this.elem.style.position = this.type;
	var coords = Style.getCoords(this.elem);
	this.left = coords.left; 
	this.top = coords.top;
	this.startX = this.left;
	this.startY = this.top;
	this._left = this.left;
	this._top = this._top;
	this.initEvents();
};
moveable.prototype.initEvents = _initEvents;
moveable.prototype.move = function(){
	if(!this._IDLE){
		this.elem.style.left = this.left + 'px';
		this.elem.style.top = this.top + 'px';
	}
	this.onaftermove.fire();
};
moveable.prototype.moveTo = function(x, y){
	this.moveBy(x - this.left, y - this.top);
};
moveable.prototype.moveBy = function(x, y){
	this.attemptedX = x;
	this.attemptedY = y;
	this.moveX = this.saveFloatX.test(x);
	this.moveY = this.saveFloatY.test(y);
	this._moveBy();
};
moveable.prototype._moveBy = function(){
	this.saveFloatX.add();
	this.saveFloatY.add();
	this.movedX += this.moveX;
	this.movedY += this.moveY;
	this.distanceX += Math.abs(this.moveX);
	this.distanceY += Math.abs(this.moveY);
	this.check_directions();
	this.left += this.moveX;
	this.top += this.moveY;
	if(!this.STOP){
		this.move();
	}else{
		this.STOP = false;
	}
};

moveable.prototype.check_directions = function(){
	this.directions.X = !this.moveX ? this.directions.X : (this.moveX > 0);
	this.directions.Y = !this.moveY ? this.directions.Y : (this.moveY > 0);
};
moveable.prototype.correctLimit = function(type, move){
	var lim = this.limits[type];
	if(!lim){
		return false;
	}
	var step = this["move" + type];
	var delta = move - step;
	lim.value -= delta;
};
moveable.prototype.setLimits = function(type, value, startValue){
	type = type.toUpperCase();
	if(this.limits[type]){
		return;
	}
	var PRESETS = moveable.LIMITS[type];
	this.limits[type] = new Limit(0, value);
	if(startValue){
		this.limits[type].value = startValue;
	}
	this.limits[type]._parent = this;
	this.limits[type].type = type;
	this.limits[type].MINUS_REACHED = false;
	this.limits[type].PLUS_REACHED = false;
	this.limits[type]._REACHED = false;
	this.limits[type].onmore.register(
		'limit-more',
		function(){
			var mov = this._parent;
			mov['move' + this.type] = this.MORE_VALUE;
			this._REACHED = true;
		}.bind(this.limits[type])
	);
	this.limits[type].onless.register(
		'limit-less',
		function(){
			var mov = this._parent;
			mov['move' + this.type] = this.LESS_VALUE;
			this._REACHED = true;
		}.bind(this.limits[type])
	);
	this[PRESETS.onmore] = DOMEvent.cloneEvent(this.limits[type].onmore, this);
	this[PRESETS.onless] = DOMEvent.cloneEvent(this.limits[type].onless, this);
	this[PRESETS.onmoreout] = DOMEvent.cloneEvent(this.limits[type].onmoreout, this);
	this[PRESETS.onlessout] = DOMEvent.cloneEvent(this.limits[type].onlessout, this);
	this.onmove.register(
		'limit' + type, 
		function(){
			var mov = this._parent;
			this.change(mov['move' + this.type]);
		}.bind(this.limits[type]), null, 0
	);
};	
moveable.prototype.setMoveSpace = function(X, Y, sX, sY){
	if(!this.moveSpace){
		this.moveSpace = {};
		this.onmovespacereach = new E_Connection(this);
		this.onmovespaceout = new E_Connection(this);
	}
	if(X || X === 0){
		this.moveSpace.X = X;
		this.setLimits('X', X, sX || 0);
		this.onmovespacereach.add(this.onleft, ["left", "X"]);
		this.onmovespacereach.add(this.onright, ["right", "X"]);
		this.onmovespaceout.add(this.onleftout, ["left", "X"]);
		this.onmovespaceout.add(this.onrightout, ["right", "X"]);
	}
	if(Y || Y === 0){
		this.moveSpace.Y = Y;
		this.setLimits('Y', Y, sY || 0);
		this.onmovespacereach.add(this.ontop, ["top", "Y"]);
		this.onmovespacereach.add(this.onbottom, ["bottom", "Y"]);
		this.onmovespaceout.add(this.ontopout, ["top", "Y"]);
		this.onmovespaceout.add(this.onbottomout, ["bottom", "Y"]);
	}
	return this.moveSpace;
};
moveable.prototype.reflect = function(lim){
	if(lim.TO_REACHED){
		this['move' + lim.type] = this['move' + lim.type] - lim.exceeded;
		lim.value -= lim.exceeded;
	}else if(lim.FROM_REACHED){
		this['move' + lim.type] = this['move' + lim.type] - lim.preceeded;
		lim.value -= lim.preceeded;
	}
};
moveable.prototype.__name = "moveable";
moveable.prototype.toString = __toString;

moveable.LIMITS = {
	X: {
		onless: 'onleft',
		onmore: 'onright',
		onmoreout: 'onrightout',
		onlessout: 'onleftout',
		less: 'left',
		more: 'right'
	},
	Y: {
		onless: 'ontop',
		onmore: 'onbottom',
		onlessout: 'ontopout',
		onmoreout: 'onbottomout',
		less: 'top',
		more: 'bottom'
	}
};
moveable.detectMoveable = function(oMoveable){	 
	if(!oMoveable){
		return false;
	}
	if(oMoveable instanceof moveable){
		oMoveable._MUTUAL = true;
		return oMoveable;
	}else{
		return new moveable(oMoveable, false)
	}
};
moveable._TO_INSTANCES = true;
moveable._instances = [];
moveable.__loaded = true;