
/**
 * This file contains functions which will be called by the HTML generated by the Form Parser.
 *
 * It must be copied into the site's JS folder and referenced by every page which
 * uses the form parser.
 */

/* 
	INIT HELP LINKS : This needs to be called by the site's document onload handler!
*/
function fnInitFormHelp() {	
	nsAll = navigator.userAgent.toLowerCase().indexOf("netscape") != -1 ? true:false;
	if(!nsAll) {
		fnHideAllHelpLinks();
	}
}

function fnHideAllHelpLinks(){
    var obj,nextspan,anchor,content

    // get all spans
    obj=document.getElementsByTagName('span')

    // run through them
    for (var i=0;i<obj.length;i++){

		// if it has a class of helpLink
		if(/helpLink/.test(obj[i].className)){
		
			// get the adjacent span
			nextspan=obj[i].nextSibling
			while(nextspan.nodeType!=1) nextspan=nextspan.nextSibling

			// hide it
			nextspan.style.display='none'

			//create a new link
			anchor=document.createElement('a')

			// copy original helpLink text and add attributes
			content=document.createTextNode(obj[i].firstChild.nodeValue)
			anchor.appendChild(content)
			anchor.href='#help'
			anchor.title='Click to show help'
			anchor.className=obj[i].className
			anchor.nextspan=nextspan
			anchor.onclick=function(){fnShowHideHelpText(this.nextspan);fnChangeHelpTitle(this);return false}

			// replace span with created link
			obj[i].replaceChild(anchor,obj[i].firstChild);

		}
    }
}

// used to flip helpLink title
function fnChangeHelpTitle(obj){    
    if(obj)
    obj.title = obj.title=='Click to show help' ? 'Click to hide help' : 'Click to show help'
}

 // used to flip the display property
function fnShowHideHelpText(obj){  
    if(obj)
    obj.style.display = obj.style.display=='none' ? 'block' : 'none';
}

	

/**
 * Put the number of characters left onto the counter for a text area.
 */	
function fnTextCounter(targ, maxChar){

	var charUsed = targ.value.length;
	var charLeft = (maxChar - charUsed);
	
	if (charUsed >= maxChar) {
		targ.value = targ.value.substring(0, maxChar);
		charLeft = 0;
	} 
	
	var oCounter = document.getElementById(targ.id.replace("input","counter"));
	if (oCounter) {
		oCounter.innerHTML = "Characters left: " + charLeft;
	}
	
}	
	
	

/**
 * Form builder validation function for text inputs.
 */	
function fnValidateText(oInput, sLabelID, bRequired, sRequiredError, sRegex, sRegexError, sMustMatchID, sMustMatchError)
{
	// Used to record whether the input is valid, and the relavent error message.
	var bValid = true;
	var sError = "";

	// Same logic as in the c# code. Check for required error (trim the value too)
	if (oInput.value.replace(/^\s+|\s+$/g, '').length == 0) {
		bValid = !bRequired;
		sError = sRequiredError;
	}
	else if (sRegex) {
		// test regex
		try {
			var re = new RegExp(sRegex);
			if (!oInput.value.match(re)) {
				bValid = false;
				sError = sRegexError;
			}
		} catch (e) {
			// If it fails then leave it as valid.
		}
	}
	if (bValid && sMustMatchID) {
		// test mustmatch field
		var oMatch = document.getElementById(sMustMatchID);
		if (oMatch) {
			if (oMatch.value != oInput.value) {
				bValid = false;
				sError = sMustMatchError;
			}
		}
	}
	
	fnDisplayTickCross(sLabelID, bValid, sError);
}

/**
 * Form builder validation function for text areas.
 */	
function fnValidateTextArea(oInput, sLabelID, bRequired, sRequiredError)
{
	// Used to record whether the input is valid, and the relavent error message.
	var bValid = true;
	var sError = "";

	// Check for required error (trim the value too)
	if (bRequired && oInput.value.replace(/^\s+|\s+$/g, '').length == 0) {
		bValid = false;
		sError = sRequiredError;
	}
	
	fnDisplayTickCross(sLabelID, bValid, sError);
}

/**
 * Form builder validation function for drop downs.
 */	
function fnValidateSelect(oInput, sLabelID, bRequired, sRequiredError)
{
	// Used to record whether the input is valid, and the relavent error message.
	var bValid = true;
	var sError = "";
	
	// Check for required error (values are always padded with 4 chars)
	if (bRequired && oInput.options[oInput.selectedIndex].value.length == 4) {
		bValid = false;
		sError = sRequiredError;
	}
	
	fnDisplayTickCross(sLabelID, bValid, sError);
}

/**
 * Form builder validation function for drop downs.
 */	
