//
// Copyright (c) Art. Lebedev Studio | http://www.artlebedev.ru/
// Author - Leechy | leechy@design.ru
//


/*********************/
/*     variables     */
/*********************/

var isSliderKbdAccess = false;

var sSliderDefaultMarkContent = '&nbsp;';
var sSliderDefaultPointerContent = '<div class="pointer-image"></div>';

// orientation
var sSliderVertical = 'vertical';
var sSliderHorizontal = 'horizontal';

// movement
var sSliderMoveFree = 'free';
var sSliderMoveSnap = 'snap';
var sSliderMoveMarks = 'marks-only';
	// movement types sorted by importance (increasing)
var aSliderMovement = [ sSliderMoveFree, sSliderMoveSnap, sSliderMoveMarks ];

// multiple pointers movement
var iSliderMultipleDefaultGap = 1;
var sSliderMoveMultipleOver = 'over';
var sSliderMoveMultiplePush = 'push';
var sSliderMoveMultipleStop = 'stop';

// marks
var sSliderMarksEven = 'even';
var sSliderMarksProportional = 'proportional';
var sSliderMarkClass = 'mark';
var sSliderMarkSeriesClass = 'marks';
var sSliderHTMLMarks = 'marks-in-html';

var sSliderMarkPositionPrefix = 'p';

var iSliderMarkDefaultStep = 1;
var sSliderMarkStepPrefix = 's';


// other
var sSliderClassValuesDivider = '-';

// limits
var iSliderDefaultMin = 0;
var iSliderDefaultMax = 100;
var sSliderClassMinValue = 'min';
var sSliderClassMaxValue = 'max';
var sSliderLimits = sSliderClassMinValue + ' ' + sSliderClassMaxValue;
var sSlidexLimitsClass = 'limits';



// generated content classes
var sSliderInitedClass = 'slider_inited';

var sSliderContainerCenterDivClass = 'centered';

var sSliderCoverClass = 'cover';
var sSliderMarksGridClass = 'grid';
var sSliderDefaultMarkClass = 'mark';
var sSliderStartMarkClass = 'start';
var sSliderEndMarkClass = 'end';
var sSliderPointersGridClass = 'pointers';
var sSliderPointerClass = 'pointer';
var sSliderDisabledClass = 'disabled';
var sSliderPointerDisabledClass = 'disabled';


/* gonarch */
var sSliderContainerClass = 'container';
var sSliderDisabledClass = 'disabled';


// and even more
var aFormElemNames = ['input', 'select'];


// sliders
var sSliderIDPrefix = 'sldr';
var sSliderPointerIDPrefix = 'pntr';
var aSliders = new Array();
var aCovers = new Array();
var iSliders = 0;


/**************************/
/*     slider objects     */
/**************************/

function SliderMark(
	sSliderID, iPointerID,
	bDisabled, bSelected, sValue, sPosValue,
	sLabelText, oElem, sClassName, oMarkElem, iValue, iPosValue,
	iStep, isDisabled
) {
	this.sSliderID = sSliderID;
	this.iPointer = iPointerID;

	this.bDisabled = ( bDisabled )? bDisabled : false;
	this.bSelected = bSelected;
	this.sValue = sValue;
	this.sPosValue = sPosValue;
	this.iValue = ( iValue )? iValue : 0;
	this.iPosValue = ( iPosValue )? iPosValue : 0;
	this.iPos = 0;

	this.sText = sLabelText;
	this.oElem = oElem;
	var sElemClass = ( oElem )? oElem.className : null;
	this.sClassName = sClassName || sElemClass;
	this.oMarkElem = oMarkElem;

	this.iStep = ( iStep )? iStep : iSliderMarkDefaultStep;

	return this;
}

