
var gForm_lock = false;		// Global variable to lock a form so double-clicks will be ignored

function isArray(obj)
{
	return( typeof(obj.length) == "undefined" ) ? false : true;
}

function submitOnEnter(fn, e)
{
	var keycode;
	if (window.event) keycode = window.event.keyCode;
	else if (e) keycode = e.which;
	else return true;

	// If enter was pressed, call the passed function
	if (keycode == 13)
	{
		fn(e);
		return false;
	}
}


// Used to limit number of charactes in a textarea
function textCounter(field, countfield, maxlimit)
{
	if ( field.value.length > maxlimit)
	{
		// if too long...trim it!
		field.value = field.value.substring(0, maxlimit);
	} else {
		// otherwise, update 'characters left' counter
		countfield.value = maxlimit - field.value.length;
	}
}


//////////////////////////////////////////////////
//												//
// Form get/set functions						//
//												//
//////////////////////////////////////////////////

// Gets the value(s) of any input element passed to it.  If the input allows multiple selections (such as a
// multiple-select or a checkbox) then results are returned comma-deliminated.  If retrieving from a select
// that has no options, then "" is returned.
function getInputValue(oInput)
{
	var i;
	var ret_val = "";										// Default return value is blank

	if ( oInput )
	{
		if ( oInput.type ) type = oInput.type;				// Type is: text, select
		else if ( isArray(oInput) && oInput[0].type ) type = oInput[0].type;	// Array indicates checkbox or option
		else type = null;									// Type cannot be determined, skip input

		switch (type)										// Switch on the input type
		{
			case "text":
			case "hidden":
			case "password":
			case "file":
			case "textarea":
				ret_val = oInput.value;
				break;
			case "select-one":
				var len = oInput.options.length;			// Number of options
				if ( len == 0 ) ret_val = "";				// If no options, return blank
				else ret_val = oInput.options[oInput.options.selectedIndex].value;
				break;
			case "select-multiple":
				var len = oInput.options.length;			// Number of options
				if ( len == 0 ) ret_val = "";				// If no options, return blank
				else {
					for (i=0; i<len; i++)
					{
						if ( oInput.options[i].selected )
						{
							if ( ret_val == "" ) ret_val = oInput.options[i].value;
							else ret_val += ","+oInput.options[i].value;
						}
					}
				}
				break;
			case "radio":
				if ( oInput.length )
				{
					for (i=0; i<oInput.length; i++)
					{
						if ( oInput[i].checked ) ret_val = oInput[i].value;
					}
				}
				else if ( oInput.checked ) ret_val = oInput.value;
				break;
			case "checkbox":
				if ( oInput.length )
				{
					for (i=0; i<oInput.length; i++)
					{
						if ( oInput[i].checked )
						{
							if ( ret_val == "" ) ret_val = oInput[i].value;
							else ret_val += ", "+oInput[i].value;
						}
					}
				}
				else if ( oInput.checked ) ret_val = oInput.value;
				break;
			default:
//				alert("getInputValue() unknown type: "+type);
				break;
		}
	}
	return trim(ret_val);
}


// Sets the value of any input element passed to it.
function setInputValue(oInput, new_val)
{
	if ( oInput )
	{
		if ( oInput.type ) type = oInput.type;				// Type is: text, select
		else if ( isArray(oInput) && oInput[0].type ) type = oInput[0].type;	// Array indicates checkbox or option
		else type = null;									// Type cannot be determined, skip input

		switch (type)										// Switch on the input type
		{
			case "text":
			case "hidden":
			case "password":
				oInput.value = new_val;
				break;
			case "select-one":
			case "select-mulitiple":
				selDropdown(oInput, new_val);
				break;
			case "radio":
				selRadio(oInput, new_val);
				break;
			case "checkbox":
				selCheckbox(oInput, new_val);
				break;
			case "textarea":
				oInput.value = new_val;
				break;
			case "button":		// do nothing on a button
				break;
			default:
//				alert("setInputValue() unknown type: "+type);
				break;
		}
	}
}


// Takes a radio and some text and select the radio found with that text.  Matching 
// is case insensitive.
function selCheckbox(oCbox, txt) {
	var i, txt_to_match;

	if (typeof(txt) == "string") txt_to_match = txt.toLowerCase();			// If txt is a string, make it lowercase
	else if (typeof(txt) == "number") txt_to_match = txt.toString();		// If txt is a number, convert to a string

	if (oCbox) {
		if (oCbox.length) {													// If checkbox has more than one item
			for (i=0; i<oCbox.length; i++) {
				if (oCbox[i].value.toLowerCase() == txt_to_match) {			// If matching radio is found
					oCbox[i].checked = true;								//   check it
				} else {
					oCbox[i].checked = false;								// Otherwise uncheck it
				}
			}
		} else {
			if (oCbox.value.toLowerCase() == txt_to_match) {				// If matching checkbox is found
				oCbox.checked = true;										//   check it
			} else {
				oCbox.checked = false;										// Otherwise uncheck it
			}
		}
	}
}


