/*
*	Track — id of parent elenemt
*	Tracker — id of tracked element
*	OnUpdate — function which is called each time, when Tracker moved
*	OnComplete — function which is called when user stop draging
*	FingerOffset — distance between mouse pointer and corner tracker's edge
*	FormatNumbers — lead numders in hairlines with spaces
*	Min & Max — range of values
*   P[i](i=4 yet) - values of scale points
*	MinSpaceExist — exist of minimum difference between Min & Max(equals RoundTo)
*	RoundTo[i](i=5) — values will be rounded to this value(in subscales)
*	Margins — indent between Track & Tracker
*	AllowedValues — force Tracker to stick to the values
*/

function cDoubleTrackBar(Track, Tracker, Settings, Scales) {
	switch(typeof Track){
		case 'string': this.Track = document.getElementById(Track); break;
		case 'object': this.Track = Track; break;
	}
	switch(typeof Tracker){
		case 'string': this.Tracker = document.getElementById(Tracker); break;
		case 'object': this.Tracker = Tracker; break;
	}
	if (!Track || !Tracker)
		return false;
	this.OnUpdate = Settings.OnUpdate;
	this.OnComplete = Settings.OnComplete;
	this.FingerOffset = Settings.FingerOffset || 8;	 
    this.Margins = Settings.Margins || 15;
	this.MinSpaceExist = Settings.MinSpaceExist || false;
	this.FormatNumbers = Settings.FormatNumbers || true;	
	this.AllowedValues = Settings.AllowedValues || false;
    
    this.Scales = Scales;    
    for(index in this.Scales) { this.SetScale(Scales[index]); break; } 
	
	this.Disabled = (typeof Settings.Disabled != 'undefined') ? Settings.Disabled : false;	

	this.Track.style.width = (this.Track.clientWidth || this.Track.offsetWidth) + 'px';
	this.OnTrackMouseDown = this.bindAsEventListener(this.TrackMouseDown);
	this.OnDocumentMouseMove = this.bindAsEventListener(this.DocumentMouseMove);
	this.OnDocumentMouseUp = this.bindAsEventListener(this.DocumentMouseUp);	
	this.bindEvent(this.Track, 'mousedown', this.OnTrackMouseDown);   
	this.TrackerLeft = 0;
	
	this.UpdateTracker(this.Track.offsetWidth + this.FingerOffset);
	
	if((isFinite(Settings.MinPos) || isFinite(Settings.MaxPos))&& Settings.ScaleName != null)
	    this.Initialize(Settings.MinPos, Settings.MaxPos, Settings.ScaleName); 
    
	if (typeof this.OnUpdate == 'function') {
		this.OnUpdate.call(this);}
	this.fix = this.classFilter(this.Tracker.getElementsByTagName('*'), 'flr');
}
cDoubleTrackBar.prototype = {
    Initialize: function(minPos, maxPos, scaleName){
        this.ScaleName = scaleName; //to delete?        	    
	    this.SetScale(this.Scales[scaleName]);
	    this.SetPosition(minPos, maxPos);	    
    },
    SetPosition: function(minPos, maxPos,flag){
        this.MinPos = minPos >= this.Min?minPos:this.Min;
	    this.MaxPos = maxPos <= this.Max?maxPos:this.Max;
	    if(this.MinPos > this.MaxPos){this.MinPos = 0; this.MaxPos = this.MaxPos;} 	    
        var _LogicWidth = this.Track.offsetWidth - this.Margins*2 - 1;
		var _segWidth = (_LogicWidth+1)/(this.P.length-1);
	    var _subwidth = _segWidth/this.SubSeg;	    
	    var _minSpace = this.MinSpaceExist ? _subwidth : 0;
        for(var i=0; i<(this.P.length - 1); i++){ 
            pi  = this.P[i]; 
            pii = this.P[i+1];
            var snum = i;             
            if(pi <= this.MinPos && this.MinPos < pii){                
                var mnum = Math.round((this.MinPos - pi)*this.SubSeg/(pii - pi));
                this.TrackerLeft = Math.max(0, Math.min(this.TrackerRight - _minSpace - 1, _segWidth*snum + mnum*_subwidth));
                //this.MinPos = Math.min(this.MaxPos, this.Min + pi + this.RoundTo[i]*mnum);
                }
            if(pi <= this.MaxPos && this.MaxPos < pii){
                var mnum = Math.round((this.MaxPos - pi)*this.SubSeg/(pii - pi));
                this.TrackerRight = Math.max(this.TrackerLeft + _minSpace + 1, Math.min(_LogicWidth + 1, _segWidth*snum + mnum*_subwidth));
                //this.MaxPos =Math.max(this.MinPos, this.Min + pi + this.RoundTo[i]*mnum); 
                }   
            }
        	
		this.Left = true;
	    this.UpdateTracker(this.TrackerLeft + this.Margins - this.FingerOffset);
	    this.Left = false;
	    this.UpdateTracker(this.TrackerRight + this.Margins + this.FingerOffset);
	    if(this.OnComplete!=null) this.OnComplete.call(this,flag);  
    },
	TrackMouseDown: function(event) {
		this.TrackerLeft = this.Tracker.offsetLeft - this.Margins;
		this.TrackerRight = Math.min(this.TrackerLeft + this.Tracker.offsetWidth, this.Track.offsetWidth - this.Margins*2 - 1 + 1);

		this.TrackerOffsets = this.getOffsets(this.Track);

		var X = event.clientX + document.documentElement.scrollLeft;
		X -= this.TrackerOffsets[0];

		this.Left = Math.abs(this.TrackerLeft-X+this.Margins) <= Math.abs(this.TrackerRight-X+this.Margins);

		if (typeof this.Disabled == 'function') {
			if ( this.Disabled.call(this) )
				return true;
		} else if ( this.Disabled )
			return true;		
		
		this.UpdateTracker(X);

		this.bindEvent(document, 'mousemove', this.OnDocumentMouseMove);
		this.bindEvent(document, 'mouseup', this.OnDocumentMouseUp);

		return this.stopEvent(event);
	},
	DocumentMouseMove: function(event) {
		this.UpdateTracker(event.clientX + document.documentElement.scrollLeft - this.TrackerOffsets[0]);
		return this.stopEvent(event);
	},
	DocumentMouseUp: function(event) {
		this.unbindEvent(document, 'mousemove', this.OnDocumentMouseMove);
		this.unbindEvent(document, 'mouseup', this.OnDocumentMouseUp);

		if (typeof this.OnComplete == 'function') {
			this.OnComplete.call(this,true);
		}
		return this.stopEvent(event);
	},		
	UpdateTracker: function(X){
		var _LogicWidth = this.Track.offsetWidth - this.Margins*2 - 1;
		var _segWidth = (_LogicWidth+1)/(this.P.length-1);
	    var _subwidth = _segWidth/this.SubSeg;
	    var _minSpace = this.MinSpaceExist ? _subwidth : 0;
		X -= this.Margins;
		var _oldMin = this.MinPos;
		var _oldMax = this.MaxPos;
		if(this.Left){					
		    X += this.FingerOffset;		     
		    var snum = Math.min(this.P.length-2, (Math.floor(X/_segWidth) > 0 ? Math.floor(X/_segWidth): 0));
		    var XiS = X - _segWidth*snum;		    
	        var mnum =Math.min(this.SubSeg-1, (Math.floor(XiS/_subwidth) > 0 ? Math.floor(XiS/_subwidth): 0));    	               
            if( XiS - mnum*_subwidth >= _subwidth*(mnum+1) - XiS){mnum++;}
            this.TrackerLeft = Math.max(0, Math.min(this.TrackerRight - _minSpace -1, _segWidth*snum + mnum*_subwidth));
            this.MinPos = Math.min(this.MaxPos, this.Min + this.P[snum] + this.RoundTo[snum]*mnum);
	        if (this.AllowedValues){this.TrackerLeft = Math.round(_LogicWidth*(this.MinPos - this.Min)/(this.Max - this.Min));}
	    }
		else{		
		    X -= this.FingerOffset;
		    var snum = Math.min(this.P.length-2, (Math.floor(X/_segWidth) > 0 ? Math.floor(X/_segWidth): 0)); 
    	    var XiS = X - _segWidth*snum;		  
	        var mnum = Math.min(this.SubSeg-1, (Math.floor(XiS/_subwidth) > 0 ? Math.floor(XiS/_subwidth): 0));
            if(XiS - mnum*_subwidth >= _subwidth*(mnum+1) - XiS){mnum++;}
            this.TrackerRight = Math.max(this.TrackerLeft + _minSpace + 1, Math.min(_LogicWidth + 1, _segWidth*snum + mnum*_subwidth));
            this.MaxPos =Math.max(this.MinPos, this.Min + this.P[snum] + this.RoundTo[snum]*mnum);    
	        if (this.AllowedValues){this.TrackerRight = Math.round(_LogicWidth*(this.MaxPos - this.Min)/(this.Max - this.Min));}
	    }
		this.Tracker.style.width = (this.TrackerRight - this.TrackerLeft) + 'px';
		this.Tracker.style.left = (this.Margins + this.TrackerLeft) + 'px';		
		this.Tracker.style.backgroundPosition = -this.TrackerLeft + 'px center';			

		if (typeof this.OnUpdate == 'function')
			if ( !this.AllowedValues || (this.AllowedValues && (_oldMax!=this.MaxPos || _oldMin!=this.MinPos)) )
				this.OnUpdate.call(this);
				
		if (this.fix)
			for (var i in this.fix)
				this.fix[i].style.left = (this.TrackerRight - this.TrackerLeft ) + 'px';	
	},
	AddHairline: function (pos, index, first) {	    
		var _LogicWidth = this.Track.offsetWidth - this.Margins*2 - 1;
		if(index>=0 && index<(this.SubSeg) && first)
		{   for (var i=1; i<(this.SubSeg); i++)
		    {
		        var _lTouch = this.Track.appendChild(document.createElement('div'));
		        _lTouch.style.left = this.Margins + (_LogicWidth/((this.P.length-1)*this.SubSeg))*(index*this.SubSeg + i) + 'px';
		        _lTouch.className = 'l_touch';
		    }
		}
		var _Touch = this.Track.appendChild( document.createElement('div'));
        _Touch.style.left = this.Margins + (_LogicWidth/(this.P.length-1))*index + 'px';
		_Touch.className = 'touch';
		_Touch.innerHTML = "<span>" + (pos == this.Max ? '' :(this.FormatNumbers ? this.leadSpaces(pos) : pos)) + "</span>";
	},
	AutoHairline: function(num) {	          
	    var first = true;
		for (var i=(this.Track.childNodes.length - 1); i>0; i--){
            node = this.Track.childNodes[i];
            if(node.className == 'touch') {
                this.Track.removeChild(node); 
                first = false;} }
		for (var i=0; i<(num); i++) {
			var val = this.P[i];
			this.AddHairline(val, i, first);}
	},
	SetScale: function(Settings){	  
	    if(typeof(Settings)== "string"){ 
	        var values = Settings.split(',');
	        for(var i=0;values[i];i++){
	            var p = values[i].indexOf(':');	            
	            var l = values[i].length;
	            var par = values[i].substring(0,p);
	            var value = values[i].substring(p+1, l);
	            switch(par){case("Min"):this.Min = Number(value); break;
	                        case("Max"):this.Max = Number(value); break;
	                        case("P1"):this.P1 = Number(value); break;
	                        case("P2"):this.P2 = Number(value); break;
	                        case("P3"):this.P3 = Number(value); break;
	                        case("P4"):this.P4 = Number(value); break;} }
	        this.P = new Array(this.Min, this.P1, this.P2, this.P3, this.P4, this.Max); }  
	    else{	        
	        this.Min = Settings.Min || 0;
	        this.Max = Settings.Max || 100;
	        this.P = new Array(Settings.Min, Settings.P1, Settings.P2, Settings.P3, Settings.P4, Settings.Max);	 }
        this.MinPos = this.Min;
        this.MaxPos = this.Max;
	    this.SubSeg = Settings.SubSeg || 5;
	    this.RoundTo = new Array();
        for(var i=0; i<this.P.length-1; i++) {
            if(this.SubSeg != 0 || this.SubSeg != 1){
                this.RoundTo[i] = (this.P[i+1]- this.P[i])/this.SubSeg;}
            else {this.RoundTo[i] = this.Max - this.Min < this.RoundTo ? 1 : this.Max - this.Min;}}
        if (this.Min >= this.Max)
	        this.Max = this.Min +1; 
	    this.AutoHairline(this.P.length);   
	},
	ChangeScale: function(name,flag){
	    var scale = this.Scales[name];
	    this.SetScale(scale);
	    this.Left = true;
	    this.UpdateTracker(this.TrackerLeft + this.Margins - this.FingerOffset);
	    this.Left = false;
	    this.UpdateTracker(this.TrackerRight + this.Margins + this.FingerOffset);
	    if(this.OnComplete!=null) this.OnComplete.call(this,flag);
	},
	getOffsets: function(element) {
	    var valueT = 0, valueL = 0;
	    do {
			valueT += element.offsetTop  || 0;
			valueL += element.offsetLeft || 0;
			element = element.offsetParent;
	    } while (element);
	    return [valueL, valueT];
	},	
	leadSpaces: function(numb) {
		var res = '';
		numb = numb.toString();
		var l = numb.length;
		for (var i=l; i>0; i--)
        if ((l-i)%3==2 && i!=1)
				res = ' '+numb.charAt(i-1)+res;
			else
				res = numb.charAt(i-1)+res;
		return res;
	},
	bindEvent: function(element, event, callBack){
		if (element.addEventListener) {
			element.addEventListener(event, callBack, false);
		} else {
			element.attachEvent('on' + event, callBack);
		}
	},
	unbindEvent: function(element, event, callBack){
		if (element.removeEventListener) {
			element.removeEventListener(event, callBack, false);
	    } else if (element.detachEvent) {
			element.detachEvent('on' + event, callBack);
	    }
	},
	bindAsEventListener: function (callBack) {
		var _object = this;
		return function(event) {
			return callBack.call(_object, event || window.event);
		}
	},
	stopEvent: function (event){
		if (event.preventDefault) {
			event.preventDefault();
			event.stopPropagation();
		} else {
			event.returnValue = false;
			event.cancelBubble = true;
		}
		return false;
	},
	classFilter: function (r,m,not){
	    m = " " + m + " ";
	    var tmp = [];
	    for ( var i = 0; r[i]; i++ ) {    
	        var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
		    if ( not ^ pass ) tmp.push( r[i] );
	    }
	    return tmp;
	}
}
