/* (C) Innoware 2009
	by Tom Coote 
*/

/*jslint  eqeqeq: true, browser: true */
/*global $, jQuery, JSON, SalaryPicker */

/* NOTE: this script requires the following js libraries 
 * 	- jQuery 	(developed against v1.3.2)
 *	- jQuery ui	(developed against v1.7.2)
 * 	- json2 	(parser by Douglas Crockford)
 */

var jSalaryPicker = function() {
	
	var that = {},
		salaryRanges = undefined,
		pickerWidth = 486,
		perYearMinFigure = 5000,
		perYearMaxFigure = 65000,
		perHourMinFigure = 3,
		perHourMaxFigure = 15,
		currentUI = 'interactiveUI';
	
	function isIE6() {
		return (navigator.userAgent.toLowerCase().indexOf('msie 6') !== -1);
	}
	
	// Show in the UI how many vacancies there are without valid
	// salaries. If there are non of these then remove the words for this.
	function setNumberOfNoneSalaries() {
		if (salaryRanges && salaryRanges.otherSalaries.length > 0) {
			$('span#catchAll span').html(salaryRanges.otherSalaries.length);
		}
		else {
			$('span#catchAll').remove();
		}
	}
	
	// Functions for getting the left and right markers. Can't grab the first and second
	// elements where they are in the DOM because the user is able to drag the first marker
	// past the second which then becomes the second in the UI.
	function getLeftMarker() {
		var marker1 = $('div#rangeSlider div.slider:first'),
			marker2 = $('div#rangeSlider div.slider:last');
			
		if (marker1.position().left < marker2.position().left) {
			return marker1;
		}
		else {
			return marker2;
		}
	}
	function getRightMarker() {
		var marker1 = $('div#rangeSlider div.slider:first'),
			marker2 = $('div#rangeSlider div.slider:last');
			
		if (marker1.position().left >= marker2.position().left) {
			return marker1;
		}
		else {
			return marker2;
		}
	}
	
	// Draw a white area between the two range markers to indicate
	// what range has been selected.
	function whiteOutRangeSelection() {
		var leftMarker = getLeftMarker(),
			rightMarker = getRightMarker();
			
		$('div#whiteBox').css({
			'left': leftMarker.position().left + 7,
			'width': (rightMarker.position().left - leftMarker.position().left)
		});
	}
	
	function initiateDraggableMarkers() {
		$('div#rangeSlider div.slider').draggable({
			'axis': 'x',
			'containment': 'div#salaryPicker',
			'drag': whiteOutRangeSelection,
			'stop': whiteOutRangeSelection,
			'cursor': 'pointer'
		});
	}
	
	// Given the salary to mark, the max salary number available in the picker and
	// the width of the ui picker return the left position of where the marker should go.
	function getRedMarkerLeftPosition(salary, maxFigure, minFigure, uiWidth) {
		var percent = 0, pixels = 0;
			
		// We're not starting from zero in the picker, so this means we need to
		// negate the salary by the starting point to figure out the correct position
		salary = salary - minFigure;
		// If we negate the salary we need to negate the same from max figure
		// so that percentages are still correct
		maxFigure = maxFigure - minFigure;
	
		// What percent out of maxFigure is this?
		// maxFigure is the max figure that the picker can go to in the UI.
		percent = salary / maxFigure * 100;
		
		// What is the percent (from above) of uiWidth.
		// uiWidth is used because that is the width of the picker
		pixels = uiWidth / 100 * percent;
		
		// Want to keep the red lines a little bit tucked in at each end
		if (pixels > (uiWidth - 2)) { 
			pixels = (uiWidth - 2);
		}
		if (pixels < 4) {
			pixels = 4;
		}
		
		return pixels - 1;
    }

    // Find the highest salary of the given type.
    function getHighestSalary(salaryType) {
        var salary = 0;

        for (var s in salaryRanges[salaryType]) {
            if (salaryRanges[salaryType].hasOwnProperty(s)) {
                var thisSalary = parseFloat(salaryRanges[salaryType][s].salaryFrom);

                if (thisSalary > salary) {
                    salary = thisSalary;
                }
            }
        }

        return salary;
    }
	

	// Given the marker left position, the max salary number available in the picker and
	// the width of the ui picker return the salary figure that has been marked.
	function getSalaryFigureFromLeftPosition(leftPosition, maxFigure, minFigure, uiWidth, salaryType) {
	    // What percent out of the uiWidth is this?
	    // uiWidth is used because that is the width of the picker
	    var percent = leftPosition / uiWidth * 100;

	    // Finally what percent is this of the maxFigure taking into account
	    // the positive minFigure value.
	    var salary = ((maxFigure - minFigure) / 100 * percent) + minFigure;

	    // Modify the salary if it falls at the ends of the picker limits so
	    // that is includes all marked salaries as they show on the picker.
	    if (salary >= maxFigure) {
	        salary = getHighestSalary(salaryType);
	    }
	    else if (salary <= minFigure) {
	        salary = 0;
	    }

	    return salary;
	}

	// Put all the red lines on the picker to indicate where a salary is.
	// Will position annual salaries if given the "perYearSalaries" type
	// and hourly wages if given the "perHourSalaries" type.
	function setSalaryMarkers(salaryType) {
		$('div.redMarker').remove();
		
		if (!salaryRanges) { return false; }
		
		for (var s in salaryRanges[salaryType]) {
			if (salaryRanges[salaryType].hasOwnProperty(s)) {
				var salary = salaryRanges[salaryType][s].salaryTo - salaryRanges[salaryType][s].salaryFrom,
					redLine = $('<div />'),
					maxFigure = (salaryType === 'perYearSalaries') ? perYearMaxFigure  : perHourMaxFigure,
					minFigure = (salaryType === 'perYearSalaries') ? perYearMinFigure : perHourMinFigure;
					
				if (salary === 0) {
					salary = salaryRanges[salaryType][s].salaryTo;
				}
				else {
					salary = salaryRanges[salaryType][s].salaryFrom + (salary / 2);
				}
				
				$(redLine).addClass('redMarker').css({
					'left': getRedMarkerLeftPosition(salary, maxFigure, minFigure, pickerWidth),
					'opacity': 0.2
				});
				$('div#salaryPicker div#rangeSlider div#whiteBox').after(redLine);
			}
		}
	}
	
	// Show a loading symbol so that loading can be indicated 
	// between tab press's and on initial load.
	function showLoading() {
		if ($('div#salaryUILoading').length < 1) {
			var loadingElement = $('<div />');
			
			$(loadingElement).attr('id', 'salaryUILoading').
				css('opacity', 0.5).
				html('<div>loading...</div>');
			$('div#salaryPicker div#rangeSlider').append(loadingElement);
		}
		else {
			$('div#salaryUILoading').show();
		}
	}
	function hideLoading() {
		$('div#salaryUILoading').hide();
	}
	
	// Set up picker for the selection of annual salaries.
	function selectPerYear() {
		var lowestK = 10,
			tab = this;
		
		showLoading();
		// Annoyingly we must set a really small timeout so that the loading message appears.
		window.setTimeout(function() {
			setSalaryMarkers('perYearSalaries');
			
			// Choose a starting position for the markers to sit, just a guess!
			$('div#rangeSlider div.slider:first').css('left', 75).show();
			$('div#rangeSlider div.slider:last').css('left', 155).show();
			whiteOutRangeSelection();
			
			// Show the range of numbers in the UI
			$('div#salaryPicker ul.rangeValues li').each(function() {
			$(this).html("&#163;" + lowestK + 'k');
				lowestK += 10;
			});
			
			$('div#salaryPicker ul.tabs li').removeClass('selected');
			$(tab).addClass('selected');
			
			hideLoading();
		}, 10);
		
		return false;
	}
	
	// Set up picker for the selection of hourly wages.
	function selectPerHour() {
	    var lowestUnit = perHourMinFigure + 1,
			tab = this;
		
		showLoading();
		// Annoyingly we must set a really small timeout so that the loading message appears.
		window.setTimeout(function() {
			setSalaryMarkers('perHourSalaries');
			
			// Choose a starting position for the markers to sit, just a guess!
			$('div#rangeSlider div.slider:first').css('left', 70).show();
			$('div#rangeSlider div.slider:last').css('left', 190).show();
			whiteOutRangeSelection();
			
			// Show the range of numbers in the UI
			$('div#salaryPicker ul.rangeValues li').each(function() {
			$(this).html("&#163;" + lowestUnit + 'ph');
				lowestUnit += 2;
			});
		
			$('div#salaryPicker ul.tabs li').removeClass('selected');
			$(tab).addClass('selected');
			
			hideLoading();
		}, 10);
		
		return false;
	}
	
	// Toggle the UI between the cool picker and the rubbish form
	function toggleUI() {
		if (currentUI === 'degradedUI') {
			$('span#degradedUI').hide();
			$('span#interactiveUI').show();
			currentUI = 'interactiveUI';
		}
		else {
			$('span#interactiveUI').hide();
			$('span#degradedUI').show();
			currentUI = 'degradedUI';
		}
		
		return false;
	}
	
	// Only allow decimal numbers. To be used on the keypress
	// events of input boxes.
	function decimalsOnly(evt) {
		var k = parseInt(evt.keyCode || evt.charCode, 10);

		if (k === 46 || k === 8 || k === 9 || k === 37 || k === 39) {
			return true;
		}
		
		if (k < 48 || k > 57) {
			evt.preventDefault();
			evt.stopPropagation();
			return false;
		}
		
		return true;
	}
	
	
	that.initSalaryPicker = function()  {
		currentUI = 'interactiveUI';
		
		// First off get the salary range information from the server
		WelcomeVSControl.GetSalaryRanges(function(data) {
			if (data && data.value) {
				salaryRanges = JSON.parse(data.value);
				
				setNumberOfNoneSalaries();
				selectPerYear.apply($('div#salaryPicker ul.tabs li:last').get(0));
				initiateDraggableMarkers();
			}
			
			// Add UI events
			$('div#salaryPicker ul.tabs li:first').click(selectPerHour);
			$('div#salaryPicker ul.tabs li:last').click(selectPerYear);
			$('div#salaryPicker a.uiChanger').click(toggleUI);
			$('div#salaryPicker input#salaryFrom').keypress(decimalsOnly);
			$('div#salaryPicker input#salaryTo').keypress(decimalsOnly);
		});
		
		if (isIE6()) {
			toggleUI.apply($('div#salaryPicker a.uiChanger:first').get(0));
		}
		else {
			$('span#interactiveUI').show();
		}
	};
	
	// Return an array of vacancy ID's that have been selected by the picker.
	// If catchAll is true then return ID's of the vacancies that don't have a salary
	// else get those that were picked from the UI.
	that.getSelectedVacancyIDs = function(catchAll) {
		var chosenIDs = [], s = undefined;
		
		if (!salaryRanges) { return []; }
		
		if (catchAll) {
			// all vacancies that never gave a valid salary range
			for (s in salaryRanges.otherSalaries) {
				if (salaryRanges.otherSalaries.hasOwnProperty(s)) {
					chosenIDs.push(salaryRanges.otherSalaries[s].vacancyID);
				}
			}
		}
		else {
			var salaryType = undefined,
				rangeElement = undefined,
				bottomRange = 0,
				topRange = 0,
				maxFigure = 0,
				minFigure = 0;
				
			if (currentUI === 'interactiveUI') {
				// Get the salary type and range selection from the cool interactive picker UI
				salaryType = $('div#salaryPicker ul.tabs li:first').hasClass('selected') ? 'perHourSalaries' : 'perYearSalaries';
				rangeElement = $('div#salaryPicker div#rangeSlider div#whiteBox');
				bottomRange = rangeElement.position().left;
				topRange = bottomRange + rangeElement.width();
				maxFigure = (salaryType === 'perYearSalaries') ? perYearMaxFigure  : perHourMaxFigure;
				minFigure = (salaryType === 'perYearSalaries') ? perYearMinFigure : perHourMinFigure;
			}
			else {
				// Get the salary type and range from the degraded form UI
				salaryType = $('div#salaryPicker input[name=salaryType]:checked').attr('id');
				maxFigure = (salaryType === 'perYearSalaries') ? perYearMaxFigure  : perHourMaxFigure;
				minFigure = (salaryType === 'perYearSalaries') ? perYearMinFigure : perHourMinFigure;
				
				// Need to check that numbers entered for a salary are OK
				var salaryFrom = parseFloat($('div#salaryPicker input#salaryFrom').val()),
					salaryTo = parseFloat($('div#salaryPicker input#salaryTo').val());
				
				if (!salaryFrom || !salaryTo) {
					alert('The numbers entered for the search do not seem to be valid.\n\nPlease check them and try again.');
					return false;
				}
				
				if (salaryFrom > salaryTo) {
					var temp = salaryFrom;
					salaryFrom = salaryTo;
					salaryTo = temp;
				}
				
				// Create a virtual range as if these numbers where selected using the picker UI
				bottomRange = parseInt(getRedMarkerLeftPosition(salaryFrom, maxFigure, minFigure, pickerWidth), 10);
				topRange = parseInt(getRedMarkerLeftPosition(salaryTo, maxFigure, minFigure, pickerWidth), 10);
			}
				
			// Find all vacancies that are within the range that has been marked out
			// in the picker by the user.
			for (s in salaryRanges[salaryType]) {
				if (salaryRanges[salaryType].hasOwnProperty(s)) {
					var salary = salaryRanges[salaryType][s].salaryTo - salaryRanges[salaryType][s].salaryFrom,
						leftPosition = 0;
						
					if (salary === 0) {
						salary = salaryRanges[salaryType][s].salaryTo;
					}
					else {
						salary = salaryRanges[salaryType][s].salaryFrom + (salary / 2);
					}
					
					// The position of the marker for this salary needs to be inside the range selected in the ui.
					leftPosition = getRedMarkerLeftPosition(salary, maxFigure, minFigure, pickerWidth);
					
					if (leftPosition >= bottomRange && leftPosition <= topRange) {
						chosenIDs.push(salaryRanges[salaryType][s].vacancyID);
					}
				}
			}
		}
	
		return chosenIDs;
	};
	
	// Return the selected range from the UI as an array
	// i.e. [20000, 30000, 'perHourSalaries']
	// The last item in the array is the key that says which salary
	// type array is used. If catchAll is true then it will use the getSelectedVacancyIDs
	// funciton instead as these don't have salaries.
	that.getSelectedSalaryRange = function(catchAll) {
		var salaryType = undefined;
		
		if (!salaryRanges) { return []; }
		
		if (catchAll) {
			// If catch all then we can't give a range because they don't have ranges,
			// so all we can do is return the ID's.
			return that.getSelectedVacancyIDs(true);
		}
		else if (currentUI === 'interactiveUI') {
			// Get the salary type and range selection from the cool interactive picker UI
			salaryType = $('div#salaryPicker ul.tabs li:first').hasClass('selected') ? 'perHourSalaries' : 'perYearSalaries';
			var rangeElement = $('div#salaryPicker div#rangeSlider div#whiteBox'),
				bottomRange = rangeElement.position().left,
				topRange = bottomRange + rangeElement.width(),
				maxFigure = (salaryType === 'perYearSalaries') ? perYearMaxFigure  : perHourMaxFigure,
				minFigure = (salaryType === 'perYearSalaries') ? perYearMinFigure : perHourMinFigure;
				
				// Need to convert the ranges in pixels to actual salaries and return those
			return [getSalaryFigureFromLeftPosition(bottomRange, maxFigure, minFigure, pickerWidth, salaryType),
						getSalaryFigureFromLeftPosition(topRange, maxFigure, minFigure, pickerWidth, salaryType),
						salaryType];
		}
		else {
			// Get the salary type and range from the degraded form UI
			salaryType = $('div#salaryPicker input[name=salaryType]:checked').attr('id');
			var salaryTo = parseFloat($('div#salaryPicker input#salaryTo').val()),
				salaryFrom = parseFloat($('div#salaryPicker input#salaryFrom').val());
				
			// Need to check that numbers entered for a salary are OK
			if (!salaryFrom || !salaryTo) {
				alert('The numbers entered for the search do not seem to be valid.\n\nPlease check them and try again.');
				return false;
			}
			
			if (salaryFrom > salaryTo) {
				var temp = salaryFrom;
				salaryFrom = salaryTo;
				salaryTo = temp;
			}

			return [salaryFrom, salaryTo, salaryType];				
		}
	};
	
	return that;
}();