function SliderPointer(
	sSliderID, sPointerID, oElem, oPointerElem,
	sMovement, sMin, sMax, sValue, bDisabled
) {
	this.sSliderID = sSliderID;
	this.sPointerID = sPointerID;
	this.oElem = oElem;
	this.oPointerElem = oPointerElem;
	this.oLimitsElem = null;

	this.sMovement = sMovement;
	this.iMin = ( !isNaN( parseInt( sMin ) ) )? parseInt( sMin ) : null;
	this.iMinPos = null;
	this.iMax = ( !isNaN( parseInt( sMax ) ) )? parseInt( sMax ) : null;
	this.iMaxPos = null;
	this.sValue = sValue;
	this.iValue = ( !isNaN( parseInt( sValue ) ) )? parseInt( sValue ) : 0;
	this.iPos = 0;
	this.bDisabled = ( bDisabled )? bDisabled : false;
	this.bLocked = false;

	/* current selected mark */
	this.oMark = null;

	/* functions */
	this.disable = function() {
		this.bDisabled = true;
		if ( this.oElem ) this.oElem.disabled = true;
		Common.Event.add( this.oPointerElem, sSliderPointerDisabledClass );
	}

	this.enable = function() {
		this.bDisabled = false;
		if ( this.oElem ) this.oElem.disabled = false;
		Common.Class.remove( this.oPointerElem, sSliderPointerDisabledClass );
	}

	this.recalcPositionFromValue = function() {
		var oSlider = aSliders[ this.sSliderID ];
		if ( oSlider ) {
			/* setting limits */
			if ( this.iMin && this.iValue < this.iMin ) this.iValue = this.iMin;
			if ( this.iMax && this.iValue > this.iMax ) this.iValue = this.iMax;

			/* looking for marks */
			for ( var i = 0; i < oSlider.aMarks.length; i++ ) {
				if ( this.iValue == oSlider.aMarks[i].iValue || !oSlider.aMarks[i + 1] || ( i == 0 && this.iValue < oSlider.aMarks[i].iValue ) ) {
					this.iPos = oSlider.aMarks[i].iPos;
					this.oMark = oSlider.aMarks[i];
					return;
				}
				if ( this.iValue > oSlider.aMarks[i].iValue && this.iValue < oSlider.aMarks[i + 1].iValue ) {
					if ( this.sMovement == sSliderMoveMarks ) {
						/* marks-only */
						var iMark = ( ( this.iValue - oSlider.aMarks[i].iValue ) > ( oSlider.aMarks[i + 1].iValue - this.iValue ) )? i + 1 : i;
						this.iValue = oSlider.aMarks[iMark].iValue;
						this.iPos = oSlider.aMarks[iMark].iPos;
						this.oMark = oSlider.aMarks[iMark];
					} else {
						var iInterval = oSlider.aMarks[i + 1].iValue - oSlider.aMarks[i].iValue;
						var iValue = this.iValue - oSlider.aMarks[i].iValue;
						var iPos = iValue / iInterval;
						this.iPos = ( oSlider.aMarks[i + 1].iPos - oSlider.aMarks[i].iPos ) * iPos + oSlider.aMarks[i].iPos;
						this.oMark = null;
					}
					break;
				}
			}
		}
	}

	this.recalcValueFromNewPosition = function( iNewPos ) {
		var oSlider = aSliders[ this.sSliderID ];
		var iCalcValue = 0;
		if ( oSlider ) {
			for ( var i = 0; i < oSlider.aMarks.length; i++ ) {
				if ( iNewPos == oSlider.aMarks[i].iPos || !oSlider.aMarks[i + 1] || ( i == 0 && iNewPos < oSlider.aMarks[i].iPos ) ) {
					iCalcValue = oSlider.aMarks[i].iValue;
					break;
				}
				if ( iNewPos > oSlider.aMarks[i].iPos && iNewPos < oSlider.aMarks[i + 1].iPos ) {
					var iInterval = oSlider.aMarks[i + 1].iPos - oSlider.aMarks[i].iPos;
					/* marks-only */
					if ( this.sMovement == sSliderMoveMarks ) {
						var iValue = ( iNewPos - oSlider.aMarks[i].iPos > oSlider.aMarks[i + 1].iPos - iNewPos )? 1 : 0;
					} else {
						var iPos = iNewPos - oSlider.aMarks[i].iPos;
						var iValue = iPos / iInterval;
					}
					iCalcValue = ( oSlider.aMarks[i + 1].iValue - oSlider.aMarks[i].iValue ) * iValue + parseInt( oSlider.aMarks[i].iValue );
					if ( oSlider.aMarks[i].iStep > 1 ) iCalcValue = Math.round( iCalcValue / oSlider.aMarks[i].iStep ) * oSlider.aMarks[i].iStep;
					break;
				}
			}
			if ( oSlider.aPointers.length > 1 ) {
				/* stop on nex pointer check */
				if ( (iCalcValue < this.iValue) && (oSlider.iActivePointer > 0) ) {
					if ( iCalcValue < oSlider.aPointers[ oSlider.iActivePointer - 1 ].iValue + iSliderMultipleDefaultGap )
						iCalcValue = oSlider.aPointers[ oSlider.iActivePointer - 1 ].iValue + iSliderMultipleDefaultGap;
				}
				if ( (iCalcValue > this.iValue) && (oSlider.iActivePointer < oSlider.aPointers.length - 1) ) {
					if ( iCalcValue > oSlider.aPointers[ oSlider.iActivePointer + 1 ].iValue - iSliderMultipleDefaultGap )
						iCalcValue = oSlider.aPointers[ oSlider.iActivePointer + 1 ].iValue - iSliderMultipleDefaultGap;
				}
			}
			return iCalcValue;
		}
	}

	this.movePointer = function() {
		var oSlider = aSliders[ this.sSliderID ];
		if ( this.oPointerElem ) {
			if ( oSlider.sOrientation == sSliderVertical ) {
				this.oPointerElem.style.top = this.iPos + '%';
			} else {
				this.oPointerElem.style.left = this.iPos + '%';
			}
		}
		changeSliderPointerValue( this );
	}

	this.setMinValue = function( iNewMinValue ) {
		var iNewMin = parseInt( iNewMinValue )
		if ( !isNaN( iNewMin ) && iNewMin != this.iMin ) {
			this.iMinPos = this.getPositionFromValue(iNewMinValue);
			if ( iNewMin > this.iMin ) {
				this.iMin = iNewMin;
				this.recalcPositionFromValue();
				this.movePointer();
			} else this.iMin = iNewMin;
			this.resizeLimitsElem()
		}
	}

	this.setMaxValue = function( iNewMaxValue ) {
		var iNewMax = parseInt( iNewMaxValue )
		if ( !isNaN( iNewMax ) && iNewMax != this.iMax ) {
			this.iMaxPos = this.getPositionFromValue(iNewMaxValue);
			if ( iNewMax < this.iMax ) {
				this.iMax = iNewMax;
				this.recalcPositionFromValue();
				this.movePointer();
			} else this.iMax = iNewMax;
			this.resizeLimitsElem()
		}
	}

	this.setValue = function( iNewValue ) {
		if ( iNewValue != this.iValue ) {
			this.iValue = iNewValue;
			this.recalcPositionFromValue();
			this.movePointer();
		}
	}

	return this;
}