function fnValidateFile(oInput, sLabelID, bRequired, sRequiredError, sFileTypes, sFileTypesError)
{
	// Used to record whether the input is valid, and the relavent error message.
	var bValid = true;
	var sError = "";
	
	// Check for required error
	if (bRequired && oInput.value.length == 0) {
		bValid = false;
		sError = sRequiredError;
	}
	else if (oInput.value.length > 0 && sFileTypes.length > 0) {
		bValid = false;
		
		var sFileType = oInput.value.substring(oInput.value.lastIndexOf(".") + 1);
		
		// check for invalid file type
		var fileTypes = sFileTypes.split(",");
		for(i = 0; i < fileTypes.length; i++){
			// trim and lower case
			fileTypes[i] = fileTypes[i].replace(/^\s+|\s+$/g, '').toLowerCase();
			
			// remove any dot
			if (fileTypes[i].charAt(0) == ".") fileTypes[i] = fileTypes[i].substring(1);
			
			// compare
			if (fileTypes[i] == sFileType.toLowerCase()) {
				bValid = true;
				break;
			}
		}
		
		if (!bValid) {
			if (sFileTypesError.length > 0) {
				sError = sFileTypesError;
			}
			else {
				sError = "The file must be one of: " + sFileTypes;
			}
		}
	}
	
	fnDisplayTickCross(sLabelID, bValid, sError);
}

/**
 * Form builder validation function for checkbox.
 */	
function fnValidateCheckbox(oInput, sLabelID, bRequired, sRequiredError)
{
	// Used to record whether the input is valid, and the relavent error message.
	var bValid = true;
	var sError = "";
	
	// Check for required error (values are always padded with 4 chars)
	if (bRequired && !oInput.checked) {
		bValid = false;
		sError = sRequiredError;
	}
	
	fnDisplayTickCross(sLabelID, bValid, sError);
}

/**
 * Form builder validation function for checkbox list.
 */	
function fnValidateCheckboxList(oInput, sLabelID, bRequired, sRequiredError)
{
	// Used to record whether the input is valid, and the relavent error message.
	var bValid = true;
	var sError = sRequiredError;
	
	// Check for required error (values are always padded with 4 chars)
	if (bRequired) 
	{
		// Loop through all checkboxes and see if one is checked.
		var oAllInputs = oInput.parentNode.getElementsByTagName("input");
		bValid = false;
		
		// If you find a checked one then set it to valid and end.
		for (var i = 0; i < oAllInputs.length; i++) {
			if (oAllInputs[i].checked) {
				bValid = true;
				break;
			}
		}
	}
	
	fnDisplayTickCross(sLabelID, bValid, sError);
}

/**
 * Form builder validation function for radio buttons.
 */	
function fnValidateRadioList(oInput, sLabelID, bRequired, sRequiredError, bAllowSubmit)
{
	// Used to record whether the input is valid, and the relavent error message.
	var bValid = true;
	var sError = sRequiredError;
	
	// Check for required error (values are always padded with 4 chars)
	if (bRequired) 
	{
		// Loop through all checkboxes and see if one is checked.
		var oAllInputs = oInput.parentNode.getElementsByTagName("input");
		bValid = false;
		
		// If you find a checked one then set it to valid and end.
		for (var i = 0; i < oAllInputs.length; i++) {
			if (oAllInputs[i].checked) {
				bValid = true;
				break;
			}
		}
	}
	
	// If its valid so far, check whether this radio button is good
	if (bValid) {
		if (oInput.checked) {
			bValid = bAllowSubmit;
		}
	}
	
	fnDisplayTickCross(sLabelID, bValid, sError);
}

/**
 * Form builder validation function for date picker.
 * sInputPrefix - The prefix of IDs used by date picker selects, e.g. input42_day = input42
 */
function fnValidateDatePicker(sInputPrefix, sLabelID, bRequired, sRequiredError, lFrom, sFromError, lTo, sToError) {
	var bValid = true;
	var sError = "";
	
	// Get a handle on the 3 dropdowns.
	var oDay = document.getElementById(sInputPrefix + "_day");
	var oMonth = document.getElementById(sInputPrefix + "_month");
	var oYear = document.getElementById(sInputPrefix + "_year");
	
	// If required and date not chosen, error.
	if (bRequired && (oYear.options[oYear.selectedIndex].value.length == 0 || oMonth.options[oMonth.selectedIndex].value.length == 0 || oDay.options[oDay.selectedIndex].value.length == 0)) {
		bValid = false;
		sError = sRequiredError;
	}
	else
	{
		// A date is chosen. No easy way to valididate dates in JS as it just goes over to the next month e.g. on feb.
		var oDate = new Date();
		oDate.setFullYear(oYear.options[oYear.selectedIndex].value, oMonth.options[oMonth.selectedIndex].value - 1, oDay.options[oDay.selectedIndex].value);
		oDate.setHours(0);
	    oDate.setMinutes(0);
	    oDate.setSeconds(0);
	    oDate.setMilliseconds(0);
		lDate = oDate.getTime();
		
		if (isNaN(lDate)) {
			// If invalid date chosen, error.
			bValid = false;
			sError = sRequiredError;
		}
		else 
		{
			// A valid date is chosen, or at least one that JS can parse.
			// If not within date range, error.
			if (lDate < lFrom) {
				var oFrom = new Date();
				oFrom.setTime(lFrom);
				bValid = false;
				sError = sFromError + oFrom.getDate() + "/" + (oFrom.getMonth() + 1) + "/" + oFrom.getFullYear();
			}
			else if (lDate > lTo) {
				var oTo = new Date();
				oTo.setTime(lTo);
				bValid = false;
				sError = sToError + oTo.getDate() + "/" + (oTo.getMonth() + 1) + "/" + oTo.getFullYear();
			}
		}
	}
	
	fnDisplayTickCross(sLabelID, bValid, sError);
}

