function Scroll(holder, content, bars, timer, settings){
	this.holder = holder;
	this.content = content;
	this.timer = Timer.detectTimer(timer);
	this.mov = new moveable(this.content);
	this.onscroll = DOMEvent.cloneEvent(this.mov.onmove);
	this.onscrollstart = new DOMEvent(this);
	this.onscrollstop = new DOMEvent(this);
	this._bars = bars;
	this.settings = Scroll.defaultSettings;
	if(settings){
		for(var i in settings){
			this.settings[i] = settings[i];
		}
	}
	if(this.settings._INIT){
		this.init();
	}
	if(this.constructor._TO_INSTANCES){
		this.constructor._instances.push(this);
	}
}
Scroll.prototype.init = function(){
	this.getHolderProps();
	this.getContentProps();
	this.check();
}
Scroll.prototype.getHolderProps = function(){
	this.holder_props = Style.getDimensions(this.holder);
}
Scroll.prototype.getContentProps = function(){
	this.content_props = Style.getDimensions(this.content);
}
Scroll.prototype.check = function(dX, dY){
	var deltaX = dX || (this.content_props.width - this.holder_props.width);
	var deltaY = dY || (this.content_props.height - this.holder_props.height);
	if(this.barX){
		this.barX.refresh(deltaX);
	}else{
		if(this._bars.X){
			this.barX = new Scroll.Scrollbar("X", this, deltaX);
		}
	}
	if(this.barY){
		this.barY.refresh(deltaY);	
	}else{
		if(this._bars.Y){
			this.barY = new Scroll.Scrollbar("Y", this, deltaY);	
		}
	}
	this.deltaY = deltaY;
	this.deltaX = deltaX;
}

Scroll.prototype.refresh = function(){
	this.getHolderProps();
	this.getContentProps();
	this.check();
}
Scroll.prototype.moveContentTo = function(x, y){
	if(this.barX){
		this.barX.moveContentTo(x);
	}
	if(this.barY){
		this.barY.moveContentTo(y);
	}
}
Scroll._instances = [];
Scroll._TO_INSTANCES = true;
Scroll.Scrollbar = function(type, parentObject, delta){
	this.parent = parentObject;
	this.type = type.toUpperCase();
	this.op_type = Scroll.types[Number(!Scroll.types.indexOf(this.type))];
	this.delta = delta;
	//this.settings = this.parent.settings[this.type];
	this.PROPS = Scroll.bars[this.type];
	this.HIDDEN = false;
	this.THUMB_SET = false;
	this.STATE = 0;//NOT INITIALIZED
	this.init();
	if(this.constructor._TO_INSTANCES){
		this.constructor._instances.push(this);
	}
}
Scroll.Scrollbar.prototype.init = function(partly){
	if(!partly){
		var _bar = this.parent._bars[this.type];
		for(var i in _bar){
			this[i] = _bar[i];
		}
		if(this.delta <= 0){
			this.hide(1);
			this.STATE = 1;//PARTLY INITIALIZED
			return false;
		}
	}
	this.count();
	this.initMovs();
	this.get_speed();
	this.init_buttons();
	this.init_track();
	if(this.parent.settings._ARROWS){
		this.init_arrows();
	}
	if(this.type == "Y"){
		if(this.parent.settings._MOUSEWHEEL){
			this.initWheel();
		}
		if(this.parent.settings._SELECTION){
			this.initSelection();
		}
	}
	this.HIDDEN = true;
	this.show(1);
	this.STATE = 2;//INITIALIZED
}
Scroll.Scrollbar.prototype.unpack = function(){
}
Scroll.Scrollbar.prototype.count = function(){
	var prop = this.PROPS.mainDim;
	var pad = parseInt(Style.getElementStyle(this.track, this.PROPS.secDim));
	this.track_len = parseInt(Style.getElementStyle(this.track, prop));
	this.thumb_len = parseInt(Style.getElementStyle(this.thumb, prop));
	if(!this.thumb_len || this.THUMB_SET){
		this.set_thumb(prop)
	}
	this.th_delta = this.track_len - this.thumb_len;
	this.mov_coeff = this.delta / this.th_delta;
	if(this.th_mov){
		this.th_mov.limits[this.type].to = this.th_delta;
//		this.dd_mouse.to = this.thumb_len;
	}
}
Scroll.Scrollbar.prototype.initMovs = function(){
	this.th_mov = new moveable(this.thumb);
	this.th_mov.setLimits(this.type, this.th_delta, 0);
//	this.th_mov.allowed[this.op_type] = false;
	this.th_mov.onmove.register("mov", function(){
		var oM = this.th_mov;
		oM["move" + this.op_type] = 0;
		var args = [0, -oM["move" + this.type] * this.mov_coeff];
		if(this.type == "X"){
			args = args.invert();
		}
		this.parent.mov.moveBy.apply(this.parent.mov, args);
	}.bind(this, this.th_mov));
	this.th_movement = new Movement(this.th_mov, this.parent.timer);
	this.th_movement.onstart.register("event", function(){
		this.parent.onscrollstart.fire();
	}.bind(this));
	this.th_movement.onstop.register("event", function(){
		this.parent.onscrollstop.fire();
	}.bind(this));
	this.dd = new DragDrop(this.th_mov);
	this.dd.ondragstart.register("event", function(){
		this.parent.onscrollstart.fire();	
	}.bind(this));
	this.dd.ondrop.register("event", function(){
		this.parent.onscrollstop.fire();	
	}.bind(this));
//	this.set_dd_mouse();
}
Scroll.Scrollbar.prototype.set_thumb = function(prop){
	var c_length = this.parent.content_props[prop];
	var h_length = this.parent.holder_props[prop];
	var t_len = Math.floor(this.track_len / (c_length / h_length));
	this.thumb_len = Math.max(t_len, this.parent.settings.thumb_min_len);
	this.thumb.style[prop] = this.thumb_len + "px";
	this.THUMB_SET = true;
}
Scroll.Scrollbar.prototype.get_speed = function(){
	this.step = this.parent.settings.speed / this.mov_coeff;
}