SliderPointer.prototype.resizeLimitsElem = function() {
	if (this.iMin != null && this.iMax != null && this.oLimitsElem) {
		if (this.iMin != null && !this.iMinPos) this.iMinPos = this.getPositionFromValue(this.iMin);
		if (this.iMax != null && !this.iMaxPos) this.iMaxPos = this.getPositionFromValue(this.iMax);
		this.oLimitsElem.style.width = (this.iMaxPos - this.iMinPos) + '%';
		this.oLimitsElem.style.marginLeft = this.iMinPos + '%';
	}
}

SliderPointer.prototype.getPositionFromValue = function(iValue) {
	var oSlider = aSliders[ this.sSliderID ];
	if ( oSlider ) {
		/* looking for marks */
		for ( var i = 0; i < oSlider.aMarks.length; i++ ) {
			if ( iValue == oSlider.aMarks[i].iValue || !oSlider.aMarks[i + 1] || ( i == 0 && iValue < oSlider.aMarks[i].iValue ) ) {
				return oSlider.aMarks[i].iPos;
			}
			if ( iValue > oSlider.aMarks[i].iValue && iValue < oSlider.aMarks[i + 1].iValue ) {
				var iInterval = oSlider.aMarks[i + 1].iValue - oSlider.aMarks[i].iValue;
				var iPos = (iValue - oSlider.aMarks[i].iValue) / iInterval;
				return ( oSlider.aMarks[i + 1].iPos - oSlider.aMarks[i].iPos ) * iPos + oSlider.aMarks[i].iPos;
			}
		}
	}
}


function Slider( sSliderID, oElem, sOrientation, sMarksType, aPointers, aMarks, iMin, iMax ) {
	this.sSliderID = sSliderID;
	this.oElem = oElem;
	this.sOrientation = sOrientation;
	this.sMarksType = sMarksType;
	this.aPointers = aPointers;
	this.aMarks = aMarks;
	this.iMin = iMin;
	this.iMax = iMax;

	this.iActivePointer = null;
	this.oGridDiv = null;
	this.oPointersDiv = null;
	this.oCoverDiv = null;

	this.disable = function() {
		this.bDisabled = true;
		if ( this.oElem ) this.oElem.disabled = true;
		Common.Event.add( this.oElem, sSliderDisabledClass );
		for( var i in this.aPointers ){window.status+=' '+i
			this.aPointers[i].disable();
		}
	}

	this.enable = function() {
		this.bDisabled = false;
		if ( this.oElem ) this.oElem.disabled = false;
		Common.Class.remove( this.oPointerElem, sSliderDisabledClass );
		for( var i in this.aPointers ){
			this.aPointers[i].enable();
		}
	}

	return this;
}



/********************************/
/*     marks class analysis     */
/********************************/

function getSliderMarkValue( aMarkValues ) {
	return aMarkValues[1] || aMarkValues[0];
}

function marksSort( aFirst, aSecond ) {
	var iFirst = aFirst[1] || aFirst[0];
	var iSecond = aSecond[1] || aSecond[0];
	return ( iSecond - iFirst );
}

function createMarksFromClassNames( oSlider, sSliderID, sClassNames, iPointerID, aMarks ) {
	/* get pointer limits */
	var aLimits = getNamedValuesArray( sSliderLimits, sClassNames );

	if ( !Common.Class.match( oSlider, sSliderHTMLMarks ) ) {
		/* ordinary ticks */
		var aMarksValues = getValuesArrayByName( sSliderMarkClass, sClassNames );
		for ( var i in aMarksValues ) {
			var iStep = getIntValueByPrefix( aMarksValues[i], sSliderMarkStepPrefix );
			if ( !iStep || isNaN( iStep ) || iStep < 1 ) iStep = iSliderMarkDefaultStep;
			var sPosValue = getIntValueByPrefix( aMarksValues[i], sSliderMarkPositionPrefix );
			if ( !sPosValue || isNaN( sPosValue ) ) sPosValue = aMarksValues[i][1];
			aMarks[ aMarks.length ] = new SliderMark(
				sSliderID, iPointerID,
				false, false, aMarksValues[i][0], sPosValue,
				aMarksValues[i][0], null, aMarksValues[i][2], null, null, null,
				iStep
			);
		}
		

		/* periodical ticks */
		var iMinValue = parseInt( aLimits[ sSliderClassMinValue ] );
		var iMaxValue = parseInt( aLimits[ sSliderClassMaxValue ] );
		if ( !isNaN( iMinValue ) && !isNaN( iMaxValue ) ) {
			aMarksValues = getValuesArrayByName( sSliderMarkSeriesClass, sClassNames );
			if ( aMarksValues.length ) {
				aMarksValues.sort( marksSort );
				// calculating step (greatest common divisor)
				var aValues = new Array();
				for ( var i in aMarksValues ) aValues[i] = getSliderMarkValue( aMarksValues[i] );
				var iGCD = parseInt( getGCD( aValues ) );
				// creating ticks
				for ( var i = iMinValue; i <= iMaxValue; i += iGCD ) {
					for ( var j = 0; j < aMarksValues.length; j++ ) {
						if ( i % aValues[j] == 0 ) {
							var sValue = i;
							var sLabelText = aMarksValues[j][0]
							aMarks[ aMarks.length ] = new SliderMark(
								sSliderID, iPointerID,
								false, false, sValue, sValue,
								sLabelText, null, aMarksValues[j][2], null
							);
							break;
						}
					}
				}
			}
		}
	}
}


