// The functions in this file handle user input.
// MapToolBar functions, searches, etc.

// The following two function handle the RenderButton() function output.  Basically it allows the clicked button to stay highlighted.
var g_currentlyClickedButton = null;
function input_renderButtonClick(clickedImage) {
	// If there is an image that was clicked then run it through the renderButtonHover as onmouseout
	if (g_currentlyClickedButton) {
		// If the currentlyClickedButton is the clickedImage then do nothing
		if (g_currentlyClickedButton == clickedImage) {
			return false;
		}
		// It isn't.  "Unclick" the button and tell the hover controller to unhighlight it.
		g_currentlyClickedButton.setAttribute('isClicked', 'false');
		input_renderButtonHover(g_currentlyClickedButton, false);
	}
	clickedImage.setAttribute('isClicked', 'true');
	g_currentlyClickedButton = clickedImage;
}

function input_renderButtonUnClick(clickedImage) {
	clickedImage.setAttribute('isClicked', 'false');
	input_renderButtonHover(clickedImage, false);
}

function input_renderButtonHover(currentImage, hoverMode) {
	// If a button has been clicked, and it is the just-selected button then return (don't do highlight handling).
	if (currentImage.getAttribute('isClicked') == 'true') {
		return;
	}

	if (hoverMode) {
		// Sometimes it gets confused about what was clicked (not sure when, I know that resizing the map sometimes does it).
		// Just make sure it doesn't have _hover if we are about to highlight it.
		currentImage.src=currentImage.src.replace(/_hover/,'');

		// Highlight
		currentImage.src=currentImage.src.replace(/\.gif/,'_hover.gif');
	} else {
		// Unhighlight
		currentImage.src=currentImage.src.replace(/_hover/,'');
	}
}

// Causes the Obj's className to go from highlight to normal every interval for duration
function input_blink(obj, highlight, normal, interval, duration) {
	if (!document.getElementById(obj)) {
		// Object doesn't exist, return.
		return false;
	}
	
	var runningInterval = 0;
	for (var i=0;i<=duration;i++) {
		runningInterval += interval;
		var currClassName = highlight;
		if ((i % 2) == 0) {
			currClassName = normal;
		}
		window.setTimeout("document.getElementById('"+ obj +"').className = '"+ currClassName + "';",runningInterval);
	}
	
	// Reset to the normal mode.
	document.getElementById(obj).className = normal;
	
	// Always return false.
	return false;	
}

// Layer functions
function input_populateGroupListPopupTable(mapObj) {
	// Polk doesn't want the layer list to be automatically generated.  Rather, we will build the list
	// in the map.aspx page and then use this function to update the check boxes.

	// Make sure context is available.
	if ((!mapObj) || (!mapObj.currentContext)) {return false;}

	// Find the checkbox for each group, set its value.
	for (var i=0;i<mapObj.currentContext.groupList.groups.length;i++) {
		var currGroup = mapObj.currentContext.groupList.groups[i];
		var thisID = mapObj.id + '-groupVisibility' + currGroup.id;
		
		// Make sure that this layer group exists in the layer list.
		if (document.getElementById(thisID)) {
			var isChecked = '';
			if (currGroup.visible) {isChecked='checked';}
			document.getElementById(thisID).checked = isChecked;
		}
	}
}

