﻿//function used to create all of the sliders
function RenderSliders() {
	$("div.slider-container, div.slider").each(function()
		{
			RenderSlider(this);
		});
}
		

//function used to create sliders in supplied container
function RenderChildSliders(container) {
	var sliders = container.find("div.slider-container, div.slider");
	sliders.each(function()
		{
			RenderSlider(this);
		});
}

//function used to create a slider
function RenderSlider(sliderElement) {
			//Get our slider container vars.
			var sliderContainer = $(sliderElement);
			var uiSliderContainer = sliderContainer.children("div.ui-slider-container");	//the main slider container
			var sliderTrack = uiSliderContainer.children("div.ui-slider-track");			//the actual area the handles move along
			var sliderHandles = sliderTrack.children("div.ui-slider-handle");				//handle(s) used to alter the selected values on the slider
			var sliderRange = sliderTrack.children("div.ui-slider-range");					//range is the highlighted area showing the area covered by the slider							
			var sliderSummary = uiSliderContainer.children('label.ui-slider-summary');		//label showing the value currently selected by the slider
			var sliderLowerLabel = uiSliderContainer.children('label.limit-low');			//label showing the lower bound of the slider
			var sliderUpperLabel = uiSliderContainer.children('label.limit-high');			//label showing the upper bound of the slider
			var handleCount = sliderHandles.length;											//indicates whether this is a single or dual slider
			var dataContainer = sliderContainer.children("select");							//select list(s) used to create this slider
			var upperRangeLimit = sliderContainer.find('input#UPPER_RANGE_LIMIT').val();		//the left param of the slider, used by the summary control to see if the upper handle has been moved or not
			var summaryDefaultText = sliderContainer.find('input#DUAL_SLIDER_SUMMARY_DEFAULT_TEXT').val();	//the text used by a dual slider's summary if neither handle has been moved
			var summaryPrefix = sliderContainer.find('input#DUAL_SLIDER_SUMMARY_PREFIX').val();			//the text used by a dual slider's summary if only the upper handle has been moved e.g. 'Up to £10,000'
			var summarySuffix = sliderContainer.find('input#DUAL_SLIDER_SUMMARY_SUFFIX').val();			//the text used by a dual slider's summary if only the lower handle has been moved e.g. '£10,000 and above'
			var summarySeparator = sliderContainer.find('input#DUAL_SLIDER_SUMMARY_SEPARATOR').val();		//the text used by a dual slider's summary if both handles have been moved e.g. '£10,000 to £20,000'
			var useRange = (sliderContainer.find('input#USE_RANGE').val() == 'false') ? false : true;		//value used to signify if the dual slider should use the range param			
			var dataItems = new Array();  													//values as an array of jquery objects.
			
			//If the options in each of the containers (two in a range) change dynamically depending on what is specified in one and the other, 
			//then the dataItems collection needs to be built taking this into consideration.
			if (sliderContainer.hasClass('dynamic')) 
			{
			    //Loop through our data containers and get a distinct list of values.
			    dataContainer.each(function(iDataContainer) {
			        var container = $(this);
			        //Loop though each of our available data items in our data container.
			        container.children().each(function(iDataItem) {
			            //Create a string key of this option.
			            var dataItemKey = this.value + ":" + this.text;

			            //We only need to match duplicate elements on our dataContainer(s) greater than 1.
			            switch (iDataContainer) {
			                case 0: //This is a single handle slider.
			                    if (((this.value != "") && (handleCount == 2)) || (handleCount == 1))
			                    {
			                        dataItems.push({ key: dataItemKey, item: this, ordinal: [iDataItem, null] });
			                    }
			                    break;
			                case 1: //This is a double handle slider.			                    
			                    if (containsKey(dataItemKey, dataItems) < 0) 
			                    {
			                        if (((this.value != "") && (handleCount == 2)) || (handleCount == 1)) dataItems.push({ key: dataItemKey, item: this, ordinal: [iDataItem + 1, null] });
			                    }
			                    else
			                    {
			                        dataItems[containsKey(dataItemKey, dataItems)].ordinal[iDataContainer] = iDataItem;
			                    }
			                    break;
			            }
			        });			        
			    });			
			}
			else {
			    //Loop though each of our available data items in our data container.
			    $(dataContainer[0]).children().each(function(iDataItem) {
			        //Create a string key of this option.
			        var dataItemKey = this.value + ":" + this.text;

			        //we dont want a 0 value as this is covered by the 'any' option
			        if (sliderContainer.value != '0') {
			            dataItems.push({ key: dataItemKey, item: this, ordinal: [iDataItem, null] });
			        }
			    });
			}
			
			//if this is a single slider we need to operate this as a FIFO queue and not a LIFO stack.
			//we need to shift out element 0 and re-add it to the end of the queue, this should force the 
			//inital state of the handle to begin at the right hand side
			//If this is a dual slider we need to duplicate the 'any' option into the end of the array so we
			//have two otherwise it will be impossible to deselect the lower handle
			if(handleCount == 1) {
				var val = dataItems.shift();	//shift the first item out of the array (the 'any' option)
				dataItems.push(val);			//push it into the end
				
				//configure the upper and lower labels, this is a single slider so only 1 datacontainer
				//to worry about, so we can just take the upper and lower values
				sliderUpperLabel.html(dataContainer.find('option:first').text());
				sliderLowerLabel.html(dataContainer.find('option:first').next('option').text());
			}
			else {
			    if (sliderContainer.hasClass('dynamic') == false) 
			    {
			        var val = dataItems[0]; 		//copy first item out of the array (the 'any' option)
				    dataItems.push(val);			//push it into the end
				}				
				sliderUpperLabel.html($(dataContainer[1]).find('option:first').text());
				sliderLowerLabel.html($(dataContainer[0]).find('option:first').next('option').text());
			}
						
			//The number of steps is equal to the data length - 1.
			var dataLength = (dataItems.length - 1);
			//Hide our select element.
			dataContainer.hide();
			//Enable and show our slider bar.
			sliderTrack.slider(
			{
			    //Set the number of steps to equal the options in the select element.
			    steps: dataLength,
			    min: 0,
			    max: dataLength,
			    range: useRange,
			    //Feedback to the user the output value of the slider.
			    slide: function(e, ui) {
			        ui.handle.children("div.value").text(dataItems[ui.value].item.text);
			        if ((handleCount == 1)) {
			            sliderRange.width(ui.handle.position().left + (ui.handle.width() / 2));
			            sliderSummary.text(dataItems[ui.value].item.text);
			        }
			        else //Handle the range for multiple values.
			        {
			            var handleIndex = (ui.handle.hasClass('high')) ? 1 : 0;
			            var lowerHandle = sliderHandles.eq(0);
			            var upperHandle = sliderHandles.eq(1);

			            //ok we need to do some extra processing here to stop non-range based sliders from breaking
			            //it should be possible for non range based sliders to select the same value, however they
			            //shouldn't both be able to select the upper or lower limits and they also shouldn't be able
			            //to cross over each other or everything will go west!
			            if (!useRange) {
			                if (handleIndex == 1) {		//upper handle slide
			                    if (ui.value == 0) {		//if upper handle has been set to 0, reset it to 1
			                        sliderTrack.slider("moveTo", 1, 1);
			                    }
			                    else {
			                        var lowerHandlePosition = $(this).slider('value', 0)
			                        if (ui.value < lowerHandlePosition) {	//if upper handle is below lower handle reset to same value
			                            sliderTrack.slider("moveTo", lowerHandlePosition, 1);
			                        }
			                    }
			                }
			                else {				//lower handle slide
			                    if (ui.value == dataLength) {	//if lower handle is at the upper limit move it back one
			                        sliderTrack.slider("moveTo", dataLength - 1, 0);
			                    }
			                    else {
			                        var upperHandlePosition = $(this).slider('value', 1)
			                        if (ui.value > upperHandlePosition) {		//if the lower handle is above the upper one reset to same value
			                            sliderTrack.slider("moveTo", upperHandlePosition, 0);
			                        }
			                    }
			                }
			            }

			            if (lowerHandle.position()) {
			                // ok we need to detect if the lower slider is still at any and is so change to text to read 'Up To {0}'
			                if (upperHandle.position().left == upperRangeLimit && lowerHandle.position().left == 0) {
			                    sliderSummary.text(summaryDefaultText);
			                }
			                else if (lowerHandle.position().left == 0) {
			                    var text = summaryPrefix + upperHandle.text();
			                    sliderSummary.text(text);
			                }
			                else if (upperHandle.position().left == upperRangeLimit) {
			                    var text = lowerHandle.text() + summarySuffix;
			                    sliderSummary.text(text);
			                }
			                else if (upperHandle.position().left == lowerHandle.position().left) {
			                    var text = lowerHandle.text();
			                    sliderSummary.text(text);
			                }
			                else {
			                    var text = lowerHandle.text() + summarySeparator + upperHandle.text();
			                    sliderSummary.text(text);
			                }
			            }

			            //Set our range width to display our active area.
			            try {
			                sliderRange.width((upperHandle.position().left + (ui.handle.width() / 2)) - 
			                (lowerHandle.position().left + (ui.handle.width() / 2))).css("left", lowerHandle.position().left + (ui.handle.width() / 2));
			            }
			            catch (ex) { }
			        }
			    },
			    //When the slider has changed update our select element to match this value.
			    change: function(e, ui) {
			        var handleIndex = (ui.handle.hasClass('low')) ? 0 : 1;

			        //we need to handle the single and dual sliders separatly due to the combined dataitems array
			        if (handleCount == 1) {
			            dataContainer.eq(handleIndex)[0].selectedIndex = dataItems[ui.value].ordinal[handleIndex];
			            dataContainer.eq(0).trigger("change");
			        }
			        else {
			            if (handleIndex == 0) {
			                dataContainer.eq(0)[0].selectedIndex = dataItems[ui.value].ordinal[0];
			                dataContainer.eq(0).trigger("change");
			            }
			            else {
			                if (useRange) {
			                    if (sliderContainer.hasClass('dynamic')) 
			                    {
                                    //As the options are dynamic, the list contained in dataItems will not provide the correct index required for selection.
                                    //We therefore use the index in the actual select list (dataContainer.eq(1)[0]) that corresponds to the required value (ui.value).
                                    for (var x = 0; x < dataContainer.eq(1)[0].options.length; x++)
                                    {
                                        if (dataContainer.eq(1)[0].options[x].value == dataItems[ui.value].item.value)
                                        {
                                            dataContainer.eq(1)[0].selectedIndex = x;
                                            break;
                                        }
                                    }                                        
			                    } 
			                    else 
			                    { 
			                        //if this is a dual slider with the range param set we need to knock the selected
			                        //index back by one to account for the staggered select values.			                
			                        dataContainer.eq(1)[0].selectedIndex = (dataItems[ui.value].ordinal[0] - 1);
			                    }			                    
			                } 
			                else
			                {
		                        dataContainer.eq(1)[0].selectedIndex = dataItems[ui.value].ordinal[0]; 			                    
			                }
			                dataContainer.eq(1).trigger("change");
			            }
			        }
			    }
			}).show();

			//Initialise our slider handles to our selected dataItem values.
			//but make sure to do the upper handle first if it exists as otherwise it'll screw up
			//the lower handle cos of the range issue!
			if(dataContainer[1]) {
				var dc = dataContainer[1];
				try
				{
				    if (sliderContainer.hasClass('dynamic')) 
				    {
					    var dataItemKey = dc.options[dc.selectedIndex].value + ":" + dc.options[dc.selectedIndex].text;
					    var index = containsKey(dataItemKey, dataItems);
					    if (index <= 0) index = dataItems.length;
					    sliderTrack.slider("moveTo",index, 1);
				    }
				    else
				    {
					    //move the upper handle to its position, if its position is 0 then it is unselected
					    //and must be moved to the upper range limit
					    var dataItemKey = dc.options[dc.selectedIndex].value + ":" + dc.options[dc.selectedIndex].text;
					    var index = containsKey(dataItemKey, dataItems);
					    if(index == 0) index = dataItems.length;
					    sliderTrack.slider("moveTo",index, 1);
					}
				}
				catch(ex) { }				
			}
			if(dataContainer[0]) {
				var dc = dataContainer[0];
				try
				{
				    var dataItemKey = dc.options[dc.selectedIndex].value + ":" + dc.options[dc.selectedIndex].text;				
				    sliderTrack.slider("moveTo", containsKey(dataItemKey, dataItems), 0);
				}
				catch(ex) {}
            }
}

