///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
//
// This block of code is responsible for managing the state
// of any registered HTML button items.
//
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

// Attribute names - these are like 'defines'
var ID_ATTRIBUTE               = "id";
var BTN_PRESSED_ATTRIBUTE      = "btnPressed";
var UNSELECTED_IMAGE_ATTRIBUTE = "unselectedImage";
var SELECTED_IMAGE_ATTRIBUTE   = "selectedImage";

// Per-button information.
// Any button which is registered will supply the desired selected and
// unselected images; our code then manages the displaying of these
// images, based on the user pressing and releasing the mouse button
// within one of the buttons.
//
var btns = new Array();

// Given a button Id, locate the associated button data
// which was created when the button was registered.
//
function getButtonData(id)
{
	for (var i = 0; i < btns.length; i++)
	{
		var btnData = btns[i];
		if(btnData[ID_ATTRIBUTE] == id)
		{
			return(btnData);
		}
	}
	return(null);
}

// Function for querying whether the mouse button has been
// pressed and then released within the confines of the form's
// submit button UI element.
//
function isBtnPressed(id)
{
	var btnData = getButtonData(id);
	if (btnData == null)
	{
		// Unregistered button
		return(false);
	}
	else
	{
		return(btnData[BTN_PRESSED_ATTRIBUTE]);
	}
}

// This function is used to register data about a button
// which will be managed by the various event handlers in
// this file.
//
function registerBtn(id, selectedImage, unselectedImage)
{
	// To speed up realtime performance when we try to change
	// the image when the user clicks the button, we will pre-load
	// (cache) the images, to prevent a lag the first time that we
	// try to swap the images.
	//
	var selectedImageObj = new Image();
	selectedImageObj.src = selectedImage;
	var unselectedImageObj = new Image();
	unselectedImageObj.src = unselectedImage;

	// Create a new generic object; attach the data we care
	// about as properties for this object.
	//
	var btnData = new Object();
	btnData[ID_ATTRIBUTE]  = id;
	btnData[BTN_PRESSED_ATTRIBUTE] = false;
	btnData[UNSELECTED_IMAGE_ATTRIBUTE] = unselectedImageObj;
	btnData[SELECTED_IMAGE_ATTRIBUTE] = selectedImageObj;
	btns[btns.length] = btnData;

	// Assign the event handler we need in order to properly
	// support updating the button image when the user presses
	// or releases the mouse button over the button image.
	//
	var btn = document.getElementById(id);
	if (btn != null)
	{
		btn.onmousedown = function(){btnPressHandler(id)};
		btn.onmouseup = function()  {btnReleaseHandler(id)};
		btn.onmouseout = function() {mouseOutHandler(id)};
	}
}

// Function triggered when the user presses the mouse button
// while over the form's submit button.  Among other things,
// it will change the image displayed by the button and it
// will tag the button as being currently selected.
//
function btnPressHandler(id)
{
	var btnData = getButtonData(id);
	btnData[BTN_PRESSED_ATTRIBUTE] = true;
	document.getElementById(id).src = (btnData[SELECTED_IMAGE_ATTRIBUTE]).src;
}

// Function triggered when the user releases the mouse button
// while over the form's submit button.  Among other things,
// it will restore the image displayed by the button to its
// original (unselected) state.
//
function btnReleaseHandler(id)
{
	var btnData = getButtonData(id);

	if(btnData[BTN_PRESSED_ATTRIBUTE])
	{
		document.getElementById(id).src = (btnData[UNSELECTED_IMAGE_ATTRIBUTE]).src;

		// Don't clear this, because this event can occur before the
		// submit event; if we clear this now, then the submit code
		// will never process the request.
		//
		//btnData[BTN_PRESSED_ATTRIBUTE] = false;
	}
}

