function moveable(elem){
	this.elem = elem;
	this.movedX = 0;
	this.movedY = 0;
	this.moveX = 0;
	this.moveY = 0;
	this._moveX = 0;
	this._moveY = 0;
	this.distanceX = 0;
	this.distanceY = 0;
	this.directions = {X: 0, Y: 0};
	this.saveFloatX = new Nums.SaveFloatPoint();
	this.saveFloatY = new Nums.SaveFloatPoint();
	this.limits = {};
	this.init();
	if(this.constructor._TO_INSTANCES){
		this.constructor._instances.push(this);
	}
}
moveable.prototype.init = function(){
	this.elem.style.position = "absolute";
	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.init_events();
};
moveable.prototype.move = function(){
	if(!this._IDLE){
		this.elem.style.left = this.left + 'px';
		this.elem.style.top = this.top + 'px';
	}
};
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(this.moveX, this.moveY);
};
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.left += this.moveX;
	this.top += this.moveY;
	//direction
		if(this._moveX._signOf() != this.moveX._signOf()){
			this.changedir('X', this.moveX._signOf(), this._moveX._signOf());
		}
		if(this._moveY._signOf() != this.moveY._signOf()){
			this.changedir('Y', this.moveY._signOf(), this._moveY._signOf());
		}
		this._moveX = this.moveX;
		this._moveY = this.moveY;
	//
	this.move();
};
moveable.prototype.changedir = function(type, to, from){
	this.directions[type] = to;
};
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){
	if(!window.Limit){
		alert('please, include limit.js');
		return false;
	}
	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, [{side: 'left', type: 'X', limit: this.limits.X}]);
		this.onmovespacereach.add(this.onright, [{side: 'right', type: 'X', limit: this.limits.X}]);
		this.onmovespaceout.add(this.onleftout, [{side: 'left', type: 'X', limit: this.limits.X}]);
		this.onmovespaceout.add(this.onrightout, [{side: 'right', type: 'X', limit: this.limits.X}]);
	}
	if(Y || Y === 0){
		this.moveSpace.Y = Y;
		this.setLimits('Y', Y, sY || 0);
		this.onmovespacereach.add(this.ontop, [{side: 'top', type: 'Y', limit: this.limits.Y}]);
		this.onmovespacereach.add(this.onbottom, [{side: 'bottom', type: 'Y', limit: this.limits.Y}]);
		this.onmovespaceout.add(this.ontopout, [{side: 'top', type: 'Y', limit: this.limits.Y}]);
		this.onmovespaceout.add(this.onbottomout, [{side: 'bottom', type: 'Y', limit: this.limits.Y}]);
	}
	return this.moveSpace;
};
moveable.prototype.reflect = function(lim){
	if(lim.TO_REACHED){
		var val = lim.MORE_VALUE - lim.exceeded;
		this['move' + lim.type] = val;
		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.setGrid = function(grid, left, top){
	this.grid = grid;
	this.grid.left = left;
	this.grid.top = top;
	this.grid.current = {x: -1, y: -1};
	this.onaftermove.register('grid', function(){
		var grid_el = this.grid.get_elem(this.left - this.grid.left, this.top - this.grid.top);
		if(!Grid.eq(this.grid.current, grid_el)){
			this.ongridchange.fire(grid_el, this.grid.current);
			this.grid.current = grid_el;
		}
	});
	this.ongridchange = new DOMEvent(this);
}
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 = [];

Object.extend(moveable.prototype, default_prototype_functions);
moveable.prototype._events = [
	{name: "aftermove", func_name: "_moveBy", type: "after"},
	{name: "move", func_name: "_moveBy", type: "before"},
	{name: "dirchange", func_name: "changedir", type: "after"}
];
moveable.prototype.__name = "moveable";
