SAWSlider = function(divEl){
	this.div_ = divEl;
	this.id_ = divEl.id;
	
	this.iLeftWidth_ = divEl.offsetWidth/2 - 2 - this.CURSORWIDTH;
	this.iRightWidth_ = divEl.offsetWidth/2 - 2 - this.CURSORWIDTH;
	iH = parseInt(divEl.style.height);
	if(isNaN(iH)) iH = divEl.offsetHeight;
	this.iHeight_ = iH - 4;
	
	this.text_ =
		'<table cellpadding=0 cellspacing=0 id="'+divEl.id+'_main">'+
		'<table cellpadding=0 cellspacing=0 id="'+divEl.id+'_main">'+
		'<tr><td valign="center" id="'+divEl.id+'_border">'+
		'<table cellpadding=0 cellspacing=0><tr>'+
		'<td id="'+divEl.id+'_filled" style="width:'+(this.iLeftWidth_)+'px; height:'+this.iHeight_+'px"><span class="SAWSlider__text">x&nbsp;</span></td>'+
		'<td id="'+divEl.id+'_cursor" style="width:'+(this.CURSORWIDTH)+'px; height:'+this.iHeight_+'px"><span class="SAWSlider__text">&nbsp;</span></td>'+
		'<td id="'+divEl.id+'_empty" style="width:'+(this.iRightWidth_)+'px; height:'+this.iHeight_+'px"><span class="SAWSlider__text">&nbsp;</span></td>'+
		'</td></tr></table>'+
		'</td></tr></table>';
	
	this.class__filled_ = 'SAWSlider__filled';
	this.class__filled__noborder_ = 'SAWSlider__filled__noborder';
	this.class__cursor_ = 'SAWSlider__cursor';
	this.class__cursor__pressed_ = 'SAWSlider__cursor__pressed';
	this.class__empty_ = 'SAWSlider__empty';
	this.class__empty__noborder_ = 'SAWSlider__empty__noborder';
	this.class__border_ = 'SAWSlider__border';
	this.fResolution_ = 1;
	this.fMin_ = 0;
	this.fMax_ = 100;
	this.fValue_ = 50;
	
	this.objLeft_ = null;
	this.objRight_ = null;
	this.objCursor_ = null;
	
	this.bChanged_ = false;
	this.onchange=null;
	this.onfinalchange=null;
	this.onslidestart=null;
	
	SAWSlider.id2obj_[this.id_] = this;
}

SAWSlider.id2obj_ = new Array();

SAWSlider.prototype.CURSORWIDTH = 10;

SAWSlider.prototype.setClasses = function(sFilled, sFilledNoBorder, sCursor, sCursorPressed, sEmpty, sEmptyNoBorder, sBorder){
	if(sFilled) this.class__filled_ = sFilled;
	if(sFilledNoBorder) this.class__filled__noborder_ = sFilledNoBorder;
	if(sCursor) this.class__cursor_ = sCursor;
	if(sCursorPressed) this.class__cursor__pressed_ = sCursorPressed;
	if(sEmpty) this.class__empty_ = sEmpty;
	if(sEmptyNoBorder) this.class__empty__noborder_ = sEmpty;
	if(sBorder) this.class__border_ = sBorder;
}


/**
	sets the value resolution of the slider. 
	If you set resolution to 1, you will disallow fractionary values; 
	if you set resolution to 5 the slider will go just to 0%, 5%, 10%, ..
	Default resolution is 0.1, i.e., you will not get percentanges with two digits after comma (can get 9.3% but not 9.33%)
**/
SAWSlider.prototype.setResolution = function(fResolution){
	this.fResolution_ = fResolution;
}

/**
	Programatically set the value, draw the slider accordingly and calls onvaluechanged if it exists and value has changed
**/
SAWSlider.prototype.setValue = function(fValue){
	fValue = Math.round(fValue/this.fResolution_)*this.fResolution_;
	var fValueOld = this.fValue_;
	this.fValue_ = fValue;
	
	if(!this.objLeft_)return;
	
	this.slideToActualValue_();
}

/**
	Returns the value of the slider.
**/
SAWSlider.prototype.getValue = function(){
	return this.fValue_;
}