/*****************************/
/*     inputs dissection     */
/*****************************/


// select
function dissectSelect( oSlider, sSliderID, oSelect, aPointers, aMarks ) {
	/* create pointer */
	var iPointerID = aPointers.length;
	aPointers[ iPointerID ] = new SliderPointer(
		sSliderID, sSliderID + sSliderPointerIDPrefix + iPointerID, oSelect, null,
		sSliderMoveMarks, null, null, oSelect.options[ oSelect.selectedIndex ].value
	)

	/* events */
	Common.Event.add(oSelect, 'change', sliderSelectChanged);

	/* create marks */
	for ( var i = 0; i < oSelect.options.length; i++ ) {
		aMarks[ aMarks.length ] = new SliderMark(
			sSliderID, iPointerID,
			oSelect.options[i].disabled, oSelect.options[i].selected, oSelect.options[i].value, oSelect.options[i].value,
			oSelect.options[i].text, oSelect.options[i], oSelect.options[i].className, null
		);
	}
}


// input[text]
function dissectTextInput( oSlider, sSliderID, oInput, aPointers, aMarks ) {
	/* get pointer limits */
	var aLimits = getNamedValuesArray( sSliderLimits, oInput.className );

	/* get movement type */
	var sMovement = sSliderMoveFree;
	var aParents = [ oSlider, oInput ];
	for ( var i in aParents ) for ( var j in aSliderMovement )
		if ( Common.Class.match( aParents[i], aSliderMovement[j] ) ) sMovement = aSliderMovement[j];

	/* create pointer */
	var iPointerID = aPointers.length;
	aPointers[ iPointerID ] = new SliderPointer(
		sSliderID, sSliderID + sSliderPointerIDPrefix + iPointerID, oInput, null,
		sMovement, aLimits[ sSliderClassMinValue ], aLimits[ sSliderClassMaxValue ], oInput.value
	)
	
	/* get marks from class names */
	createMarksFromClassNames( oSlider, sSliderID, oInput.className, iPointerID, aMarks );
}


// input[radio]
function dissectRadioInput( oSlider, sSliderID, oInput, aRadioInputs, aPointers, aMarks ) {
	if ( aRadioInputs[ oInput.name ] == null ) {
		aRadioInputs[ oInput.name ] = aPointers.length;
		var iPointerID = aPointers.length;
		aPointers[ aRadioInputs[ oInput.name ] ] = new SliderPointer(
			sSliderID, sSliderID + sSliderPointerIDPrefix + iPointerID, oInput, null,
			sSliderMoveMarks, null, null, 0
		)
	}
	/* get text for mark label... from 'label' element */
	var sLabelText = '';
	if ( oInput.id ) {
		for ( var iLabelIdx = 0; ( oLabelElem = oSlider.getElementsByTagName('label')[iLabelIdx] ); iLabelIdx++ ) {
				/* gonarch: IE понятия не имеет о getAttribute */
				/* leechy: имеет, но не для всех атрибутов */
				if ( ( oLabelElem.htmlFor && oLabelElem.htmlFor == oInput.id ) || oLabelElem.getAttribute('for') == oInput.id )
					sLabelText = getTextValue( oLabelElem ); break;
		}
	}
	aMarks[ aMarks.length ] = new SliderMark(
		sSliderID, oInput,
		oInput.disabled, oInput.checked, oInput.value, oInput.value,
		sLabelText, oInput, oInput.className, null
	)

	/* events */
	Common.Event.add(oInput, 'click', sliderRadioChanged);

	/* set pointer value */
	if ( oInput.checked && aPointers[ aRadioInputs[ oInput.name ] ] ) {
		aPointers[ aRadioInputs[ oInput.name ] ].sValue = oInput.value;
		aPointers[ aRadioInputs[ oInput.name ] ].iValue = ( !isNaN( parseInt( oInput.value ) ) )? parseInt( oInput.value ) : 0;
	}
}




/***************************/
/*     slider creation     */
/***************************/


