function resizeable(elem, dimension){
	this.elem = elem;
	this.onresize = new DOMEvent(this);
	this.onafterresize = new DOMEvent(this);
	this.saveFloatX = new Nums.SaveFloatPoint();
	this.saveFloatY = new Nums.SaveFloatPoint();
	this.resizedX = 0;
	this.resizedY = 0;
	this.resX = 0;
	this.dimension = dimension ? dimension.toUpperCase() :  false;
	this.resY = 0;
	this.errHeight = 0;
	this.count = 0;
	this.limits = {};
	this.init();
}
resizeable.prototype.init = function(){
	var dims = Style.getDimensions(this.elem);
	this.width = new Nums.Positive(dims.width);
	this.height = new Nums.Positive(dims.height);
	this.onzerowidth = DOMEvent.cloneEvent(this.width.onzero, this);
	this.onzeroheight = DOMEvent.cloneEvent(this.height.onzero, this);
}
resizeable.prototype.resize = function(){
	if(!this.dimension){
		this.elem.style.width = this.width + "px";
		this.elem.style.height = this.height + "px";
	}else{
		if(this.dimension == "X"){
			this.elem.style.width = this.width + "px";
		}else if(this.dimension == "Y"){
			this.elem.style.height = this.height + "px";
		}
	}
	this.count++;
	this.onafterresize.fire();
}
resizeable.prototype.resizeTo = function(w, h){
	var wVal = w - this.width;
	var hVal = h - this.height;
	this.resizeBy(wVal, hVal);
}
resizeable.prototype.resizeBy = function(w, h){
	this.resX = this.saveFloatX.add(w);
	this.resY = this.saveFloatY.add(h);
	this.onresize.fire();
	this.width.add(this.resX);
	this.height.add(this.resY);
	this.resize();
}
resizeable.prototype.setLimits = function(type, value, startValue){
	type = type.toUpperCase();
	if(this.limits[type]){
		return;
	}
	var PRESETS = resizeable.LIMITS[type]
	this.limits[type] = new Limit(0, value);
	if(startValue){
		this.limits[type].value = startValue;
	}
	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(objLim){
			this['res' + objLim.type] = objLim.MORE_VALUE;
			objLim._REACHED = true;
			objLim.MORE_REACHED = true;
		}.bind(this, this.limits[type])
	);
	this.limits[type].onless.register(
		'limit-less',
		function(objLim){
			this['res' + objLim.type] = objLim.LESS_VALUE;
			objLim._REACHED = true;
			objLim.LESS_REACHED = true;
		}.bind(this, 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.onmore].register = function(name, func, times){
		this.limits[type].onmore.register(name, function(){
			this.onafterresize.register(name, func, 1);
		}.bind(this), times);
	}.bind(this);
	this[PRESETS.onless].register = function(name, func, times){
		this.limits[type].onless.register(name, function(){
			this.onafterresize.register(name, func, 1);
		}.bind(this), times);
	}.bind(this);
	this.onresize.register(
		'limit' + type, 
		function(objLim){
			objLim.change(this['res' + objLim.type]);
		}.bind(this, this.limits[type]), null, 0
	);
}	
resizeable.prototype.setResizeSpace = function(X, Y, sX, sY){
	if(!this.moveSpace){
		this.moveSpace = {};
		this.onresizespacereach = new MajorDOMEvent();
	}
	if(X || X === 0){
		this.moveSpace.X = X;
		this.setLimits('X', X, sX || 0);
		this.onresizespacereach._link(this.onwidthless, "width-less");
		this.onresizespacereach._link(this.onwidthmore, "width-more");
	}
	if(Y || Y === 0){
		this.moveSpace.Y = Y;
		this.setLimits('Y', Y,  sY || 0);
		this.onresizespacereach._link(this.onheightless, "height-less");
		this.onresizespacereach._link(this.onheightmore, "height-more");
	}
	return this.moveSpace;
}
resizeable.prototype.addMoveable = function(oM){
	this.moveable = oM;
	this._CHANGE_MOVEABLE = 0;
	this.onresize.register("change moveable", function(){
		if(this._CHANGE_MOVEABLE){
			this.moveable.moveBy(this.resX * this._CHANGE_MOVEABLE, this.resY * this._CHANGE_MOVEABLE);
		}
	});
}
resizeable.prototype.toString = __toString;
resizeable.prototype.__name = "resizeable";
resizeable.LIMITS = {
	X: {
		onless: 'onwidthless',
		onmore: 'onwidthmore',
		onmoreout: 'onwidthmoreout',
		onlessout: 'onwidthlessout',
		less: 'width-less',
		more: 'width-more'
	},
	Y: {
		onless: 'onheightless',
		onmore: 'onheightmore',
		onmoreout: 'onheightmoreout',
		onlessout: 'onheightlessout',
		less: 'height-less',
		more: 'height-more'		
	}
}
function Resize(elem, oTimer, oMoveable, type){
	this.elem = elem;
	this.resizeable = new resizeable(elem, type);
	this.timer = Timer.detectTimer(oTimer);
	if(this.timer._MUTUAL){
		if(this.timer.addResize){
			this.timer.registerResize(this);
		}else{
			Resize.handleMutualTimer(this.timer);
			this.timer.registerResize(this);
		}
	}else{
		this.timer.registerEvent({
			name: "resize", 
			func: function(){
				this.resizeable.resizeBy(this.stepX, this.stepY);
			},
			oThis: this,
			args: []
		});
	}
	if(typeof oMoveable == "object" && oMoveable instanceof moveable){
		this.resizeable.addMoveable(oMoveable);
	}else if(typeof oMoveable == "boolean"){
		if(oMoveable){
			this.resizeable.addMoveable(new moveable(this.elem));
		}
	}
	this.stepLeft = 0;
	this.stepUp = 0;
	this.stepDown = 0;
	this.stepRight = 0;
	this.stepX = 0;
	this.stepY = 0;
	this.onresize = DOMEvent.cloneEvent(this.resizeable.onresize, this);
	this.onafterresize = DOMEvent.cloneEvent(this.resizeable.onafterresize, this);
	this.onzerowidth = DOMEvent.cloneEvent(this.resizeable.onzerowidth, this);
	this.onzeroheight = DOMEvent.cloneEvent(this.resizeable.onzeroheight, this);
	this.onstop = new DOMEvent(this);
	this.onstart = new DOMEvent(this);
	if(!this.resizeable.moveable){
		this.resizeLeft = this.resizeUp = function(){return false}
	}
}
Resize.prototype.setSteps = function(x, y){
	this.stepX = x;
	this.stepY = y;
}
Resize.prototype.start = function(){
	if(!this.timer._MUTUAL){
		this.timer.start();
	}
	this.IS_DOING = true;
	this.onstart.fire();
}
Resize.prototype.resizeLeft = function(value){
	this.stepLeft = value;
	this.stepX = value + this.stepRight;
	this.resizeable._CHANGE_MOVEABLE = -1;
}
Resize.prototype.resizeUp = function(value){
	this.stepUp = value;
	this.stepY = value + this.stepDown;
	this.resizeable._CHANGE_MOVEABLE = -1;
}
Resize.prototype.resizeRight = function(value){
	this.stepRight = value;
	this.stepX = value + this.stepLeft;	
	this.resizeable._CHANGE_MOVEABLE = 0;
}
Resize.prototype.resizeDown = function(value){
	this.stepDown = value;
	this.stepY = value + this.stepUp;	
	this.resizeable._CHANGE_MOVEABLE = 0;
}
Resize.prototype.stopLeft = function(){
	this.stepX -= this.stepLeft;
	this.stepLeft = 0;
	this.onresize.remove(Resize._RES_LEFT.name);
}
Resize.prototype.stopUp = function(){
	this.stepY -= this.stepUp;
	this.stepUp = 0;
	this.onresize.remove(Resize._RES_UP.name);
}
Resize.prototype.stopRight = function(){
	this.stepX -= this.stepRight;
	this.stepRight = 0;
}
Resize.prototype.stopDown = function(){
	this.stepY -= this.stepDown;
	this.stepDown = 0;
}
Resize.prototype.stop = function(){
	this.onresize.remove(Resize._RES_LEFT.name);
	this.onresize.remove(Resize._RES_UP.name);
	if(!this.timer._MUTUAL){
		this.timer.clear();
	}
	this.IS_DOING = false;
	this.onstop.fire();
}
Resize.prototype.setLimits = function(type, value, startValue){
	this.resizeable.setLimits(type, value, startValue);
	var PRESETS = resizeable.LIMITS[type];
	this[PRESETS.onless] = DOMEvent.cloneEvent(this.resizeable[PRESETS.onless], this);
	this[PRESETS.onmore] = DOMEvent.cloneEvent(this.resizeable[PRESETS.onmore], this);
}
Resize.prototype.setResizeSpace = function(X, Y, sX, sY){
	this.moveSpace = this.resizeable.setResizeSpace(X, Y, sX, sY);
	if(!this.onresizespacereach){
		this.onresizespacereach = DOMEvent.cloneEvent(this.resizeable.onresizespacereach, this);
	}
}
Resize.prototype.invertSteps = function(){
	this.stepX = -this.stepX;
	this.stepY = -this.stepY;
}
Resize.prototype.toString = __toString;
Resize.prototype.__name = "Resize";
Resize.handleMutualTimer = function(oTimer){
	if(oTimer.registerResize){
		return;
	}
	oTimer.resizes = [];
	oTimer.registerResize = function(oR){
		this.resizes.push(oR);
	}
	oTimer.registerEvent(
	{
		name: "resize",
		func: function(){
			this.resizes.each(function(res){
				if(res.IS_DOING){
					res.resizeable.resizeBy(res.stepX, res.stepY);
				}
			})
		}, 
		oThis: oTimer,
		args: [],
		freq: Resize.frequency
	}
	)
}
Resize.frequency = 1;
Resize._RES_LEFT = {
	name: "resize-left",
	func: function(){
		this.moveable.moveBy(-this.stepLeft, 0);
	}
}
Resize._RES_UP = {
	name: "resize-top",
	func: function(){
		this.moveable.moveBy(0, -this.stepUp);
	}
}
Resize.setGrow = function(oResize){
	oResize.Grow = {};
	oResize.ongrown = new DOMEvent();
	oResize.ongrown.register("stop", Resize.defaultOnGrown.bind(oResize))
	oResize.growTo = function(toW, toH, speed){
		speed = speed ? speed : 3;
		var currentWidth = this.resizeable.width;
		var currentHeight = this.resizeable.height;
		var deltaWidth = toW - currentWidth;
		var deltaHeight = toH - currentHeight;
		if(!deltaWidth && !deltaHeight){
			return;
		}
		var biggerDelta = Math.abs(deltaWidth) > Math.abs(deltaHeight) ? deltaWidth : deltaHeight;
		var numOfSteps = Math.abs(Math.round(biggerDelta / speed));
		var stepX = deltaWidth / (numOfSteps * 2);
		var stepY = deltaHeight / (numOfSteps * 2);
		this.Grow.grownX = 0;
		this.Grow.grownY = 0;
		this.Grow.deltaWidth = deltaWidth;
		this.Grow.deltaHeight = deltaHeight;
		this.Grow.stepX = stepX;
		this.Grow.stepY = stepY;
		this.resizeLeft(stepX);
		this.resizeRight(stepX);
		this.resizeUp(stepY);
		this.resizeDown(stepY);

		this.onresize.register("grow-to", function(oR, oG){
			var STOP_X = false, STOP_Y = false;
			if(Math.abs(oG.grownX + oG.stepX * 2) >= Math.abs(oG.deltaWidth)){
				var sX = (Math.abs(oG.deltaWidth) - Math.abs(oG.grownX))  / 2 * oG.stepX.signOf();
				this.resizeLeft(sX);
				this.resizeRight(sX);
				STOP_X = true;
			}
			if(Math.abs(oG.grownY + oG.stepY * 2) >= Math.abs(oG.deltaHeight)){
				var sY = (Math.abs(oG.deltaHeight) - Math.abs(oG.grownY))  / 2 * oG.stepY.signOf();
				this.resizeUp(sY);
				this.resizeDown(sY);
				
				oG.stepY = sY;
				STOP_Y = true;
			}
			oG.grownX += oG.stepX * 2;
			oG.grownY += oG.stepY * 2;
			if(STOP_X && STOP_Y){
				this.ongrown.fire();
			}

		}.bind(this, this.resizeable, this.Grow));
		this.start();
	}
}
Resize.defaultOnGrown = function(){
	this.onresize.remove("grow-to");
	this.stop();
}