/**
 * Display the tick or cross and error message in the <em> of the label (id) passed in.
 */
function fnDisplayTickCross (sLabelID, bValid, sError) {

	// Target <label>	
	var oLabel = document.getElementById(sLabelID);
	if (!oLabel) return;
	
	// Build <em> tags in labels if they are missing 
	if (!oLabel.getElementsByTagName("em")[0]) {
		var myEm = document.createElement("em");		
		oLabel.appendChild(myEm);
	}	
	
	// Get output target (EM)
	var outputTarget = oLabel.getElementsByTagName("em")[0];

	// Set the validation message on the field.
	if (bValid) {
		outputTarget.className = "tick";
		outputTarget.innerHTML = "&nbsp;";
	} else {
		if (typeof(sError) == "undefined" || sError.length == 0) {
			sError = "&nbsp;";
		}
		outputTarget.className = "cross";
		outputTarget.innerHTML = sError;
	}
}


/**
 * Writes the HTML for the calendar button. It's in JS because the calendar only works with JS.
 */
function fnWriteCalendarButton (sInputPrefix) {
	document.write('<div class="calendarWrap">');
	document.write('<a href="#" class="dateChooserLink" title="Open calendar" ');
	document.write(' onclick="return fnOpenDatePicker(\'' + sInputPrefix + '\',this)">Open calendar</a>');
	document.write('</div>');
}


/**
 * Fires when you click the calendar link.
 * Opens the calendar in the right place. Only one calendar exists on the page, it is reused.
 */
function fnOpenDatePicker(sInputPrefix, oLink)
{	
	// Create date picker instance if it doesn't already exist
	if (!document.DateChooser)
	{
		document.DateChooser = new DateChooser();

		// Check if the browser has fully loaded the DateChooser object, and supports it.
		if (!document.DateChooser.display)
		{
			return false;
		}

		// Set generic properties.
		document.DateChooser.setCloseTime(1000);
		document.DateChooser.setXOffset(26);
		document.DateChooser.setYOffset(0);
	}
	
	// Check if the browser has fully loaded the DateChooser object, and supports it.
	if (!document.DateChooser.display)
	{
		return false;
	}

	// Tell it to update these fields.				
	eval ("var t = {'" + sInputPrefix + "_day':'j', '" + sInputPrefix + "_month':'n', '" + sInputPrefix + "_year':'Y'};");
	document.DateChooser.setUpdateField(t);
	
	// Get a handle on the 3 dropdowns.
	var oDay = document.getElementById(sInputPrefix + "_day");
	var oMonth = document.getElementById(sInputPrefix + "_month");
	var oYear = document.getElementById(sInputPrefix + "_year");
	
	// Set the earliest and latest date to show on the calendar
	var d = new Date();	
	if (oDay[0].value.length == 0 && oMonth[0].value.length == 0 && oYear[0].value.length == 0) {
		// If "day" "month" "year" options are shown
		d.setFullYear(oYear.options[1].value, oMonth.options[1].value - 1, oDay.options[1].value);
		document.DateChooser.setEarliestDate(d);
	}
	else {
		// No day month year options. 
		d.setFullYear(oYear.options[0].value, oMonth.options[0].value - 1, oDay.options[0].value);
		document.DateChooser.setEarliestDate(d);
	}
	d.setFullYear(oYear.options[oYear.options.length - 1].value, oMonth.options[oMonth.options.length - 1].value - 1, oDay.options[oDay.options.length - 1].value);
	document.DateChooser.setLatestDate(d);		
	
	// If a date is already chosen then set it into the calendar.
	if (oYear.options[oYear.selectedIndex].value.length != 0 && oMonth.options[oMonth.selectedIndex].value.length != 0 && oDay.options[oDay.selectedIndex].value.length != 0)
	{
	    d.setFullYear(oYear.options[oYear.selectedIndex].value, oMonth.options[oMonth.selectedIndex].value - 1, oDay.options[oDay.selectedIndex].value);
		document.DateChooser.setSelectedDate(d);
	}
	
	// The update function just invokes validation on the date field.
	document.DateChooser.setUpdateFunction(fnDateChosen);
	
	// Create dummy eventargs object to tell the date picker the link target for positioning calendar.
	var e = new Object();
	e.target = oLink;
	document.DateChooser.display(e);
	
	// Don't follow the link
	return false;
}

/**
 * Fires after a date has been chosen. 
 * We use it to run the validation on this field.
 */
function fnDateChosen (date, fields) {
	for(stuff in fields) {
		var ddl = document.getElementById(stuff);
		if (ddl != null) {
			if (ddl.onblur) {
				ddl.onblur();
			}
		}
	}
}