// Based on the group list, toggle the groups and resubmit the image if they changed.
function input_reloadLayersFromGroupList(mapObj) {
	// Check the table list for each group.  Reset the visiblilty on each one.  Then re-request the image.
	var updateMap = false;
	
	// At least one layer must be selected.
	var isLayerSelected = false;
	
	// Make sure the currentContext is available.
	if (mapObj.currentContext == null) {return false;}
	
	// Store the currContext groupList so we can revert if the new list is invalid.
	var origGroupList = mapObj.currentContext.groupList.clone();

	for (var i=0;i<mapObj.currentContext.groupList.groups.length;i++) {
		var currGroup = mapObj.currentContext.groupList.groups[i];
		var currVisibility = currGroup.visible;
		var checkBoxID = mapObj.id + '-groupVisibility' + currGroup.id;

		// Get the visibility
		if (document.getElementById(checkBoxID)) {
			var newVisibility = document.getElementById(checkBoxID).checked;

			// Compare the new visibility to the old.  If there is a change then set the new value and set the updateMap flag.
			if (currVisibility != newVisibility) {
				mapObj.currentContext.groupList.groups[i].visible = newVisibility;
				updateMap = true;
			}
			if (newVisibility === true) {isLayerSelected = true;}
		}
	}
	
	if (!isLayerSelected) {
		alert('Please select at least one layer.');
		mapObj.currentContext.groupList = origGroupList;
		updateMap = false;
	}
	origGroupList = null;

	if (updateMap) {
		mapObj.getMapImage();
	}
}

// Selects or deselects all checkboxes that are children of the parentObj.
function input_setAll(parentObj, newValue) {
	// Get a list of all input boxes that are checkboxes.
	if (parentObj) {
		try {
			var inputBoxes = parentObj.getElementsByTagName('input');
			for (var i=0;i<inputBoxes.length;i++) {
				if (inputBoxes[i].getAttribute('type') == 'checkbox') {
					// This is a checkbox, deselect it.
					inputBoxes[i].checked = newValue;
				}
			}
		} catch (ex) {
			alert(ex.message);
		}
	}
	
	return false;
}

// Makes sure the map service is allowing buffer searches.
// Parses the input to make sure it is a valid number in range, calls the handling map's retrieveBuffer function.
function input_retrieveBuffer(mapObj, bufferInputObj) {
	// Convert the input to a proper number
	if (!bufferInputObj) {
		// There is a programatic error, the input object doesn't exist.
		// Allow the box to be closed, and disable the buffer functionality.
		mapObj.removeCapability('ALLOW_BUFFERSEARCH');
		return true;
	}

	var originalValue = bufferInputObj.value;

	// Remove commas and spaces.  Also, "ft" in case someone wanted to do that.
	radiusFeet = originalValue.replace(/,/,'').replace(/ /,'').replace(/ft/gi,'');
	
	// Make sure this is a number (just to prevent the occasional oddities).
	radiusFeet = parseInt(radiusFeet, 10);

	if (isNaN(radiusFeet)) {
		alert('The value you entered was not a number.');
		bufferInputObj.focus();
		return false;
	}

	// 2640 (1/2 mile) is the maximum buffer size.  In testing a full mile still performed acceptably.  10,000ft crashed the server (I think).
	// The old website only allowed 1000ft, so 2640 is a step up.
	if (radiusFeet > 2640) {
		alert('You cannot create a buffer larger than 2640ft (1/2 mile).\r\n\r\nPlease enter a smaller buffer radius.');
		bufferInputObj.value = 2640;
		bufferInputObj.focus();
		return false;
	}

	// Call the actual buffer function inside the mapObj. (All of the previous code was simply cleanup.)
	mapObj.retrieveBuffer(radiusFeet);

	// Returning true will make the buffer size popup box go away.
	return true;
}

// Automatically moves to the next text box once maxLength has been hit.
function autoTab(e) {
	thisEvent = e || window.event;
	var thisInput = thisEvent.target ? thisEvent.target : thisEvent.srcElement;
	var keyCode = thisEvent.keyCode;
	var filter = [0,8,9,16,17,18,37,38,39,40,46];
	if(thisInput.value.length >= thisInput.maxLength && !containsElement(filter,keyCode)) {
		thisInput.value = thisInput.value.slice(0, thisInput.maxLength);
		thisInput.form[(getIndex(thisInput)+1) % thisInput.form.length].select();
		thisInput.form[(getIndex(thisInput)+1) % thisInput.form.length].focus();
	}

	function containsElement(filterArray, enteredCharacter) {
		var found = false, index = 0;
		while(!found && index < filterArray.length) {
			if (filterArray[index] == enteredCharacter) {
				found = true;
			} else {
				index++;
			}
		}
		return found;
	}

	function getIndex(thisInput) {
		var index = -1, i = 0, found = false;
		while (i < thisInput.form.length && index == -1) {
			if (thisInput.form[i] == thisInput) {
				index = i;
			} else {
				i++;
			}
		}
		return index;
	}
	return true;
}