// Takes a dropdown and some text and selects any dropdown found with that text.  Matching 
// is case insensitive.
function selDropdown(oDropdown, txt)
{
	var i, txt_to_match;

	if ( typeof(txt) == "string" ) txt_to_match = txt.toLowerCase();		// If txt is a string, make it lowercase
	else if ( typeof(txt) == "number" ) txt_to_match = txt.toString();		// If txt is a number, convert to a string

	if ( oDropdown )
	{
		for (i=0; i<oDropdown.options.length; i++)
		{
			// Select the first matching dropdown and exit loop
			if ( oDropdown.options[i].value.toLowerCase() == txt_to_match )
			{
				oDropdown.options[i].selected = true;
				break;
			}
		}
	}
}


// Takes a radio and some text and select the radio found with that text.  Matching 
// is case insensitive.
function selRadio(oRadio, txt)
{
	var i, txt_to_match;

	if ( typeof(txt) == "string" ) txt_to_match = txt.toLowerCase();			// If txt is a string, make it lowercase
	else if ( typeof(txt) == "number" ) txt_to_match = txt.toString();			// If txt is a number, convert to a string

	if ( oRadio )
	{
		// If multiple radios
		if ( oRadio.length )
		{
			for (i=0; i<oRadio.length; i++)
			{
				// If matching radio is found check it.  Otherwise uncheck it.
				if ( oRadio[i].value.toLowerCase() == txt_to_match )
				{
					oRadio[i].checked = true;
				} else {
					oRadio[i].checked = false;
				}
			}
		}
		// If a single radio
		else if ( oRadio.value.toLowerCase() == txt_to_match ) oRadio.checked = true;
		else oRadio.checked = false;
	}
}


// Clears any input.  Textfields are blanked, dropdowns reset to first option
// checkboxes and radio boxes are unchecked.
function clearInputValue(oInput)
{
	if ( oInput )
	{
		if ( oInput.type ) type = oInput.type;				// Type of input, select
		else if ( isArray(oInput) && oInput[0].type ) type = oInput[0].type;	// Array indicates checkbox or option
		else type = null;									// Type cannot be determined, skip input

		switch (type)										// Switch on the input type
		{
			case "text":
			case "hidden":
				oInput.value = "";
				break;
			case "select-one":
			case "select-mulitiple":
				for (var i=0; i<oInput.length; i++)
				{
					oInput[i].selected = false;
				}
				oInput[0].selected = true;
				break;
			case "radio":
			case "checkbox":
				if ( oInput.length )
				{
					for (var i=0; i<oInput.length; i++)
					{
						oInput[i].checked = false;
					}
				}
				else oInput.checked = false;
				break;
			case "button":
				break;
			case "textarea":
				ret_val = oInput.value = "";
				break;
			default:
//				alert("clearInputValue() unknown type: "+type);
				break;
		}
	}
}

// Strip whitespace (space, tabs) from the beginning and end of a string
function trim(txt)
{
	// Handle special cases
	if ( !txt || txt == "" || txt == null || txt === undefined) return "";
	else
	{
		txt = txt.replace(/^[\s\t]*/, "");
		txt = txt.replace(/[\s\t]*$/, "");
		return txt;
	}
}

