/**
 *	ArenaFilters
 *	--------------------------
 */

var ArenaFilters = (function($) {

	var CLASS_ACTIVE = 'active',
		CLASS_DISABLED = 'disabled';

	/**
	 *	Tooltip
	 *	--------------------------
	 */

	var Tooltip = {
		init: function() {
			this.element = $('<div id="tooltip"><p class="content">' + 
				'<strong>Tip!</strong>Tooltip</p><span class="bottom"></span></div>');
			$('body').append(this.element);

			this.tip = '<strong>Tip! </strong>';
			this.content = this.element.find('p.content');
			this.element.bind('mouseout', this.close.bind(this));
		},

		add:function(selector) {
			var self = this;
			$(selector).hover(function(e){
				self.open(this);
			}, function(e){
				self.close(this);
			});
		},

		open:function(origin) {
			if(this.isOpen) {
				return;
			}

			var self = this;
			var offset = $(origin).offset();
			var title = origin._title || origin.getAttribute('title');
			
			if(title && !origin._title) {
				origin._title = title;
				origin.setAttribute('title', '');
			}

			if(title) {
				this.element.css({visibility:'hidden', display:'block'});
				this.content.html(this.tip + title);

				//var availWidth = window.innerWidth || document.documentElement.clientWidth;

                var criteria = $('#criteria');
                
				var w = this.element[0].offsetWidth,
					h = this.element[0].offsetHeight,
					left = offset.left + (origin.offsetWidth/2) - (w/2) - 7,    // jc
					top = offset.top - h - 5;  // jc - 5 to put the tip above graphical slider area
                    //left = criteria.left,
                    //top = criteria.top;
                    
				//left = Math.min(Math.max(left, 10), availWidth - w - 20);

                left = criteria.offset().left + 200;
                top = criteria.offset().top;
                
				this.element.css({visibility:'visible', display:'none'});
				this.element.hide().css({
					left: left, 
					top:  top
				}).fadeIn('fast', function(){
					self.isOpen = true;	
				});
			}
		},

		close:function(origin) {
			if(this.isOpen) {
				var self = this;
				this.element.fadeOut('fast', function(){
					self.isOpen = false;
				});
			}
		}
	}

	/**
	 *	Slider controller
	 *	--------------------------
	 */

	var SliderController = {
		init:function() {
		
			this.progress = $('span#filter-totals span.bar')[0];
			this.button = $('div#filter p.buttons a.button');
			this.range = 900;
			this.minimal = 10;
			this.count = 9;
			this.sliders = [];

			var links = new LinkListener();
			links.register(/slider-/, this.handleDNAClick.bind(this))

			this.dna = $('.dna-filter ul');
			this.template = this.dna.html();
			this.dna.empty();

            this.percentages_input =
                $('<input type="text" name="slider-percentages" style="display:none" />')
                    .appendTo($('form').get(0));
		},

		addSlider:function(slider) {
			this.sliders.push(slider);
			this.addDNA(slider);
		},

		addDNA: function(slider) {			
			var dna = $(this.template);
			slider.setDNA(dna);
			this.dna.append(dna);
		},

		handleDNAClick: function(link, rel) {
			var type = /slider-([^ ]+)/.exec(rel)[1];

			var $link = $(link);
			var node = $link.prevAll('input');
			if(!node.length) {
				node = $link.closest('li');
			}
			
			var slider = node.data('slider');
			
			switch (type) {
				case 'remove':
					slider.setRelativeValue(0);
					return true;
                    break;
				case 'lock':
					slider.setEnabled(!slider.enabled);
					return true;
                    break;
				case 'resetall':
					this.resetAll();
					return true;
                    break;
				default:
                    break;
			}
		},

		resetAll: function() {
			var slider;
			var i, l = this.sliders.length;
			for(i=0; i<l; i++) {
				slider = this.sliders[i];
				slider.setEnabled(true);
                if (slider.initialInputValue)
                    slider.setRelativeValue(slider.initialInputValue);
                else
                    slider.setRelativeValue(50);
			}
		},

        onchange: function(slider) {
            /* this is called when one of the sliders changes
            
               it takes care of updating all sliders
            */
            if (this.sliders.length < this.count) {
                return;
            };

            var percentage_locked = 0;
            var value_locked = 0;
            var value_total = 0;

            // first we check locked sliders (if any) to determine what
            // percentage is locked, and what is left for the unlocked
            // items
            for (var i=0; i < this.sliders.length; i++) {
                var s = this.sliders[i];
                var value = parseInt(s.value);
                value_total += value;
                if (!s.enabled)  {
                    value_locked += value;
                    percentage_locked += s.percentage;
                };
            };

            // so now we know what percentage is locked, and so we can
            // determine what percentage should be divided amongst the
            // remaining, unlocked items, and since we know what the total
            // (absolute) value is and what part of that is from the locked
            // items, we can also determine the left over value, and what
            // the percentage of each left over slider is
            var percentage_left = 100 - percentage_locked;
            var value_left = value_total - value_locked;

            // value_left is percentage_left % of the total value, now
            // determine the percentage per slider (NOTE: the total value
            // changes when there are locked items, this so that the 
            // _percentage_ for the locked sliders doesn't change when the
            // _value_ of the other sliders changes)
            var total_percentage = percentage_locked;
            var percentage_left_processed = percentage_left;
            var nansliders = [];
            for (var i=0; i < this.sliders.length; i++) {
                var s = this.sliders[i];
                if (!s.enabled) {
                    continue;
                };
                var value = parseInt(s.value);
                if (value_left == 0) {
                    nansliders.push(s);
                    continue;
                };
                var perc = value / value_left * percentage_left;
                percentage_left_processed -= perc;
                s.setPercentage(perc);
                total_percentage += perc;
            };

            // in case one or more sliders are locked, and all the remaining
            // ones are set to 0, we get zero division errors when trying to
            // assign the remaining values, we solve this by just spreading
            // the left-over bit over all unlocked slides (this gives a bit
            // of a flicker, but makes most sense from a mathematical
            // perspective imo)
            for (var i=0; i < nansliders.length; i++) {
                nansliders[i].setPercentage(
                    percentage_left_processed / nansliders.length);
            };

            // make sure the total of all (rounded) percentages is always 100
            this._ensure100();

            // if the total of all values is large enough to post, show
            // submit button
			if (value_total >= this.minimal) {
				if(!this.canPost) this.button.removeClass(CLASS_DISABLED);
				this.canPost = true;
                this.prepareInput();
			} else {
				if(this.canPost) this.button.addClass(CLASS_DISABLED);
				this.canPost = false;
			};
        },

        _ensure100: function() {
            /* if the total percentage is not equal to 100 due to rounding,
               fiddle-fix by adjusting the items with the largest amount of
               rounding difference (so e.g. if the total is 101%, and the
               rounding differences range from say -0.3 to 0.4999, the 0.4999
               value is upped by 1)
            */

            // first sort by rounding difference, ignore disabled (locked)
            // sliders
            var sliders = [];
            var total_rounded = 0;
            var total_desired = 100;
            for (var i=0; i < this.sliders.length; i++) {
                var slider = this.sliders[i];
                if (!slider.enabled) {
                    total_desired -= slider.percentage_rounded;
                    continue;
                };
                sliders.push(
                    [slider, slider.percentage_rounded - slider.percentage]);
                total_rounded += slider.percentage_rounded;
            };

            if (total_rounded == total_desired) {
                return;
            };

            // sort on rounding difference, ascending
            sliders.sort(function (a, b) {
                if (a < b) {
                    return -1;
                } else if (a == b) {
                    return 0;
                };
                return 1;
            });
            while (total_rounded < total_desired) {
                var slider = sliders.pop()[0];
                if (slider.percentage_rounded == 0) {
                    continue;
                };
                total_rounded++;
                slider.percentage_rounded += 1;
                while (!sliders.length && total_rounded < total_desired) {
                    slider.percentage_rounded += 1;
                    total_rounded++;
                };
                slider.dnaValue.html(slider.percentage_rounded + '%');
            };
            while (total_rounded > total_desired) {
                var slider = sliders.shift()[0];
                if (slider.percentage_rounded == 0) {
                    continue;
                };
                total_rounded--;
                slider.percentage_rounded -= 1;
                while (!sliders.length && total_rounded > total_desired) {
                    slider.percentage_rounded -= 1;
                    total_rounded--;
                };
                slider.dnaValue.html(slider.percentage_rounded + '%');
            };
            var ver = 0;
            for (var i=0; i < this.sliders.length; i++) {
                ver += this.sliders[i].percentage_rounded;
            };
        },

        prepareInput: function() {
            /* generate an input with slider values
            
                the value consists of the percentages of the sliders,
                concatenated using dashes ('-')
            */
            var values = [];
            for (var i=0; i < this.sliders.length; i++) {
                values.push(Math.round(this.sliders[i].percentage));
            };
            this.percentages_input.val(values.join('-'));
        }
	}


	/**
	 *	Slider
	 *	--------------------------
	 */

	var CLASS_SLIDER = 'slider',
		CLASS_INDICATOR = 'indicator',
		CLASS_VINDICATOR = 'value',
		CLASS_THUMB = 'thumb';

	function Slider(element, set) {
		this.element = element;
		this.thumb = $('.'+CLASS_THUMB, element);
		this.indicator = $('.'+CLASS_INDICATOR, element);
		this.vindicator = $('.'+CLASS_VINDICATOR, element);
		this.input = $('input', element.parentNode)[0];
		this.color = $(this.input).attr('ga:color');
		this.minValue = set.min || 0;
		this.maxValue = set.max || 100;
		this.increment = set.increment || 1;
		this.snapValues = set.snapValues || [0,25,50,75,100];
		this.snapSensitivity = 4;
		this.range = this.maxValue;
		this.enabled = true;
		
		var $node = $(element);
		$node.bindScoped('mousedown', this.handleClick, this);
		$node.css('background-color', this.color);
		$node.prevAll('label').css('color', this.color);
		this.thumb.css('background-color', this.color);

		if(this.input) {
			this.setRelativeValue(parseInt(this.input.value || "0", 10));
            //this.initialInputValue = this.input.value;  // jc
    		this.initialInputValue = $(this.input).attr('ga:value');
		}

		this.thumb.bind("click", function(e){e.preventDefault();});
		
		var relatedLabel = this.thumb.parents('li').find('label[title]')[0];
		
	/*	this.thumb.hover(
			function(e){ Tooltip.open(relatedLabel); },
			function(e){ Tooltip.close(); }
		)
	*/
		if(this.input) {
			$(this.input).data('slider', this);
			SliderController.addSlider(this);
		}
	}

	Slider.prototype = {
		handleClick:function(e){
			var target = $(e.target), doc = $(document);
			doc.unbind('mousemove', this.handleDrag);
			
			if(target.hasClass(CLASS_THUMB)) {
				this.dragging = true;
				doc.bindScoped('mousemove', this.handleDrag, this);
				doc.bindScoped('mouseup', this.handleRelease, this);
				e.stopPropagation();
				e.preventDefault();
			} else if(target.hasClass(CLASS_INDICATOR)) {
				var left = e.clientX - $(this.element).calculateLeft() - 10;
				this.setAbsoluteValue(left);
			}
		},
		
		handleDrag:function(e) {
			var offset = this.thumb.offset().left + this.thumb[0].offsetWidth/2;
			var dx = e.clientX - offset;
			this.setAbsoluteValue(this.thumb[0].offsetLeft + dx);
			
			e.preventDefault();
		},

		setAbsoluteValue:function(pxValue, cx) {
			var el = this.thumb[0],
				range = this.maxValue - this.minValue,
				w = this.element.offsetWidth - el.offsetWidth, 
				left = Math.min(Math.max(pxValue, 0), w), 
				value = this.minValue + Math.round((left / w) * range);
			
			if(isNaN(value)) {
				value = 0;
			}

			if(value > this.range) {
				value = this.range;
				this.setRelativeValue(value);
				return;
			}
			
			this.value = this.snapToValue(value);
			left = Math.round((this.value / range) * w);
		
			this.input.value = this.value;
			this.thumb[this.dragging? 'css' : 'animate']({
				left: left + 'px'
			});

			if(this.value >= 50) {
				this.element.style.backgroundPosition = (left - 242) + 'px -5px';
			} else {
				this.element.style.backgroundPosition = '50% 5px';
			}
			

			this.vindicator[this.dragging? 'css' : 'animate']({
				width: (left + 5) + 'px'
			});

			SliderController.onchange(this);
		},

		setRelativeValue:function(value) {
			var rel = Math.min(Math.max(value, this.minValue), this.maxValue);
			var w = this.element.offsetWidth - this.thumb[0].offsetWidth;
			var pxValue = Math.ceil(w/(this.maxValue - this.minValue) * rel);
			this.setAbsoluteValue(pxValue);
            this._relative_value = rel;
		},

		snapToValue:function(value) {
			var l = this.snapValues.length,
				sens = this.snapSensitivity;

			for(var i=0; i<l; i++) {
				var snap = this.snapValues[i],
					d = Math.abs(snap - value);

				if(d <= sens && snap <= this.range) {
					return snap;
				}
			}
			return value;
		},

        setPercentage: function(perc) {
            this.percentage = perc;
            var rounded = this.percentage_rounded = Math.round(perc);
            this.dna.width(perc + '%');
            this.dnaValue.html(this.percentage_rounded + '%');
        },

		setEnabled:function(enabled) {
			this.enabled = enabled;
			this.thumb[enabled? 'show':'hide']();
		//	this.indicator.css({ backgroundPosition: enabled? '0 0' : '0 -50px'});

			$(this.element.parentNode).toggleClass('disabled', !enabled);
			this.dna.toggleClass('disabled', !enabled);
		},

		setDNA: function(dna) {
			this.dna = dna;
			this.dnaValue = dna.find('.value');
			
			dna.data('slider', this);
			if(this.color) {
				dna.css('background-color', this.color);
			}
		},

		handleRelease:function(e){
			var doc = $(document);
			doc.unbind('mousemove', this.handleDrag);
			doc.unbind('mouseup', this.handleRelease);
			this.origin = null;
			this.dragging = false;
			e.preventDefault();
		}
	}

	$.registerPlugin('slider', Slider);


	
	/**
	 *	Return
	 *	--------------------------
	 */
	
	return {
		Tooltip: Tooltip,
		SliderController: SliderController,
		Slider: Slider
	}

})(jQuery);