function createSlider( oSlider ) {
	/* ID */
	var sSliderID = ( oSlider.id )? oSlider.id : sSliderIDPrefix + iSliders;

	/* if there is any slider with the same id, well, then we are probably trying to rebuild it */
	if ( aSliders[ sSliderID ] ) {
		if ( aSliders[ sSliderID ].oGridDiv ) aSliders[ sSliderID ].oGridDiv.parentNode.removeChild( aSliders[ sSliderID ].oGridDiv );
		if ( aSliders[ sSliderID ].oPointersDiv ) aSliders[ sSliderID ].oPointersDiv.parentNode.removeChild( aSliders[ sSliderID ].oPointersDiv );
		if ( aSliders[ sSliderID ].oCoverDiv ) aSliders[ sSliderID ].oCoverDiv.parentNode.removeChild( aSliders[ sSliderID ].oCoverDiv );
		aSliders[ sSliderID ] = null;
	}

	/* orientation */
	var sOrientation = ( Common.Class.match( oSlider, sSliderVertical ) )? sSliderVertical : sSliderHorizontal;
	var sMarksType = ( Common.Class.match( oSlider, sSliderMarksEven ) )? sSliderMarksEven : sSliderMarksProportional;

	/* pointers and ticks */
	var aPointers = new Array();
	var aMarks = new Array();

	/* get slider limits */
	var aLimits = getNamedValuesArray( sSliderLimits, oSlider.className );
	var iMin = aLimits[ sSliderClassMinValue ];
	var iMax = aLimits[ sSliderClassMaxValue ];

	var aRadioInputs = new Array();

	/* analize inputs */
	for ( var i = 0; i < aFormElemNames.length; i++ ) {
		for ( var iElemIdx = 0; ( oFormElem = oSlider.getElementsByTagName( aFormElemNames[i] )[iElemIdx] ); iElemIdx++ ) {

			if ( aFormElemNames[i] == 'select' ) {
				dissectSelect( oSlider, sSliderID, oFormElem, aPointers, aMarks );
			} else if ( aFormElemNames[i] == 'input' && oFormElem.type.toLowerCase() == 'text' ) {
				dissectTextInput( oSlider, sSliderID, oFormElem, aPointers, aMarks );
			} else if ( aFormElemNames[i] == 'input' && oFormElem.type.toLowerCase() == 'radio' ) {
				dissectRadioInput( oSlider, sSliderID, oFormElem, aRadioInputs, aPointers, aMarks );
			}
		}
	}

	/* get marks from class names */
	createMarksFromClassNames( oSlider, sSliderID, oSlider.className, null, aMarks );

	/* create slider object */
		/* gonarch: добавил указатель на HTML элемент */	
	aSliders[ sSliderID ] = new Slider( sSliderID, oSlider, sOrientation, sMarksType, aPointers, aMarks, iMin, iMax, oSlider );
	
	iSliders++;

	/* create marks */
	var oMarks = buildSliderMarks( aSliders[ sSliderID ] );
	if ( oMarks ) {
		oSlider.appendChild( oMarks );
		aSliders[ sSliderID ].oGridDiv = oMarks;
	}

	/* create pointers */
	var oPointers = buildSliderPointers( aSliders[ sSliderID ] );
	if ( oPointers ) {
		oSlider.appendChild( oPointers );
		aSliders[ sSliderID ].oPointersDiv = oPointers;
	}

	/* create 'cover' */
	var sCoverID = sSliderID + 'cover';
	var oCover = document.createElement('div');
	oCover.className = sSliderCoverClass;

	oCover.onmousedown = sliderMouseDown;
	oCover.onkeydown = sliderKeyDown;

	oSlider.appendChild( oCover );
	aSliders[ sSliderID ].oCoverDiv = oCover;

	if ( isSliderKbdAccess ) oCover.tabIndex = 0;
	oCover.id = sCoverID;
	oSlider.id = sSliderID;
	aCovers[ sCoverID ] = sSliderID;

	oSlider.unselectable = true;
}


// building marks
function compareSliderMarksPosValues( oMarkA, oMarkB ) {
	return oMarkA.iPosValue - oMarkB.iPosValue;
}

function findSliderMarkPosValue( oMark ) {
	if ( oMark.sPosValue && !isNaN( parseInt( oMark.sPosValue ) ) ) return parseInt( oMark.sPosValue );
	if ( oMark.sValue && !isNaN( parseInt( oMark.sValue ) ) ) return parseInt( oMark.sValue );
	return 0;
}

function findSliderMarkValue( oMark ) {
	if ( oMark.sValue && !isNaN( parseInt( oMark.sValue ) ) ) return parseInt( oMark.sValue );
	if ( oMark.sPosValue && !isNaN( parseInt( oMark.sPosValue ) ) ) return parseInt( oMark.sPosValue );
	return 0;
}

function calcSliderMarkPositions( oSlider ) {
	var bCreateMin = false;
	var bCreateMax = false;
	if ( oSlider.aMarks.length ) {
		var iMin = findSliderMarkPosValue( oSlider.aMarks[0] );
		var iMax = findSliderMarkPosValue( oSlider.aMarks[0] );
		for ( var i = 0; i < oSlider.aMarks.length; i++ ) {
			oSlider.aMarks[i].iValue = findSliderMarkValue( oSlider.aMarks[i] );
			oSlider.aMarks[i].iPosValue = findSliderMarkPosValue( oSlider.aMarks[i] );
			if ( oSlider.aMarks[i].iPosValue < iMin ) iMin = oSlider.aMarks[i].iPosValue;
			if ( oSlider.aMarks[i].iPosValue > iMax ) iMax = oSlider.aMarks[i].iPosValue;
		}
		if ( oSlider.iMin && oSlider.iMin < iMin ) { bCreateMin = true; iMin = oSlider.iMin; }
		if ( oSlider.iMax && oSlider.iMax > iMax ) { bCreateMax = true; iMax = oSlider.iMax; }
	} else {
		bCreateMin = true;
		bCreateMax = true;
		if ( oSlider.iMin ) iMin = oSlider.iMin;
			else { iMin = iSliderDefaultMin; oSlider.iMin = iSliderDefaultMin; }
		if ( oSlider.iMax ) iMax = oSlider.iMax;
			else { iMax = iSliderDefaultMax; oSlider.iMax = iSliderDefaultMax; }
	}
	oSlider.iMin = iMin;
	oSlider.iMax = iMax;
	if ( bCreateMin ) {
		oSlider.aMarks[ oSlider.aMarks.length ] = new SliderMark(
			oSlider.sSliderID, null,
			false, false, oSlider.iMin, oSlider.iMin,
			'', null, '', null, oSlider.iMin, oSlider.iMin
		)
	}
	if ( bCreateMax ) {
		oSlider.aMarks[ oSlider.aMarks.length ] = new SliderMark(
			oSlider.sSliderID, null,
			false, false, oSlider.iMax, oSlider.iMax,
			'', null, '', null, oSlider.iMax, oSlider.iMax
		)
	}
	oSlider.aMarks = oSlider.aMarks.sort( compareSliderMarksPosValues );

	/* gonarch: хочу равномерные марки... */
	/* leechy: делаем правильно... */
	var iInterval;
	if ( oSlider.sMarksType == sSliderMarksEven ) {
		iInterval = oSlider.aMarks.length - 1;
		for ( var i = 0; i < oSlider.aMarks.length; i++ ) {
			oSlider.aMarks[i].iPos = 100 / iInterval * i;
		}
	} else {
		iInterval = oSlider.iMax - oSlider.iMin;
		for ( var i = 0; i < oSlider.aMarks.length; i++ ) {
			var iValue = oSlider.aMarks[i].iPosValue - oSlider.iMin;
			oSlider.aMarks[i].iPos = iValue / iInterval * 100;
		}
	}
}

