/**
 
 ReCoded original jQuery plugin to
 jQuery UI widget for state and better controls

**/

(function($){

	var xlslider = {
		_init : function(internal)
		{
			this.create_divs();			
			this.checklowerlimit();
			
			this._setData('grid', this.calc_grid(this.return_snap()) );
			var self = this;
			
			var par = this.get('gutter');
			
			$('#' + this.get('ball')).draggable({
				axis: 'x'
				,containment: $('#'+par)
				,scroll: false
				,drag: function(event, ui) { 
					return self.handledrag(event, ui);
				}
				,stop: function() { 
					self.checkchildren();
					self.docallback('onvalchange',self.get('lastval')); 
					self.checklowerbound();
					self.submitchild();
					
					p = self.get('parentslider');
					if (p != null) return;
					
					self.docallback('dragstopcall'); 
				}
			});
		 	this.draw_grid();
		 	this.create_formobjects();	
		 	
		 	if (this.get('sendinitial') === 1)
		 	{
		 		var snap = this.get('snap');
		 		this.setslider( snap[0] );	
		 	}
		 	if (typeof(internal) != "undefined") return;
		 	p = this.get('parentslider');
		 	if (p == null) return;
		 	setTimeout( "$('"+this.get('selector')+"').xlslider('checkparent');", 500);
		 	
		}
		,checkparent: function(force)
		{
		 	p = this.get('parentslider');
		 	if (p == null) return;		
		 	var pv = $(p).xlslider("get_current");

		 	if (pv.length < 1) {
			 	setTimeout( "$('"+this.get('selector')+"').xlslider('checkparent');", 500);
			 	return;
		 	}	 	
		 	this.setbyparent(pv, force);
		}
		,setbyparent: function(val, force)
		{
		 	var t = this.get('threshold');
		 	var h=0;
		 	for( var i in t ) {
		 		if (parseInt(t[i]) < parseInt(val)) h = i;
		 	}

		 	this._setData('lowerbound', h);
		 	this.recalibrate(h, true, true);
		 	
			if ( force != true && this.get_current() > h) {
				return;
			}
		 	this.setslider(h, true);
		}
		,checkchildren: function()
		{
			var c = this.get('children');
			if (this.returnlen(c) < 1) return;
			
			for(var i in c)
			{
				var t = $(c[i]).xlslider("get","childfollowparent");
				$(c[i]).xlslider("setbyparent", this.get_current(), t);
			}
		}
		,submitchild: function()
		{
			var c = this.get('children');
			if (this.returnlen(c) < 1) return;
			for(var i in c) $(c[i]).xlslider("submit");
		}
		,submit: function()
		{
			var c = this.get_current();
			if (this.get('lastsubmit') == c) return;
			this.docallback('submitcallback', c);
			this._setData('lastsubmit',c);
		}
		,get: function (val)
		{
			return this._getData( val );
		},
		reload: function(internal)
		{
			this.element.empty();
			this._init(internal);
		},
		return_snap: function()
		{
			var s = this.get('snap');
			var skip = this.get('skipvals');
			if (this.returnlen(skip) < 1 ) return s;
			
			var ns = [];
			for (var i in s )
			{
				if (typeof(skip[s[i]]) != 'undefined')continue;
				ns.push(s[i]);
			}
			return ns;			
		},
		returnlen: function( a )
		{
			if (typeof(a.length) != 'undefined'  
				&& typeof(a.length) == 'function') 
			{
				return a.length;
			}
			if (typeof(a) != 'object') return 0;
			
			var c=0;
			for (var i in a )
			{
				if ( typeof(a[i]) == 'function') continue;
				c++;
			}
			return c;
		},
		/**
			creates and saves hidden field names
			1. see if hidden field exists; take it's name
			2. see if option formfield is set; take this name
			3. use gutter id, replace slider_ if present
		**/
		create_formobjects: function()
		{
			var g = this.get('gutter');
			var o_gutter = $('#' + g);
			var c =  o_gutter.children('input');
			if (c.length == 0) 
			{
				var h = this.get('formfield');
				var s = h == undefined ? g.replace(/slider_/,'') : h;
				$('<input type="hidden" name="'+s+'" value="">').appendTo(o_gutter);
			}
			else
			{
				var s = c[0].name;
			}

			this._setData('formfield', s );
		},
		/**
			create all divs nessesary for the slider,
			e.g. the gutter, the ball and display
			naming_convention:
			gutter: xlslider_gutter_<name>
			ball: xlslider_ball_<name>
			display: xlslider_display_<name>
		**/
		create_divs: function ()
		{
			var c = this.element.children();
			if ( c.length > 0 ) return;
			
			var n = this.get('name');
			
			$('<div id="xlslider_gutterwrapper_'+n+'" class="xlslider_gutterwrapper"></div>').appendTo(this.element);
			var base = $('#xlslider_gutterwrapper_'+n);
			
			if (this.get('display_first'))
			{
				$('<div id="xlslider_display_'+n+'" class="xlslider_display"></div>').appendTo(base);
			}
			
			$('<div id="xlslider_gutter_'+n+'" class="xlslider_gutter"><div id="xlslider_gutter_disabled_'+n+'"></div></div>').appendTo(base);


			
			$('<div id="xlslider_ball_'+n+'" class="xlslider_ball"></div>').appendTo($("#xlslider_gutter_disabled_"+n)) ;
						
			if (this.get('display_first') === false)
			{
				$('<div id="xlslider_display_'+n+'" class="xlslider_display"></div>').appendTo(base);
			}			

			$('<div id="xlslider_price_'+n+'" class="xlslider_price"></div>').appendTo(this.element);
			
			
			this._setData('gutter','xlslider_gutter_'+n);
			this._setData('gutter_disabled','xlslider_gutter_disabled_'+n);
			this._setData('ball','xlslider_ball_'+n);
			this._setData('display','xlslider_display_'+n);
			this._setData('pricedisplay','xlslider_price_'+n);
			
		},
		/**
			calculate even spacing for the virtual
			grid the values snap to
		**/
		calc_grid: function( _vals)
		{
			if ( typeof(_vals) == undefined) return;
			if ( _vals == null ) return;
			if (_vals.length < 1) return;
			
			var l = _vals.length-1;

			// get variables
			var o_gutter = $('#' + this.get('gutter'));
			var o_ball = $('#' + this.get('ball'))
			
			var mx = (o_gutter.width() - o_ball.width());
			var s = Math.floor (parseInt(mx)/l);
			
			if (mx % s == 0) // to close to border
			{
				l = _vals.length;
				s = s + Math.floor(s/(o_gutter.width() - (l*s)));
			}


			var r = [];
			snap_val = {};					
			for (var i = 0; i < l; i++) {
				r.push( (i+1)* s);
			}

			for (var i = 0; i < r.length; i++) 
			{
				if (i == 0 ) snap_val[0] = _vals[i];
				snap_val[r[i]] = _vals[i+1];
			}
			this._setData('snap_val', snap_val);
			return r;
		},		
		/**
			draws gridlines under the gutter div
		**/
		draw_grid: function()
		{
			// get variables
			var grid = this.get('grid');
			var snap_val = this.get('snap_val');
			var gutter = this.get('gutter');
			
			// update floater;
			$('#' + this.get('display')).html( snap_val[0] );
			
			// display grid lines
			
			var w = (grid.length * grid[0]) + (grid[0]*2);
			var d ='<div id="grid_'+ gutter +'" ';
			 	d = d + 'style="width:'+w+'px"></div>'; 
			 	
			$( d ).appendTo($('#' + gutter ).parent());

			var l = '';

			
			for (var i in snap_val)
			{
				l = l + '<div id="'+ gutter +'_'+ snap_val[i]+'" style=" width:'+ grid[0] +'px;" class="xlslider_gridlines">&nbsp;</div>';
			}
			$("#grid_" + gutter ).html( l );

		},
		/**
			when drag hits a snap-point, update values
			of the display div and hidden formfields
			and colors the range
		**/		
		handledrag: function(ev, ui , calledbyset, calllimit)
		{
			// update tooltip with nearest grid-value
			var left = Math.round(ui.position.left) ;					
			var sv = this.find_nearest( left );
			var o_display = $('#' + this.get('display'));

			var ll = this.get('lowerbound');
			if (typeof(ll) == "undefined") ll = 0;
			
			// update display
			// see for onvalchange callback
			if ( typeof(sv) !== undefined && sv != null && sv > -1)
			{
				o_display.html(sv);
				$("input[name='"+ this.get('formfield')+"']").attr('value',sv);
				
				if (sv != this.get('lastval'))
				{
					if (typeof(calledbyset) == 'undefined' || calledbyset==null)
					{
						//this.docallback('onvalchange', sv);
						if (typeof(calllimit) == 'undefined' ) {
							this.check_threshold(sv);
						}
					}
					else{
						this.docallback('onvalchange', sv);
					}
					
					this._setData('lastval',sv);	
					if (sv >= ll) {
						this.drawprice( sv );
					}
					
				}
				
				// color line
				if (this.get('colorrange')) this.color_range(sv);
			}
			
			// set display left position
			if (!this._getData('display_static')) {
				o_display.css({left:  (ui.position.left - 12)});
			}
			
			
			if (this.get('disable_seen'))  {
				this.setdisabled({before:true,raw: left});
			}
			
			if(this.get('threshold_alwayscall')) {
				if (sv >= ll) 
				this.docallback( 'threshold_alwayscall' ,sv );
			}
			
		}
		,checklowerbound: function()
		{
			var ll = this.get('lowerbound');
			var l = this.get('lastval');	
			if (l < ll) {
				this.setslider(ll, true);
			}

		}
		
		,drawprice: function ( val )
		{
			if (typeof(val) == 'undefined') val = 0;
			if (val == true) val = this.get_current();
			var pr = this.get('price');
			var price = pr[ this.get_indexbyval(val) ];
			
			if ( typeof(price) == 'undefined' ) 
			{
				if (typeof(console) == 'object') {
					console.log(this.get('name'));
					console.log('- PRICE ('+price+') UNDEF: ' + val);
					console.log('- '+pr);
					console.log('- ', this.get('snap') );
					console.log('- ', this.get('snap_val') );
				}
				return;
			}			
			
			var sx = this.get('price_sufx');
			$('#' + this.get('pricedisplay')).html( '&euro; ' + price.toFixed(2) + sx);
			
		},
		get_current: function()
		{
			return $("input[name='"+ this.get('formfield')+"']").attr('value');
		},
		docallback: function(_name, args)
		{
			var upd = this.get(_name);
			if (upd !== null && typeof(upd) == 'function')
			{
				if (typeof(args) != "undefined") upd(args);
				else upd();
			}
		},
		color_range: function ( a )
		{
			var snap_val = this.get('snap_val');
			var gutter = this.get('gutter');

			
			for ( var i in snap_val)
			{
				var o = gutter+'_'+ snap_val[i];
				if ( parseInt(a) < parseInt(snap_val[i]) )
				{
					$('#'+o).css({backgroundColor: 'transparent'});
				}
				else 
				{
					$('#'+o).css({backgroundColor: 'orange'});

				}
			}
		},
		/**
			find nearest position of pixelposition
			in the (display) value array
		**/
		find_nearest: function ( _val )
		{
			var snap_val = this.get('snap_val');
			var val = parseInt( _val );
			var r = snap_val[0];
			for ( var i in snap_val)
			{
				if ( val > parseInt( i ) ) r = snap_val[i];
			}
			return r;				
		},
		/**
			get the pixelvalue for the left of the slider ball
			by querying the snap value given
		**/
		get_pixelbyval: function ( _val )
		{
			var snap_val = this.get('snap_val');
			for ( var i in snap_val)
			{
				if ( snap_val[i] == _val ) return parseInt(i)+1;
			}
			return 0;
		},
		get_indexbyval: function( _val )
		{
			var snap = this.get('snap');
			for ( var i in snap)
			{
				if ( snap[i] == _val ) return i;
			}
			return 0;		
		},
		
		/**
			sets the slider to given value position
		**/
		setslider: function( _v , callupdate)
		{
			var b = this.get('ball');
			var w = parseInt($('#' + this.get('ball')).width()) / 4;
			var n = this.get_pixelbyval( _v )+w;
			var ui = { position: {left : n } };
			$('#' + this.get('ball')).css({'left': n });
			
			var P = typeof(callupdate) == 'undefined' ? null : true;
			this.handledrag( this, ui , P );

			return true;
		}
		,setrecalibrated: function( _v , callupdate, _vps)
		{
			var t = this.get('threshold');
			var cv = 0;
			for(var i in t) {
				if (t[i][1] == _vps) cv = i;
			}
			if (cv > 0 ) this.recalibrate( cv, true, true);
			this.setslider( _v, callupdate);
		}
		,setdisabled: function (ob )
		{
			if (typeof(ob.before) == 'undefined') ob['before'] = true;
			if (typeof(ob.after) != 'undefined') ob['before'] = false;
			if (typeof(ob.raw) != 'undefined')
			{
				var n =  ob.raw ;
			}
			else
			{	
				var n = this.get_pixelbyval( ob.val );
			}
			
			var g = this.get('gutter_disabled');
			var b = parseInt($('#'+this.get('ball')).css('width'))/2;
			
			$('#'+g).addClass('xlslider_gutter_disabled');
			$('#'+g).css({width: (n+b)+'px'});
			
		},
		checklowerlimit: function( )
		{
			var limit = this.get('lowerlimit');
			if (limit == null || limit == 0) return false;
			
			var s = this.get('snap');
			var p = this.get('price');
			// reset grid and remove values < lower_limit
			// snap, price
			
			this._setData('old_snap', s);
			this._setData('old_price', p);
			
			var news = new Array();
			var newp = new Array();

			for (var i =0; i < s.length; i++ )
			{
				if (s[i] < limit) continue;
				news.push(s[i]);
				newp.push(p[i]);
			}
			
			this._setData('snap', news);
			this._setData('price', newp);
			return true;
		},
		set_lowerlimit: function( val, internal )
		{
			this._setData('lowerlimit', val);
			this.reload(internal);
		},
		check_threshold: function (_v)
		{
			var t = this.get('threshold');
			if (t == null) return;
			
			// only when moving backwards.
			if (this.get('lastval') < _v) 
			{
				var tup = this.get('threshold_up');
				if (tup == null || typeof(tup) != 'function') {
					return;
				}
				
				this.docallback( 'threshold_up' ,_v );
				return;
			}
			
			// if we have already recalibrated for this value don't

			var recal = this.get('recalibrate_value');
			if (recal != null) {
				if ( _v >= recal) return;
			}

			var thresh = _v;
			for ( var i in t )
			{
				if (_v > i) { thresh = i }
				if (_v == i ) { thresh = i; break; }
			}			
			this.docallback(	
				'threshold_callback'
				, [t[thresh],thresh,this.get('formfield'),recal]
			); 
			
			return;
		},
		recalibrate: function( lower , force, drawprice)
		{
			var recal = this.get('recalibrate_value');
			if (recal !== null)
			{
				if (typeof(force) == 'undefined' && lower >= recal) return;
			}
			
			var s = this.get('snap');
			var r = this.get('rawdata');
			
			this._setData('recalibrate_value', lower);
			var v = 0;
			var newprices = [];
			
			for(var i=0; i<s.length;i++)
			{
				if (s[i] < lower) {
					newprices[i] = r[ lower - s[i]];
					continue;
				}
				if (s[i] == lower) {
					newprices[i] = 0;
					continue;
				}
				newprices[i] = r[s[i] - lower];
			}
			this._setData('price',newprices);
			
			if (typeof(drawprice) != 'undefined' && drawprice !=null) {
				this.drawprice(drawprice);
			}
			else {
				this.drawprice(lower);
			}
			return true;
		}
		
		
		
	};
	/**
		Sets up the widget
	**/
	$.xls = $.xls || {}; // create the namespace
	$.widget("xls.xlslider", xlslider);
	$.xls.xlslider.defaults = {
		name: 'xlslider'
		,selector: '.slider'
		,dragstopcall:null
		,parentslider: null
		,setlowerlimit:false
		,childfollowparent:false
		,children:[]		
		,snap: []
		,old_snap: []
		,grid: []
		,price: []
		,old_price: []
		,price_sufx: ''
		,snap_val: {}
		,skipvals: {}
		,gutter: null
		,ball: null
		,display: null
		,pricedisplay: null
		,lastval: 0
		,display_static: false
		,display_first: true
		,colorrange: false
		,disable_seen: true
		,onvalchange: null
		,callbackparam: null
		,lowerlimit:null		
		,threshold: null
		,threshold_alwayscall:false
		,threshold_up: null
		,threshold_callback: null
		,recalibrate_value: null
		,sendinitial:null
		,submitcallback:null
		,lastsubmit:0
	};
	$.xls.xlslider.getter = ["get_current","get"];
})(jQuery);