Scroll.Scrollbar.prototype.set_dd_mouse = function(){
	this.dd_mouse = new Limit(0, this.thumb_len);

	this.dd.ondragstart.register("catch mouse", function(){
		this.dd_mouse.value = this.dd["mouse_" + this.type.toLowerCase()];
		this.th_mov[this.PROPS.onmore].register("change mouse more", function(lim){
			this.dd_mouse.change(lim.exceeded);
		}.bind(this, this.th_mov.limits[this.type]));
		this.th_mov[this.PROPS.onless].register("change mouse less", function(lim){
			this.dd_mouse.change(lim.preceeded);
		}.bind(this, this.th_mov.limits[this.type]));
	}.bind(this));

	this.dd.ondrop.register("drop limits", function(){
		this.th_mov[this.PROPS.onmore].remove("change mouse more");
		this.th_mov[this.PROPS.onless].remove("change mouse less");
		this.th_mov.onmove.remove("accumulate");
	}.bind(this))

	this.dd_mouse.onmore.register("accumulate", function(){
		if(!this.accumulate){
			this.accumulate = new Limit(0, Infinity);
			this.accumulate.onless.register("drop all", function(){
				var m = this.accumulate.preceeded;
				this.accumulate = null;
				this.th_mov.onmove.remove("accumulate");
				if(this.type == "X"){
					this.th_mov.moveBy(m, 0);
				}else{
					this.th_mov.moveBy(0, m);					
				}
			}.bind(this))
			this.th_mov.onmove.register("accumulate", function(){
				this.accumulate.change(this.th_mov["move" + this.type]);
				this.th_mov["move" + this.type] = 0;
			}.bind(this), false, 0);
			this.accumulate.change(this.dd_mouse.exceeded);
		}
	}.bind(this));
	this.dd_mouse.onless.register("accumulate", function(){
		if(!this.accumulate){
			this.accumulate = new Limit(0, Infinity);
			this.accumulate.onless.register("drop all", function(){
				var m = -this.accumulate.preceeded;
				this.accumulate = null;
				this.th_mov.onmove.remove("accumulate");
				if(this.type == "X"){
					this.th_mov.moveBy(m, 0);
				}else{
					this.th_mov.moveBy(0, m);					
				}
			}.bind(this))
			this.th_mov.onmove.register("accumulate", function(){
				this.accumulate.change(-this.th_mov["move" + this.type]);
				this.th_mov["move" + this.type] = 0;
			}.bind(this), false, 0);
			this.accumulate.change(-this.dd_mouse.preceeded);
		}
	}.bind(this));
}
Scroll.Scrollbar.prototype.scroll_plus = function(){
	this.IS_SCROLLING = true;
	var M = this.th_movement;
	var args = [0, this.step];
	if(this.type == "X"){
		args = args.invert();
	}
	M.setSteps.apply(M, args);
	M.start();
}
Scroll.Scrollbar.prototype.scroll_minus = function(){
	this.parent.IS_SCROLLING = true;
	var M = this.th_movement;
	var args = [0, -this.step];
	if(this.type == "X"){
		args = args.invert();
	}
	M.setSteps.apply(M, args);
	M.start();
}
Scroll.Scrollbar.prototype.stop_scroll = function(e){
	this.parent.IS_SCROLLING = false;
	if(this.th_movement.IS_MOVING){
		this.th_movement.stop();
		stopPropagation(e || window.event);
		DetachEvent(document, "mouseup", this._mouseup_func);
	}
}
Scroll.Scrollbar.prototype.init_buttons = function(){
	this.bPlus.onmousedown = this.scroll_plus.bind(this);
	this.bMinus.onmousedown = this.scroll_minus.bind(this);
	this._mouseup_func = this.stop_scroll.bind(this);
	this.bPlus.onmouseup = this.bMinus.onmouseup = this._mouseup_func;
	this.bPlus.onmouseout = this.bMinus.onmouseout = function(){
		AttachEvent(document, "mouseup", this._mouseup_func);
	}.bind(this);
	this.bPlus.onmouseover = this.bMinus.onmouseover = function(){
		try{
			DetachEvent(document, "mouseup", this._mouseup_func);	
		}catch(e){}
	}
};
Scroll.Scrollbar.prototype.init_track = function(){
	this.track.onclick = function(e){
		var ev = window.event || e;
		var x = ev.offsetX || ev.layerX;
		var y = ev.layerY || ev.offsetY;
		var m = this.th_mov;
		if(this.type == "Y"){
			m.moveTo(0, y);
		}else if(this.type == "X"){
			m.moveTo(x, 0);		
		}
	}.bind(this);
	this.thumb.onclick = function(e){
		stopPropagation(e || window.event);
	};
};
Scroll.Scrollbar.prototype.init_arrows = function(){
	this.start_arrow = Scroll.Scrollbar.start_arrow.bindAvoidingEvent(this, this.type);
	AttachEvent(_elem(this.parent.holder), "mouseover", this.start_arrow);
	this.stop_arrow = Scroll.Scrollbar.stop_arrow.bind(this);
	AttachEvent(_elem(this.parent.holder), "mouseout", this.stop_arrow);
} 
Scroll.Scrollbar.prototype.detach_arrows = function(){
	this.stop_arrow();
	DetachEvent(_elem(this.parent.holder), "mouseover", this.start_arrow);
}
Scroll.Scrollbar.prototype.attach_arrows = function(){
	AttachEvent(_elem(this.parent.holder), "mouseover", this.start_arrow);
}
Scroll.Scrollbar.prototype.initWheel = function(){
	this._start_wheel = function(){
		if(this.WHEEL_WORKS){
			return false;
		}
		this.WHEEL_WORKS = true;
		Scroll.setMouseWheel(this);
	}.bind(this);
	AttachEvent(_elem(this.parent.holder), "mouseover", this._start_wheel);

	this._stop_wheel = function(){
		if(!this.WHEEL_WORKS){
			return false;
		}
		this.WHEEL_WORKS = false;
		window.onmousewheel = document.onmousewheel = null;
		if(window.addEventListener && !window.opera){
			window.removeEventListener('DOMMouseScroll', this.wheelFunc, false);
		}
	}.bind(this);
	AttachEvent(_elem(this.parent.holder), "mouseout", this._stop_wheel);
}
Scroll.Scrollbar.prototype.detach_wheel = function(){
	this._stop_wheel();
	DetachEvent(_elem(this.parent.holder), "mouseover", this._start_wheel);
}
Scroll.Scrollbar.prototype.attach_wheel = function(){
	AttachEvent(_elem(this.parent.holder), "mouseover", this._start_wheel);
}
Scroll.Scrollbar.prototype.initSelection = function(){
	this.previousMouseY = 0;
	if(Style._browser == "IE"){
		this.parent.content.onselectstart = Scroll.Scrollbar.start_selection.bind(this);
	}else{
		this.parent.content.onmousedown = Scroll.Scrollbar.start_selection.bind(this);	
	}
}
Scroll.Scrollbar.prototype.get_visible_zone = function(){
	var pos = this.parent.mov[this.PROPS.mainPos];
	var size = this.parent.holder_props[this.PROPS.mainDim];
	return {
		from: -pos, 
		to: -pos + size
	};
};
Scroll.Scrollbar.start_arrow = function(type){
	if(this.ARROWS_WORK){
		return false;
	}
	this.ARROWS_WORK = true;
	this._key_down_function = Scroll.Scrollbar.arrows[this.type].bind(this);
	this._key_up_function = this.stop_scroll.bind(this);
	AttachEvent(document, "keydown", this._key_down_function);
	AttachEvent(document, "keyup", this._key_up_function);
}
Scroll.Scrollbar.stop_arrow = function(){
	if(!this.ARROWS_WORK){
		return false;
	}
	this.ARROWS_WORK = false;
	DetachEvent(document, "keydown", this._key_down_function);
	DetachEvent(document, "keyup", this._key_up_function);
}
Scroll.Scrollbar.arrows = {
	X: function(e){
		if(this.dd.IS_DRAGGING){
			return false;
		}
		switch(e.keyCode){
			case 39: //down
				this.scroll_plus();
				break;
			case 37: //up
				this.scroll_minus();
				break;
		}
	},
	Y: function(e){
		if(this.dd.IS_DRAGGING){
			return false;
		}
		switch(e.keyCode){
			case 40: //down
				this.scroll_plus();
				break;
			case 38: //up
				this.scroll_minus();
				break;
		}
	}
}
Scroll.Scrollbar.start_selection = function(e){
	var ev = e || window.event;
	this.previousMouseY = ev.clientY;
	document.onmousemove = function(e){
		var ev = e || window.event;
		var delta = this.previousMouseY - ev.clientY;
		this.previousMouseY = ev.clientY;
		this.th_mov.moveBy(0, -delta);
	}.bind(this);
	document.onmouseup = function(){
		document.onmousemove = null;
	}
}
Scroll.Scrollbar.stop_selection = function(){

}
Scroll.wheelFunc = function(e){
	if(this.dd.IS_DRAGGING){
		return false;
	}
	var ev = window.event || e;
	var delta = (ev.wheelDelta ? ev.wheelDelta / 120 : -ev.detail / 3) * 5;
	if(isNaN(delta)){
		delta = 0;
	}
	delta = delta * (300 / this.parent.deltaY);
//	alert("Parent delta: " + this.parent.deltaY + ", delta: " + delta);

	this.th_mov.moveBy(0 ,-delta * 3);
	if(ev.preventDefault){
		ev.preventDefault();
	}
	ev.returnValue = false;
}
Scroll.setMouseWheel = function(obj){
	switch(Style._browser){
		case "Gecko":
			obj.wheelFunc = Scroll.wheelFunc.bind(obj);
	        window.addEventListener('DOMMouseScroll', obj.wheelFunc, false);		
			break;
		case "Opera": 
			window.onmousewheel = Scroll.wheelFunc.bind(obj);	
			break;
		case "IE": 
			document.onmousewheel = Scroll.wheelFunc.bind(obj);
			break;
	}
}
Scroll.Scrollbar.prototype.moveContentTo = function(value){
	var val = value / this.mov_coeff;
	if(this.type == "X"){
		this.th_mov.moveTo(val, 0);
	}else{
		this.th_mov.moveTo(0, val);
	}
}
Scroll.Scrollbar.prototype.refresh = function(delta){
	if(delta == this.delta){
		return false;
	}
	this.delta = delta;
	if(delta <= 0){
		this.hide(1);
	}else if(this.delta > 0){
		if(this.STATE == 1){
			this.init(true);//continue initialization
		}
		this.contentPosition = -this.parent.mov[this.PROPS.mainPos];
		this.moveContentTo(0);
		this.show(1);
		this.count();
		this.get_speed();
		this.moveContentTo(this.contentPosition);
	}
}
Scroll.Scrollbar.prototype.hide = function(visibility){
	if(this.HIDDEN){
		return false;
	}
	var vis = visibility || false;
	var prop = Scroll._display_props.bool(vis);
	this.bar.style[prop] = Scroll.__hides.bool(vis);
	this.HIDDEN = true;
	if(this.STATE < 2){
		return false;
	}
	this.moveContentTo(0);
	if(this.type == "Y"){
		if(this.parent.settings._MOUSEWHEEL){
			this.detach_wheel();
		}
	}
	if(this.parent.settings._ARROWS){
		this.detach_arrows();
	}
}
Scroll.Scrollbar.prototype.show = function(visibility){
	if(!this.HIDDEN){
		return false;
	}
	var vis = visibility || false;
	var prop = Scroll._display_props.bool(vis);
	this.bar.style[prop] = Scroll.__shows.bool(vis);
	if(this.type == "Y"){
		if(this.parent.settings._MOUSEWHEEL){
			this.attach_wheel();
		}
	}
	if(this.parent.settings._ARROWS){
		this.attach_arrows();
	}
	this.HIDDEN = false;
}
Scroll.Scrollbar.prototype.toString = __toString;
Scroll.Scrollbar.prototype.__name = "Scrollbar";
Scroll.Scrollbar._instances = [];
Scroll.Scrollbar._TO_INSTANCES = true;
Scroll.prototype.toString = __toString;
Scroll.prototype.__name = "Scroll";
Scroll.bars = {
	X: {
		mainDim: "width",
		secDim: "height",
		mainPos: "left",
		secPos: "right",
		plusPos: "right",
		minusPos: "left",
		pad: "paddingRight",
		onmore: "onrightlimitreach",
		onless: "onleftlimitreach"
	},
	Y: {
		mainDim: "height",
		secDim: "width",
		mainPos: "top",
		secPos: "bottom",
		plusPos: "bottom",
		minusPos: "top",
		barPos: "right",
		pad: "paddingRight",
		onmore: "onbottomlimitreach",
		onless: "ontoplimitreach"
	}
}
Scroll.types = ["X", "Y"];
Scroll._display_props = ["display", "visibility"];
Scroll.__shows = ["block", "visible"];
Scroll.__hides = ["none", "hidden"];
Scroll.defaultSettings = {
	_INIT: true,
	_MOUSEWHEEL: true,
	_ARROWS: true,
	_SELECTION: false,
	speed: 5,
	thumb_min_len: 10,
	toString: function(){
		var str = "object Settins\t\n\t";
		for(var i in this){
			if(i != "toString"){
				str += i + " => " + this[i] + "\t\n\t";
			}
		}
		return str;
	}
}