function buildSliderMarks( oSlider ) {
	var oGrid = document.createElement('div');
	oGrid.className = sSliderMarksGridClass;
	calcSliderMarkPositions( oSlider );

	for ( var i = 0; i < oSlider.aMarks.length; i++ ) {
		var sMarkClass = sSliderDefaultMarkClass;
		if ( oSlider.aMarks[i].sClassName ) sMarkClass += ' ' + oSlider.aMarks[i].sClassName;
		if ( i == 0 ) sMarkClass += ' ' + sSliderStartMarkClass;
		if ( i == oSlider.aMarks.length - 1 ) sMarkClass += ' ' + sSliderEndMarkClass;

		var oMarkContent = document.createElement('span');
		var sMarkContent = oSlider.aMarks[i].sText || sSliderDefaultMarkContent;
		oMarkContent.innerHTML = sMarkContent;
		var oMark = createSliderContainer( null, sMarkClass, oMarkContent );

		oMarkContent.onmousedown = sliderMouseDown;
		//oCover.onmousedown = sliderMouseDown;

		if ( oSlider.sOrientation == sSliderVertical ) {
			oMark.style.marginTop = oSlider.aMarks[i].iPos + '%';
		} else {
			oMark.style.marginLeft = oSlider.aMarks[i].iPos + '%';			
		}
		
		// alpha. Добавляем класс, чтобы можно было манипулировать шрифтами
		Common.Class.add(oMark, 'mark-font-' + i);
		
		// добавляем указатель на элемент
		oSlider.aMarks.oMarkElem = oMark;
		oGrid.appendChild( oMark );
	}

	return oGrid;
}


// building pointers
function buildSliderPointers( oSlider ) {
	var oGrid = document.createElement('div');
	oGrid.className = sSliderPointersGridClass;

	for ( var i = 0; i < oSlider.aPointers.length; i++ ) {
		var oPointerContent = document.createElement('div');
		oPointerContent.innerHTML = sSliderDefaultPointerContent;
		var sPointerClass = sSliderPointerClass + ' ' + oSlider.aPointers[i].oElem.className;
		var oPointer = createSliderContainer( oSlider.aPointers[i].sPointerID, sPointerClass, oPointerContent );

		oSlider.aPointers[i].oPointerElem = oPointer;
		oSlider.aPointers[i].recalcPositionFromValue();

		if ( oSlider.sOrientation == sSliderVertical ) {
			oPointer.style.top = oSlider.aPointers[i].iPos + '%';
		} else {
			oPointer.style.left = oSlider.aPointers[i].iPos + '%';
		}

		oGrid.appendChild( oPointer );

		/* create min-max div */
		var oLimits = document.createElement('div');
		oLimits.className = sSlidexLimitsClass;
		
		oSlider.aPointers[i].oLimitsElem = oLimits;

		oGrid.appendChild( oLimits );
		oSlider.aPointers[i].resizeLimitsElem();
	}

	return oGrid;
}


function createSliderContainer( sElemID, sClassNames, oContent ) {
	var oTable = document.createElement('table');
	if ( sElemID ) oTable.id = sElemID;
	oTable.className = sClassNames;
	var oTBody = document.createElement('tbody');
	var oTableRow = document.createElement('tr');
	var oTableCell = document.createElement('td');
	var oCenterDiv = document.createElement('div');
	oCenterDiv.className = sSliderContainerCenterDivClass;

	if ( oContent ) oCenterDiv.appendChild( oContent );
	oTableCell.appendChild( oCenterDiv );
	oTableRow.appendChild( oTableCell );
	oTBody.appendChild( oTableRow );
	oTable.appendChild( oTBody );
	return oTable;
}


/****************************************/
/*     slider position and movement     */
/****************************************/