// ErrorList object
function ErrorList()
{
	// Public variables

	// Private variables
	var num_errors	= 0;
	var num_warnings= 0;
	var errors		= new Array();
	var warnings	= new Array();

	// Public methods
	this.addError = function(msg, line)
	{
		if ( line === undefined || line == null || line == "" ) line = 0;
		else line = parseInt(line,10);

		if ( !errors[line] ) errors[line] = new Array();
		errors[line].push(msg);
		num_errors++;
	}

	this.getNumErrors = function()
	{
		return num_errors;
	}

	this.getErrors = function()
	{
		error_msg = "";
		for (var i=0; i<errors.length; i++)
		{
			if ( errors[i] )
			{
				for (err in errors[i])
				{
					error_msg += errors[i][err];
				}
			}
		}
		return error_msg;
	}

	this.getWarnings = function()
	{
		error_msg = "";
		for (var i=0; i<warnings.length; i++)
		{
			if ( warnings[i] )
			{
				for (err in warnings[i])
				{
					error_msg += warnings[i][err];
				}
			}
		}
		return error_msg;
	}

	this.addWarning = function(msg, line)
	{
		if ( line === undefined || line == null || line == "" ) line = 0;
		else line = parseInt(line,10);

		if ( !warnings[line] ) warnings[line] = new Array();
		warnings[line].push(msg);
		num_warnings++;
	}

	// Returns number of errors
	this.getNumWarnings = function()
	{
		return num_warnings;
	}

	// Shows any errors and warnings stored in the list.
	this.showErrors = function()
	{
		var error_msg	= this.getErrors();
		var warning_msg	= this.getWarnings();

		if ( warning_msg )
		{
			error_msg += "\nThe following are suggested, but not required:\n" + warning_msg;
		}

		if ( error_msg != "" )
		{
			alert(error_msg);
		}
	}

	// Shows any errors stored in the list.  Returns the result of a confirmation box.
	this.confirmErrors = function()
	{
		var error_msg	= this.getErrors();
		var warning_msg	= this.getWarnings();

		if ( warning_msg )
		{
			error_msg += "\nThe following are suggested, but not required:\n" + warning_msg;
		}

		if ( error_msg != "" )
		{
			error_msg += '\nDo you still want to save?'; 
			return confirm(error_msg);
		}
	}


	// Shows just the warnings in the list.  Returns the result of a confirmation box.
	this.confirmWarnings = function()
	{
		var warning_msg = this.getWarnings();

		if ( warning_msg != "" )
		{
			warning_msg = "The following are suggested, but not required:\n" + warning_msg;
			warning_msg += '\nDo you still want to save?'; 
			return confirm(warning_msg);
		}
	}

}

// Adds an error to the error list and updates the input's class
// VARIABLES:
//   oInput			Optional input to change the class to "typo".  May be null or "" if no input should be changed.
//   [oErrorList]	Error object to add an error to.  If not passed then only the input class is changed.
//   [msg]			Error string to add
//   [line]			Optional line number of error
function setError(oInput, oErrorList, msg, line)
{
	// Save the error
	if ( line === undefined || line == null || line == "" ) line = 0;
	if ( msg === undefined || msg == null ) msg = "";
	if ( oErrorList !== undefined && oErrorList != null && oErrorList != "" )
	{
		if ( msg != "" ) oErrorList.addError(msg, line);
	}

	// Set the input's class
	if ( oInput != null && oInput != "" )
	{
		if ( oInput.className && oInput.className != "typo" ) oInput.prevClassName = oInput.className;
		oInput.className = "typo";
	}
}

// Adds a warning to the error list and updates the input's class
// VARIABLES:
//   oInput			Optional input to change the class to "typo".  May be null or "" if no input should be changed.
//   [oErrorList]	Error object to add an error to.  If not passed then only the input class is changed.
//   [msg]			Error string to add
//   [line]			Optional line number of error
function setWarning(oInput, oErrorList, msg, line)
{
	// Save the error
	if ( line === undefined || line == null || line == "" ) line = 0;
	if ( msg === undefined || msg == null ) msg = "";
	if ( oErrorList !== undefined && oErrorList != null && oErrorList != "" )
	{
		if ( msg != "" ) oErrorList.addWarning(msg, line);
	}

	// Set the input's class
	if ( oInput != null && oInput != "" )
	{
		if ( oInput.className && oInput.className != "typo" ) oInput.prevClassName = oInput.className;
		oInput.className = "typo";
	}
}

// Takes all the inputs in the passed form and sets any with the error class to their
// previous class.  If no previous class, assume the class was blank.
function clearInputErrors(oForm)
{
	oInputs = oForm.getElementsByTagName("INPUT");
	for (var i=0; i<oInputs.length; i++)
	{
		if ( oInputs[i].className == "typo" )
		{
			if ( oInputs[i].prevClassName )
			{
				oInputs[i].className = oInputs[i].prevClassName;
				oInputs[i].prevClassName = null;
			}
			else
			{
				oInputs[i].className = "";
			}
		}
	}

	oInputs = oForm.getElementsByTagName("SELECT");
	for (var i=0; i<oInputs.length; i++)
	{
		if ( oInputs[i].className == "typo" )
		{
			if ( oInputs[i].prevClassName )
			{
				oInputs[i].className = oInputs[i].prevClassName;
				oInputs[i].prevClassName = null;
			}
			else
			{
				oInputs[i].className = "";
			}
		}
	}
}