// Function triggered when the user moves the cursor out of the submit
// button, while still holding down the mouse button.  We need to effectively
// act as if the user has released the mouse button; in other words, we need
// to restore the button image to its original (unselected) state, and we need
// to clear the flag which indicates that a valid button select is in progress.
// We do this because if the user releases the mouse button outside of the 
// submit button, we aren't notified, so the submit button image is left in
// the 'selected' state.
//
function mouseOutHandler(id)
{
	var btnData = getButtonData(id);

	if(btnData[BTN_PRESSED_ATTRIBUTE])
	{
		document.getElementById(id).src = (btnData[UNSELECTED_IMAGE_ATTRIBUTE]).src;
		btnData[BTN_PRESSED_ATTRIBUTE] = false;
	}
}

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
//
// This block of code is responsible for managing the automatic
// clearing of a registered textField element, the first time
// it receives the focus.
//
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

// Per-textField information; used to track which text
// fields have been cleared due to a focusIn event
// occurring.  The textField item is automatically added
// by a call to clearField(), which can be associated
// with a textField's onFocus event.
//
var textFieldClearedFlags = new Array();

// This function can be attached to the 'onFocus' handler for a text
// field, and in conjunction with a boolean flag, can be used to clear
// a text field the first time it receives the focus.  This is useful
// for placing a descriptive comment into a text field, which is then
// removed as soon as the user gives the focus to the text field.  To
// work correctly, the caller should create a boolean variable, which
// is initialized to 'true'; this variable is then passed as the second
// parameter, and indicates whether this is the first time that the
// text field has received the focus.  The return value is the update
// boolean flag value (which will also be false).
//
function clearField(id)
{
	if(!hasTextFieldBeenCleared(id))
	{
		// Clear the textField element
		document.getElementById(id).value = "";

		// Register the fact that we've cleared the
		// textField contents, so that we won't do it
		// again the next time it receives the focus.
		registerTextField(id);
	}
}

// Given a textField id, see if the text field has already
// been cleared.  Returns a boolean: true if the textField
// has already been cleared, and false otherwise.
//
function hasTextFieldBeenCleared(id)
{
	for (var i = 0; i < textFieldClearedFlags .length; i++)
	{
		var textFieldFlag = textFieldClearedFlags [i];
		if (textFieldFlag[ID_ATTRIBUTE] == id)
		{
			// TextField item is registered, so it's been cleared
			return(true);
		}
	}

	// Item not found, so it hasn't yet been cleared.
	return(false);
}

// Add the indicated textField element to the list of textFields
// which have been cleared as a result of a focusIn event.
//
function registerTextField(id)
{
	// Create a new generic object; attach the data we care
	// about as properties for this object.  For the time
	// being, the only data we need to save is the name of
	// the textField.
	//
	var textFieldData = new Object();
	textFieldData[ID_ATTRIBUTE]  = id;
	textFieldClearedFlags[textFieldClearedFlags.length] = textFieldData;
}

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
//
// Miscellaneous utilities
//
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
	
// Check if a form field is blank; blank implies that it either
// contains no characters or it only contains space characters.
//
function inputIsBlank(value)
{
	if (value == "")
	{
		return(true);
	}
	
	for (var i = 0; i < value.length; i++)
	{
		if (value.charAt(i) != ' ')
		{
			// Found a non-space character
			return(false);
		}
	}

	// String only contains space characters
	return(true);
}

// Check for the presence of "<a ", "http:", "https:", "[url" or "[link" in the field value;
// these are not allowed, since they can indicate attempts to breach security, usually by
// a spambot.
function suspiciousTagsFound(id, fieldName)
{
	var fieldValue = document.getElementById(id).value;

	if (inputIsBlank(fieldValue))
	{
		return(false);
	}

	if ((fieldValue.indexOf("<a ") == -1) &&
	    (fieldValue.indexOf("http:") == -1) &&
	    (fieldValue.indexOf("https:") == -1) &&
	    (fieldValue.indexOf("[url") == -1) &&
	    (fieldValue.indexOf("[link") == -1))
	{
		// Nothing suspicious found
		return(false);
	}
	
	alert("This form cannot be submitted because it contains text that could create a security problem.\n\n" +
		"URLs and hyperlinks are not allowed.  Please edit the '" + fieldName + "' field and try again.");
	return(true);
}