SAWSlider.startDragGen_ = function(sId){
	return(function(e){
		var objSource = SAWSlider.id2obj_[sId],
			vElPos = SAWUtils.getElementAbsolutePosition(objSource.div_);
		objSource.borderLeft_ = vElPos.left - 5;
		objSource.borderRight_ = vElPos.left + objSource.div_.offsetWidth + 5;
		objSource.borderTop_ = vElPos.top - 5;
		objSource.borderBottom_ = vElPos.top + objSource.div_.offsetHeight + 5;

		objSource.objCursor_.className = objSource.class__cursor__pressed_;
			
		SAWSlider.x0_ = SAWUtils.getMousePosition(e).left;
		SAWSlider.left0_ = objSource.leftSize_;

		document.onmouseup = function(){
			var objSource = SAWSlider.id2obj_[sId];
			document.onmousemove = null; 
			objSource.objCursor_.className = objSource.class__cursor_;
			objSource.slideToActualValue_();  // this is needed since the value might be rounded so the slider might need a small jump to correct position
			objSource.callOnFinalChange();
		}
		document.onmousemove = SAWSlider.whileDraggingGen_(sId);
		
		return false;
	});
}

SAWSlider.whileDraggingGen_ = function(sId){
	return(
		function(e){
			var vMousePos = SAWUtils.getMousePosition(e), ix = vMousePos.left, iy = vMousePos.top, objSource = SAWSlider.id2obj_[sId];

			if(ix<objSource.borderLeft_ || ix>objSource.borderRight_ || iy<objSource.borderTop_ || iy>objSource.borderBottom_){
				document.onmouseup();
				return;
			}
			var
				iDeltaX = vMousePos.left - SAWSlider.x0_,
				iLeft = SAWSlider.left0_ + iDeltaX,
				iMax = objSource.leftplusright_;
			if(iLeft<1){
				iDeltaX += 1 - iLeft;
				iLeft = SAWSlider.left0_ + iDeltaX;
			}
			else if(iLeft>iMax-1){
				iDeltaX -= iLeft - iMax + 1;
				iLeft = SAWSlider.left0_ + iDeltaX;
			}
			
			var iRight = iMax - SAWSlider.left0_ - iDeltaX;
			objSource.setLeftRightSizes_(iLeft, iRight);
			objSource.computeValue_(true);
			
			return false;
		}
	);
}

SAWSlider.clickLeftGen_ = function(sId){
	return(
		function(e){
			var iLeft = SAWUtils.getMousePosition(e).left, 
				objSource = SAWSlider.id2obj_[sId], 
				iLeft0 = SAWUtils.getElementAbsolutePosition(objSource.objLeft_).left;
			iLeft -= iLeft0 + objSource.CURSORWIDTH/2;
			if(iLeft<1) iLeft = 1;
			var iRight = objSource.leftplusright_ - iLeft;
			objSource.setLeftRightSizes_(iLeft, iRight);
			objSource.computeValue_();
			objSource.slideToActualValue_();
			objSource.callOnFinalChange();
		}
	);
}

SAWSlider.clickRightGen_ = function(sId){
	return(
		function(e){
			var iLeft = SAWUtils.getMousePosition(e).left, 
				objSource = SAWSlider.id2obj_[sId], 
				iLeft0 = SAWUtils.getElementAbsolutePosition(objSource.objLeft_).left;
			iLeft -= iLeft0 + objSource.CURSORWIDTH/2;
			if(iLeft>objSource.leftplusright_-1) iLeft = objSource.leftplusright_-1;
			var iRight = objSource.leftplusright_ - iLeft;
			objSource.setLeftRightSizes_(iLeft, iRight);
			objSource.computeValue_();
			objSource.slideToActualValue_();
			objSource.callOnFinalChange();
		}
	);
}


SAWSlider.prototype.show = function(){
	this.div_.innerHTML = this.text_;
	
	document.getElementById(this.id_+'_filled').className = this.class__filled_;
	document.getElementById(this.id_+'_empty').className = this.class__empty_;
	document.getElementById(this.id_+'_cursor').className = this.class__cursor_;
	document.getElementById(this.id_+'_border').className = this.class__border_;
	
	document.getElementById(this.id_+'_cursor').onmousedown = SAWSlider.startDragGen_(this.id_);
	document.getElementById(this.id_+'_filled').onclick = SAWSlider.clickLeftGen_(this.id_);
	document.getElementById(this.id_+'_empty').onclick = SAWSlider.clickRightGen_(this.id_);
	
	this.objRight_ = document.getElementById(this.id_+"_empty"),
	this.objLeft_ = document.getElementById(this.id_+"_filled");
	this.objCursor_ = document.getElementById(this.id_+"_cursor");
	this.leftSize_ = this.objLeft_.offsetWidth;
	this.rightSize_ = this.objRight_.offsetWidth;
	this.leftplusright_ =  this.leftSize_ +  this.rightSize_;
	this.height_ = this.objLeft_.offsetHeight;
	//document.getElementById('debug').innerHTML = this.objLeft_.offsetWidth+'  '+this.objRight_.offsetWidth+'  '+(this.objLeft_.offsetWidth+this.objRight_.offsetWidth);
	this.bLeftHidden_ = false;
	this.bRightHidden_ = false;
	
	
	this.slideToActualValue_();
}