// SAVE BUTTON ENABLING/DISABLING FUNCTIONS
//
// Used to apply an onchange function to every input in a form.  The function will enable
// the button when anything in the form has been changed.  It does not overwrite any
// existing events on the form fields.
//
// This function provides an easy way to apply the onchange event to all elements of a form.
// Some forms with multiple sections or more complexity may need the onchange event
// manually applied to the wanted fields without using this function.
//
//   Variables:
// 		form_id		- ID of the form to apply the onChange event to
//		btn_id		- ID of the button to enable/disable (the id must be unique for the entire page)
//		className	- class the button should receive when active
function initFormOnChange(form_id, btn_id, className)
{
	var oForm;
	if ( oForm = document.getElementById(form_id) )
	{
		for (var i=0; i<oForm.elements.length; i++)
		{
			// Radios and checkboxes get an onClick event
			if ( oForm.elements[i].type == "radio" || oForm.elements[i].type == "checkbox" )
			{
				if ( document.addEventListener )	// Moz
				{
					oForm.elements[i].addEventListener("click", function(e) {enableButton(e, btn_id, className);}, false);
				}
				else if ( document.attachEvent )	// IE
				{
					oForm.elements[i].attachEvent("onclick", function(e) {enableButton(e, btn_id, className);} );
				}
			}
			// All other input elements get an onChange and onKeyPress event
			else if ( oForm.elements[i].type != "button" )
			{
				if ( document.addEventListener )	// Moz
				{
					oForm.elements[i].addEventListener("change", function(e) {enableButton(e, btn_id, className);}, false);
					oForm.elements[i].addEventListener("keyup", function(e) {enableButton(e, btn_id, className);}, false);
				}
				else if ( document.attachEvent )	// IE
				{
					oForm.elements[i].attachEvent("onchange", function(e) {enableButton(e, btn_id, className);} );
					oForm.elements[i].attachEvent("onkeyup", function(e) {enableButton(e, btn_id, className);} );
				}
			}
		}
	}
}

// Enables the button with the given ID and applies the passed class to it.
//  evt			- event that initiated this action.  null means it was called manually.
//  btn_id		- ID (or button object) of button to enable
//  className	- the class to give the button
function enableButton(evt, btn_id, className)
{
	var obj, key_pressed;

	var evt = (evt) ? evt : ((window.event) ? window.event : null);

	// If evt is not null, get the key pressed
	if ( evt != null )
	{
		if ( evt.which ) key_pressed = evt.which;
		else key_pressed = evt.keyCode;
	}

	// Allow any event without an event handler since this means the function was called manually.
	// Allow any onChange event.  Ignore tabs (9), return (13) and arrow keys (33-40).
	if ( evt == null || evt.type == "change" ||
	   (key_pressed != 9 && key_pressed != 13 && !(key_pressed >= 33 && key_pressed <= 40)) )
	{
		obj = ( typeof(btn_id) == "string" ) ? document.getElementById(btn_id) : btn_id;
		if ( obj )
		{
			// Only change if not already set.  This removes flicker on IE.
			if ( obj.disabled ) obj.disabled = false;
			if ( obj.className != className ) obj.className = className;
		}
	}
}

// Disables the button with the given ID and applies the passed class to it
//  btn_id		- ID (or button object) of button to enable
//  className	- the class to give the button
function disableButton(btn_id, className)
{
	var obj;
	obj = ( typeof(btn_id) == "string" ) ? document.getElementById(btn_id) : btn_id;
	if ( obj )
	{
		obj.disabled = true;
		obj.className = className;
	}
}

// Given the passed row, clone it and rename all id's that end with a given string to the original id
// appended with the new end.  So this:					<tr id="row_0"><td><input name="name_0" /></td></tr>
// called with cloneEditRow(oTr, "_0", "_5") becomes	<tr id="row_5"><td><input name="name_5" /></td></tr>
function cloneEditRow(oTr_source, old_end, new_end)
{
	oTr		= oTr_source.cloneNode(true);
	oTr.id	= "";

	// Rename any id or name ending with "_0" to the new count
	oItems = findChildrenById(oTr, old_end, "ends_with")
	for (i=0; i<oItems.length; i++)
	{
		if (oItems[i].name && oItems[i].name.lastIndexOf(old_end) == (oItems[i].name.length - old_end.length))
		{
			oItems[i].name = oItems[i].name.substring(0,oItems[i].name.lastIndexOf(old_end)) + new_end;
		}

		if (oItems[i].id && oItems[i].id.lastIndexOf(old_end) == (oItems[i].id.length - old_end.length))
		{
			oItems[i].id = oItems[i].id.substring(0,oItems[i].id.lastIndexOf(old_end)) + new_end;
		}

		clearInputValue(oItems[i]);		// will clear any input, ignores non-inputs
	}
	return oTr;
}

function validateDigital()
{
	// Lock the form to prevent double-click saves
	if ( gForm_lock ) return;
	else gForm_lock = true;

	var errors	= new ErrorList();
	var oForm	= document.getElementById("digital_magazine");

	clearInputErrors(oForm);

	var email		= trim(getInputValue(oForm["email"]));

	if ( !checkEmail(email) ) setError(oForm["email"], errors, "Invalid email address\n");

	if ( errors.getNumErrors() )
	{
		errors.showErrors();
		gForm_lock = false;
	}
	else oForm.submit();
}