function makeTabActive(clickedTab) {
	// Get the tab elements.
	if (!clickedTab) {return false;}
	var tabPanel = getParentByClassName(clickedTab,'tabPanel');
	var tabList = getParentByClassName(clickedTab,'tabList');
	var tabOptions = tabList.getElementsByTagName('li');

	// All the tabBoxes have a prefix that indicates that it is part of this panel.
	// That prefix is set as the id attribute of the <div class="tabPanel" /> element.
	var tabPanelPrefix = tabPanel.id;

	// Deactivate the current tab and tabBox.
	// Check each tab in the tabList; if the tab has a className of "current" then store its title, it is the current active tab.
	// Clear the className to deactivate it, then hide the tabBox that is associated with it.
	for (var i=0;i<tabOptions.length;i++) {
		if (tabOptions[i].className == 'current') {
			var currTabTitle = tabOptions[i].getAttribute('title');
			// Deactivate the tab header.
			tabOptions[i].className = '';

			// Hide the tab's box.
			if (document.getElementById(tabPanelPrefix + '.' + currTabTitle)) {
				document.getElementById(tabPanelPrefix + '.' + currTabTitle).style.display='none';
			}
			
			// Stop processing after we find the active tab.
			break;
		}
	}

	// Activate the new tab and tabBox.
	// The "clickedTab" is the A element inside the LI.  Get the actual tab.
	var selectedLI = clickedTab.parentNode;
	// Determine the id of the new tabBox div.
	var thisTitle = tabPanelPrefix + '.' + selectedLI.getAttribute('title');

	// Activate this tab.
	selectedLI.className='current';
	
	// If there is a tabBox, show it.
	if (document.getElementById(thisTitle)) {
		document.getElementById(thisTitle).style.display='block';
	} else {
		return false;
	}

	// Return false to prevent the page from changing to "#"
	return false;
}

// Get the parent, check it's className, if it doesn't match then call the parent as the child.
// If the parent is the document object then return null.
function getParentByClassName(childObj, className) {
	className = className.toUpperCase();

	// Set the childObj to it's parentNode and check if it 1) has a parentNode, 2) matches the tagName, 3) is the document object.
	// If the childObj's parentNode is the match then we don't even enter the loop.
	while ((childObj.parentNode) && (childObj.parentNode.className.toUpperCase() != className) && (childObj != document)) {
		childObj = childObj.parentNode;
	}

	// If the loop ended on document or null parentNode then return null.
	if ((childObj == document) || (!childObj.parentNode)) {
		return null;
	}
	
	// Return the current node.
	return childObj.parentNode;
}

// Get the parent, check it's tagName, if it doesn't match then call the parent as the child.
// If the parent is the document object then return null.
function getParentByTagName(childObj, tagName) {
	tagName = tagName.toUpperCase();

	// Set the childObj to it's parentNode and check if it 1) has a parentNode, 2) matches the tagName, 3) is the document object.
	// If the childObj's parentNode is the match then we don't even enter the loop.
	while ((childObj.parentNode) && (childObj.parentNode.tagName.toUpperCase() != tagName) && (childObj != document)) {
		childObj = childObj.parentNode;
	}

	// If the loop ended on document or null parentNode then return null.
	if ((childObj == document) || (!childObj.parentNode)) {
		return null;
	}
	
	// Return the current node.
	return childObj.parentNode;
}