/**
	sets the lowest and highest values the slider can take. By default these are 0 and 100
**/
SAWSlider.prototype.setBounds = function(fMin, fMax){
	if(this.objLeft_){
		alert("You cannot set bounds after a slider is shown. Call function setBounds() before function show()!");
		return;
	}
	this.fMin_ = fMin;
	this.fMax_ = fMax;
}

/**
	adjusts the slider according to actual value
**/
SAWSlider.prototype.slideToActualValue_ = function(){
	var iLeft = Math.round((this.fValue_ - this.fMin_)/(this.fMax_ - this.fMin_) * (this.leftplusright_-2))+1,
		iRight = this.leftplusright_ - iLeft;
	this.setLeftRightSizes_(iLeft, iRight);
}

/*
	calls onfinalchange handler if it exists and the value of the slider has been modified from previous call
	onfinalchange is called when the user commits its change to the slider, by a mouseup event
	onfinalchange handler should address more computational intensive procedures, that cannot be completed during slider drag
*/
SAWSlider.prototype.callOnFinalChange = function(){
	if(this.onfinalchange!=null && this.bChanged_){
		if(typeof this.onfinalchange == typeof "blabla") eval(this.onfinalchange);
		else this.onfinalchange();
	}
	this.bChanged_ = false;
}


/**
	computes the slider value from actual pixel position of the cursor.
	this is the point where onchange is called (if the value is changed and the handler exists)
**/
SAWSlider.prototype.computeValue_ = function(bSlide){
	var fValue = this.fMin_ + (this.fMax_ - this.fMin_) * (this.leftSize_-1)/(this.leftplusright_-2),
		fValue_old = this.fValue_;
	
	if(this.fResolution_<1) fValue = parseInt(""+Math.round(fValue/this.fResolution_))/(1/this.fResolution_);
	else fValue = parseInt(""+Math.round(fValue/this.fResolution_))*this.fResolution_;
	
	this.fValue_ = fValue;
	if(fValue != fValue_old){
		if(bSlide){
			if(!this.bChanged_ && this.onslidestart){
				if(typeof this.onslidestart == typeof "blabla")
					eval(this.onslidestart);
				else this.onslidestart();
			}
		}
		this.bChanged_ = true;

		if(this.onchange!=null){
			if(typeof this.onchange == typeof "blabla") eval(this.onchange);
			else this.onchange();
		}
	}
}


SAWSlider.prototype.setLeftRightSizes_ = function(iLeft, iRight){
	if(iLeft==3 || iLeft==2){
		this.bLeftHidden_ = true;
		this.objLeft_.className = this.class__filled__noborder_;
	}
	else if(iLeft==1){
		iLeft = 0;
		iRight++;
		this.bLeftHidden_ = true;
		this.objLeft_.className = 'SAWSlider__hidden';
	}
	else if(this.bLeftHidden_){
		this.bLeftHidden_ = false;
		this.objLeft_.className = this.class__filled_;
	}
	
	if(iRight==2 || iRight==2){
		this.bRightHidden_ = true;
		this.objRight_.className = this.class__empty__noborder_;
	}
	else if(iRight==1){
		iRight=0; iLeft++;
		this.bRightHidden_ = true;
		this.objRight_.className = 'SAWSlider__hidden';
	}
	else if(this.bRightHidden_){
		this.bRightHidden_ = false;
		this.objRight_.className = this.class__empty_;
	}
	
	SAWUtils.setElementWidth(this.objLeft_, iLeft);
	SAWUtils.setElementWidth(this.objRight_, iRight);
	SAWUtils.setElementWidth(this.objLeft_, iLeft);
	SAWUtils.setElementWidth(this.objRight_, iRight);

	if(iLeft==0) this.leftSize_ = 1; else this.leftSize_ = this.objLeft_.offsetWidth;
	if(iRight==0) {this.rightSize_ = 1; this.leftSize_ = this.leftplusright_ - 1;} else this.rightSize_ = this.objRight_.offsetWidth;
	
//document.getElementById('debug').innerHTML += "<br/>"+this.objLeft_.offsetWidth+'['+iLeft+']  '+this.objRight_.offsetWidth+'['+iRight+']  '+(this.objLeft_.offsetWidth+this.objRight_.offsetWidth);
}