function comparePointersPos( a, b ) { return a.iPos - b.iPos; }
function getSliderPointerFromPosition( oSlider, iNewPos ) {
	if ( oSlider.aPointers.length > 1 ) {
		oSlider.aPointers.sort(comparePointersPos);
		for ( var i = 0; i < oSlider.aPointers.length - 1; i++ ) {
			if ( iNewPos <= oSlider.aPointers[i].iPos ) return i;
				else if ( iNewPos > oSlider.aPointers[i].iPos && iNewPos < oSlider.aPointers[i + 1].iPos ) {
					return ( ( iNewPos - oSlider.aPointers[i].iPos ) > ( oSlider.aPointers[i + 1].iPos - iNewPos ) )? i + 1 : i;
				}
		}
		return oSlider.aPointers.length - 1;
	} else {
		return 0;
	}
}

function moveActiveSliderPointer( iCurrentWindowPos ) {
	if ( oActiveSlider ) {
		var iNewPos = ( iCurrentWindowPos - iActiveSliderWindowOffset ) / iActiveSliderSize * 100;
		if ( oActiveSlider.iActivePointer == null ) oActiveSlider.iActivePointer = getSliderPointerFromPosition( oActiveSlider, iNewPos );
		var oPointer = oActiveSlider.aPointers[ oActiveSlider.iActivePointer ];
		if ( oPointer && !oPointer.bDisabled ) {
			var iNewValue = oPointer.recalcValueFromNewPosition( iNewPos );
			if ( Math.round( iNewValue ) != oPointer.iValue ) {
				oPointer.iValue = Math.round( iNewValue );
				oPointer.recalcPositionFromValue();
				oPointer.movePointer();
			}
		}
	}
}

function changeSliderPointerValue( oPointer ) {
	/* gonarch: fixed problem with radiobutton switch */
	/* leechy: a little bit changed */
	switch ( oPointer.oElem.type ) {
		case 'radio':
			if ( oPointer.oMark ) {
				oPointer.oMark.oElem.checked = true;
				if ( oPointer.oMark.oElem.onclick ) oPointer.oElem.onclick();
			}
			break;
		default:
			oPointer.oElem.value = oPointer.iValue;
			if ( oPointer.oElem.onchange ) oPointer.oElem.onchange();
	}
}


/***************************/
/*     event capturing     */
/***************************/

var oActiveSlider = null;
var iActiveSliderSize = 0;
var iActiveSliderLayerPos = 0;
var iActiveSliderWindowPos = 0;
var iActiveSliderWindowOffset = 0;

function sliderMouseDown( evt ) {
	var oSlider = null;
	if ( aCovers[ this.id ] && aSliders[ aCovers[ this.id ] ] ) oSlider = aSliders[ aCovers[ this.id ] ];
		else if ( aSliders[ this.id ] ) oSlider = aSliders[ this.id ];

	if ( oSlider ) {

		if ( oSlider.sOrientation == sSliderVertical ) {
			iActiveSliderSize = this.offsetHeight;
			iActiveSliderLayerPos = ( window.event )? event.offsetY : evt.layerY;
			iActiveSliderWindowPos = ( window.event )? event.clientY : evt.pageY;
		} else {

			iActiveSliderSize = this.offsetWidth;
			iActiveSliderLayerPos = ( window.event )? event.offsetX : evt.layerX;
			iActiveSliderWindowPos = ( window.event )? event.clientX : evt.pageX;

		}
		iActiveSliderWindowOffset = iActiveSliderWindowPos - iActiveSliderLayerPos;
		oActiveSlider = oSlider;
		moveActiveSliderPointer( iActiveSliderWindowPos );

		if ( isSliderKbdAccess && oSlider.oCoverDiv && oSlider.oCoverDiv.focus ) oSlider.oCoverDiv.focus();
		return false;
	}
}

function sliderKeyDown( evt ) {
}


function moveMouse( evt ) {
	if ( oActiveSlider ) {
		if ( evt && evt.cancelable && evt.preventDefault ) evt.preventDefault();
		if ( window.event && event.cancelBubble ) event.cancelBubble = true;
		if ( oActiveSlider.sOrientation == sSliderVertical ) {
			var iCurrentWindowPos = ( window.event )? event.clientY : evt.pageY;
		} else {
			var iCurrentWindowPos = ( window.event )? event.clientX : evt.pageX;
		}
		moveActiveSliderPointer( iCurrentWindowPos );
		return false;
	}
	return true;
}

function upMouse( evt ) {
	if ( oActiveSlider ) {
		if ( oActiveSlider.iActivePointer != null ) oActiveSlider.iActivePointer = null;
		oActiveSlider = null;
	}
}

function sliderSelectChanged() {
	var oSelect = (window.event)? event.srcElement : this;
	for ( var sSldrId in aSliders ) {
		for ( var iPtrIdx = 0; iPtrIdx < aSliders[ sSldrId ].aPointers.length ; iPtrIdx++ ) {
			if ( aSliders[ sSldrId ].aPointers[ iPtrIdx ].oElem == oSelect ) {
				// to be changed - we must use some internal method to set values
				aSliders[ sSldrId ].aPointers[ iPtrIdx ].iValue = oSelect.value;
				aSliders[ sSldrId ].aPointers[ iPtrIdx ].recalcPositionFromValue();
				aSliders[ sSldrId ].aPointers[ iPtrIdx ].movePointer();
			}
		}
	}
}

