/*
Class: Slider
        Creates a slider with two elements: a knob and a container. Returns the values.
Note:
        The Slider requires an XHTML doctype.
Arguments:
        element - the knob container
        knob - the handle
        options - see Options below
        maxknob - an optional maximum slider handle
Options:
		start - the minimum value for your slider.
		end - the maximum value for your slider.
        mode - either 'horizontal' or 'vertical'. defaults to horizontal.
        offset - relative offset for knob position. default to 0.
        knobheight - positions the max slider knob
		snap - whether the slider will slide in steps 
		numsteps - number of slide steps 
Events:
        onChange - a function to fire when the value changes.
        onComplete - a function to fire when you're done dragging.
        onTick - optionally, you can alter the onTick behavior, for example displaying an effect of the knob moving to the desired position.
                Passes as parameter the new position.
*/
var SliderDouble = new Class({
	options: {
		onChange: Class.empty,
		onComplete: Class.empty,
		onTick: function(pos){
			this.moveKnob.setStyle(this.p, pos);			
		},
		start: 0,
		end: 100,
		offset: 0,
		knobheight: 13,
		knobwidth: 12,
		mode: 'horizontal',
		clip_w:0, 
		clip_l:0,
		isinit:true,
		snap: false,
		range: false,
		step:null
	},
    initialize: function(el, knob, bkg, options, maxknob) {
		this.setOptions(options);
		this.element = $(el);
		this.knob = $(knob);
		this.step = this.options.start;
		this.previousChange = this.previousEnd = -1;
		this.bkg = $(bkg);
		
		if(this.options.steps == null){
			this.options.steps = this.options.end - this.options.start;
			/*if (this.options.step == null) {
				this.options.steps = this.options.end - this.options.start;
			} else {
				this.options.steps = Math.abs(this.options.end - this.options.start) / this.options.step;
			}*/
		}
		if(maxknob != null)
			this.maxknob = $(maxknob);

		var mod, offset;
		switch (this.options.mode) {
			case 'horizontal':
				this.z = 'x';
				this.p = 'left';
				mod = {'x': 'left', 'y': false};
				offset = 'offsetWidth';
				break;
			case 'vertical':
				this.z = 'y';
				this.p = 'top';
				mod = {'x': false, 'y': 'top'};
				offset = 'offsetHeight';
		}
		this.max = this.element[offset] - this.knob[offset] * 2 + (this.options.offset * 2);
		this.half = this.knob[offset]/2;
		this.full = this.element[offset] - this.knob[offset] * 2 + (this.options.offset * 2);
		this.min = $chk(this.options.range[0]) ? this.options.range[0] : 0;
		this.getPos = this.element['get' + this.p.capitalize()].bind(this.element);
		this.knob.setStyle(this.p, - this.options.offset);

		this.range = this.max - this.min;
		this.steps = this.options.steps || this.full;
		this.stepSize = Math.abs(this.range) / this.steps;
		this.stepWidth = this.stepSize * this.full / Math.abs(this.range) ;
		
		this.bkg.setStyles({
			left : 0,
			width: this.full,
			margin: '0px ' + this.options.knobwidth + 'px'
		});
		
		var lim = {}; 
		lim[this.z] = [- this.options.offset, this.full - this.options.knobwidth - this.options.offset];

		if(maxknob != null) {
			this.maxPreviousChange = -1;
			this.maxPreviousEnd = -1;
			this.maxstep = this.options.end;
			this.maxknob.setStyle(this.p, this.full - this.options.offset + this.options.knobwidth);
			
			var limm = {};
			limm[this.z] = [- this.options.offset + this.options.knobwidth, this.full - this.options.offset + this.options.knobwidth];
		}

		this.drag = new Drag(this.knob, {
			limit: lim,
			modifiers: mod,
			snap: 0,
			onStart: function(){
					this.draggedKnob();
			}.bind(this),
			onDrag: function(){
					this.draggedKnob();
			}.bind(this),
			onComplete: function(){
					this.draggedKnob();
					this.end();
			}.bind(this)
		});
		
		if(maxknob != null) {  
			this.maxdrag = new Drag(this.maxknob, {
				limit: limm,
				modifiers: mod,
				snap: 0, 
				onStart: function(){
					this.draggedKnob(1);
				}.bind(this),
				onDrag: function(){
					this.draggedKnob(1);
				}.bind(this),
				onComplete: function(){
					this.draggedKnob(1);
					this.end();
				}.bind(this)
			});		
		}
		
		if (this.options.snap) {
			var grid = (this.full / Math.abs(this.options.end - this.options.start)) * this.options.step;
			this.drag.options.grid = grid;
			this.maxdrag.options.grid = grid;
		}
		if (this.options.initialize) this.options.initialize.call(this);
    },
	setMin: function(stepMin){
    	this.step = stepMin.limit(this.options.start, this.options.end);
		this.checkStep();
		//this.end();
		this.moveKnob = this.knob;
		
		this.bkg.setStyles({
			left : this.toPosition(this.step),
			width: Math.abs(this.toPosition(this.step)- this.toPosition(this.maxstep))
		});

		this.fireEvent('onTick', this.toPosition(this.step));
		return this;
	},
	setMax: function(stepMax){
		this.maxstep = stepMax.limit(this.options.start, this.options.end);
		this.checkStep(1);
		this.maxknob.setStyle(this.p, this.toPosition(this.maxstep) - this.options.offset);
		
		this.moveKnob = this.maxknob;
		this.bkg.setStyles({
			width : Math.abs(this.toPosition(this.step)- this.toPosition(this.maxstep)) - this.options.knobwidth
		});

		this.fireEvent('onTick', this.toPosition(this.maxstep));
		// For Init Only 
		if(this.options.isinit){
			var lim = {}; var mi,mx;
			mi = - this.options.offset; 
			mx = parseInt(this.maxknob.getStyle('left')) - this.options.offset - this.options.knobwidth ;
			lim[this.z] = [mi, mx];
			this.drag.options.limit = lim;
			this.options.isinit = false;
		}
		return this; 
	},
	clickedElement: function(event){
		var position = event.page[this.z] - this.getPos() - this.half;
		position = position.limit(-this.options.offset, this.max -this.options.offset);

		this.step = this.toStep(position);

		this.bkg.setStyles({
			left : this.clip_l,
			width : r
		});
		this.checkStep();
		this.end();
		this.fireEvent('onTick', position);
	},

	draggedKnob: function(mx){
		var lim = {}; var mi,mx;
		if(mx==null) {
			this.step = this.toStep(this.drag.value.now[this.z]);	 
			this.checkStep();
		}else {
			this.maxstep = this.toStep(this.maxdrag.value.now[this.z] - this.options.knobwidth); 
			this.checkStep(1);
		}
	},
	checkStep: function(mx){
		var lim = {}; 
		var limm = {};
		var mi, mx;
		
		if(mx == null) {
			if (this.previousChange != this.step){
				this.previousChange = this.step;
			}
		} else {
			if (this.maxPreviousChange != this.maxstep){
				this.maxPreviousChange = this.maxstep;
			}
		}
		if(this.maxknob != null) {
			mi = -this.options.offset; 
			mx = parseInt(this.maxknob.getStyle('left')) - this.options.knobwidth ;
			lim[this.z] = [mi, mx];
			this.drag.options.limit = lim;
			
			mi = parseInt(this.knob.getStyle('left')) - this.options.offset + this.options.knobwidth; 
			mx= this.full + this.options.offset + this.options.knobwidth;
			limm[this.z] = [mi, mx];
			this.maxdrag.options.limit = limm; 
			
			var minpos = (this.step < this.maxstep) ? this.step : this.maxstep;
			var maxpos = (this.step < this.maxstep) ? this.maxstep : this.step;
			
			if (this.options.step > 0) {
				minpos = Math.floor(minpos / this.options.step) * this.options.step;
				maxpos = Math.floor(maxpos / this.options.step) * this.options.step;
			}
			this.fireEvent('onChange', { 'minpos': minpos, 'maxpos': maxpos });
			
			this.clip_l = parseInt(this.knob.getStyle('left'));
			var w = Math.abs(parseInt(this.knob.getStyle('left')) - parseInt(this.maxknob.getStyle('left'))) - this.options.knobwidth;
			
			this.bkg.setStyles({
				left : this.clip_l,
				width : w 
			});
		}else {  
			this.fireEvent('onChange', this.step);
			this.bkg.style.clip = "rect(0px "+  (parseInt(this.drag.value.now[this.z]) +3)  + "px 10px 0px)";  

		}
	},
	end: function(){
		if (this.previousEnd !== this.step || (this.maxknob != null && this.maxPreviousEnd != this.maxstep)) {
			this.previousEnd = this.step;
			if(this.maxknob != null) {
				this.maxPreviousEnd = this.maxstep;
				if(this.step < this.maxstep)
					this.fireEvent('onComplete', { minpos: this.step + '', maxpos: this.maxstep + '' });
				else    
					this.fireEvent('onComplete', { minpos: this.maxstep + '', maxpos: this.step + '' });
			}else{  
				this.fireEvent('onComplete', this.step + '');
			}
		}
	},
	
	toStep: function(position){
		//return Math.round((position + this.options.offset) / this.full * this.options.steps * this.options.step) + this.options.start;
		return Math.round((position + this.options.offset) / this.stepSize) + this.options.start;
	},

	toPosition: function(step){
		//return (this.full * step / this.options.steps) - (this.full * this.options.start / this.options.steps) - this.options.offset;
		return (this.full + this.options.knobwidth) * (step - this.options.start) / this.options.steps - this.options.offset;
	}

});

SliderDouble.implement(new Events);
SliderDouble.implement(new Options);