//function used to return the index of a value within the array passed in
function containsKey(key, array)
{
	for(var i = 0 ; i < array.length ; i++)
	{
		if(array[i].key == key) return i;
	}
	return -1;
}

//function used to destroy all sliders!
function DestroySliders() {
	$("div.slider").each(
		function() {
			var sliderContainer = $(this);
			var uiSliderContainer = sliderContainer.children("div.ui-slider-container");
			var sliderTrack = uiSliderContainer.children("div.ui-slider-track");
			sliderTrack.slider('destroy');
		}
	);
}

//function used to destroy all sliders that are child of the container!
function DestroyChildSliders(container) {
	var sliders = container.find("div.slider");
	sliders.each(
		function() {
			var sliderContainer = $(this);
			var uiSliderContainer = sliderContainer.children("div.ui-slider-container");
			var sliderTrack = uiSliderContainer.children("div.ui-slider-track");
			sliderTrack.slider('destroy');
		}
	);
}

//fucntion used to reset all sliders
function ResetSliders() {
	$("div.slider").each(
		function() {
			ResetSlider($(this));	
		}
	);
}

//function used to reset a slider
function ResetSlider(container) {
	var sliderTrack = container.find("div.ui-slider-track");
	var steps = container.find('option').length;
	
	//we need to handle dual and single sliders differently
	var handleCount = sliderTrack.find("div.ui-slider-handle").length;
	if(handleCount == 1) {
		sliderTrack.slider('moveTo',steps,0);
	}
	else {
		sliderTrack.slider('moveTo',steps-1,1);
		sliderTrack.slider('moveTo',0,0);
	}
}