function sliderRadioChanged() {
	var oRadio = (window.event)? event.srcElement : this;
	for ( var sSldrId in aSliders ) {
		for ( var iMarkIdx = 0; iMarkIdx < aSliders[ sSldrId ].aMarks.length ; iMarkIdx++ ) {
			if ( aSliders[ sSldrId ].aMarks[ iMarkIdx ].oElem == oRadio ) {
				// to be changed - we must use some internal method to set values
				aSliders[ sSldrId ].aPointers[0].iValue = oRadio.value;
				aSliders[ sSldrId ].aPointers[0].recalcPositionFromValue();
				aSliders[ sSldrId ].aPointers[0].movePointer();
			}
		}
	}
}



/****************/
/*     init     */
/****************/

function initSliders() {

	for ( var iElemIdx = 0; ( oDivElem = document.getElementsByTagName('div').item( iElemIdx ) ); iElemIdx++ ) {
		if ( Common.Class.match( oDivElem, 'slider' ) && !Common.Class.match( oDivElem, sSliderInitedClass ) ){ createSlider( oDivElem ); Common.Class.add( oDivElem, sSliderInitedClass ); }
	}
	
	Common.Event.add(document, 'mousemove', moveMouse);
	Common.Event.add(document, 'mouseup', upMouse);
	if ( window.onSlidersLoad ) onSlidersLoad();
}

Common.Event.add(window, 'load', initSliders);





/*****************************/
/*     support functions     */
/*****************************/

function getNamedValuesArray( sNames, sValues, sDivider ) {
	sDivider = sDivider || sSliderClassValuesDivider;
	sValues = ' ' + sValues;
	var aValues = new Array();
	if ( sNames && sValues ) {
		aNames = sNames.split(/[|\s]/);
		for ( var i = 0; i < aNames.length; i++ ) {
			if ( aNames[i].length ) {
				var sName = ' ' + aNames[i] + sDivider;
				var iStartPos = sValues.indexOf( sName );
				if ( iStartPos >= 0 ) {
					iStartPos += sName.length;
					var iEndPos = sValues.indexOf( ' ', iStartPos );
					if ( iEndPos < 0 ) iEndPos = sValues.length;
					aValues[ aNames[i] ] = sValues.substring( iStartPos, iEndPos );
				} else aValues[ aNames[i] ] = null;
			}
		}
	}
	return aValues;
}

function getValuesArrayByName( sName, sValues, sDivider ) {
	sDivider = sDivider || sSliderClassValuesDivider;
	var aValues = new Array();
	sValues = ' ' + sValues;
	var sName = ' ' + sName + sDivider;
	var iStartPos = sValues.indexOf( sName );
	while ( iStartPos >= 0 ) {
		iStartPos += sName.length;
		var iEndPos = sValues.indexOf( ' ', iStartPos );
		if ( iEndPos < 0 ) iEndPos = sValues.length;
		var sTempValues = sValues.substring( iStartPos, iEndPos );
		aValues[ aValues.length ] = sTempValues.split( sDivider );
		iStartPos = sValues.indexOf( sName, iEndPos );
	}
	return aValues;
}

function getIntValueByPrefix( aValues, sPrefix ) {
	for ( var i = 0; i < aValues.length; i++ )
		if ( aValues[i].indexOf( sPrefix ) == 0 ) return parseInt( aValues[i].substr( sPrefix.length ) );
	return null;
}


/* reminder(s) */
function getREM( aValues, iDivider ) {
	var iREM = 0;
	for ( var i in aValues ) iREM += aValues[i] % iDivider;
	return iREM;
}

/* greatest common divisor */
function getGCD( aValues ) {
	var iMin = aValues[0];
	for ( var i in aValues ) if ( aValues[i] < iMin ) iMin = aValues[i];
	while ( iMin > 1 && getREM( aValues, iMin ) ) iMin--;
	return iMin;
}


function getAttribute(oNode, sAttr){
	return (oNode.attributes) ? oNode.attributes[sAttr].nodeValue : oNode.getAttribute(sAttr);
}

/* gonarch: возвращает ID слайдера, которому принадлежит целевой элемент */
function getSliderID( oTarget ){
	var re = new RegExp("^"+sSliderIDPrefix+"\\d+$");
	var oDivs;
	do {
		if ( oTarget.id && re.test(oTarget.id) ) return oTarget.id;
		oDivs = oTarget.getElementsByTagName('div');
		for (var i=0; i < oDivs.length ; i++ ) {
			if( oDivs[i].id && re.test(oDivs[i].id) )
			return oDivs[i].id;
		}
	} while (oTarget = oTarget.offsetParent)
	return null;
}


function SliderIsEnabled(strCSliderId){ //проверяет, влючен ли слайдер
	if( aSliders[ strCSliderId ] ){
		var oRef = aSliders[ strCSliderId ].oElem;
		//return (document.getElementById(strCSliderId).className.indexOf('disabled') > -1) ? false : true;
		return !Common.Class.match(oRef, sSliderDisabledClass);
	}
}

function SliderDisable(strCSliderId){ //отключает слайдер
	if ( aSliders[ strCSliderId ] && SliderIsEnabled(strCSliderId) ){
		Common.Event.add(aSliders[ strCSliderId ].oElem, sSliderDisabledClass);
	}
}

function SliderEnable(strCSliderId) { //включает слайдер
	if( aSliders[ strCSliderId ] && !SliderIsEnabled(strCSliderId) ){
		Common.Class.remove( aSliders[ strCSliderId ].oElem, sSliderDisabledClass );
	}
}