/************************************************************************
 TEUtilities.js
 jpl 5/31/05
 
	Suite of general purpose JavaScript functions
	
	Data Validation:
		boolean	isInteger(stringValue)
		boolean	isPositiveInteger(stringValue)
		boolean	isNumeric(stringValue)
		boolean	isDate(stringValue)
		boolean	isValidEmailAddress(stringValue)
		boolean	isValidDomainName(stringValue)
	
	String Manipulation:
		int		countInStringMatches(theString, theTarget)
	
	Cookie Interaction:
		String	GetCookie(name)
		SetCookie(name, value)
	
	Window Opening:
		OpenWindow(URL, windowName, width, height,
				   horizontalPosition, verticalPosition)
	
	
	HTML Generation:
		writePaging(theSpan, clickAction, currentPage, totalPages, options)
	
************************************************************************/


function properInt(theValue, badReturnValue) {
	if(isInteger(theValue + ''))
		return parseInt(theValue, 10);
	else
		return badReturnValue;
}
function properNumber(theValue, badReturnValue) {
	if(isNumeric(theValue + ''))
		return parseFloat(theValue);
	else
		return badReturnValue;
}

function isInteger(stringValue) {
	return stringValue.match(/^-?\d+$/);
}

function isPositiveInteger(stringValue) {
	return (stringValue.match(/^\d+$/)  &&  !stringValue.match(/^0+$/));
}

function isNonNegativeInteger(stringValue) {
	return stringValue.match(/^\d+$/);
}

function isNumeric(stringValue) {
	return stringValue.match(/^[-+]?[0-9]*\.?[0-9]+$/);
}

function isPositiveNumeric(stringValue) {
	return stringValue.match(/^\d+(\.\d+)?$/);
}

function isValidEmailAddress(stringValue) {
	return stringValue.match(/^(\w|-|_|\.)+@(\w|-|_|\.){2,}\.\w{2,5}$/)
}

function isValidDomainName(stringValue) {
	return stringValue.match(/(\w|-|_|\.){3,}\.\w{2,5}$/)
}


	function countInStringMatches(theString, theTarget) {
		
		var index = 0;
		var findCount = 0;
		while (index >= 0) {
			index = theString.indexOf(theTarget, index)
			if (index >= 0) {
				findCount++;
				index++;
			}
		}
		return findCount;
	}
	
	
	function reverse(string){
		returnString = '';
		for (i = string.length; i >= 0; i--)
			returnString += string.charAt(i);
		return returnString;
	}

	// left is just a rename of substring()
	function left(string, count){
		return string.substring(0, count);
	}

	// right actually uses reverse() and left()
	function right(string, count){
		return reverse(left(reverse(string), count));
	}


	function rtrim(string) {
		return string.replace(/\s+$/,'');
	}
	function ltrim(string){
		return string.replace(/^\s+/,'');
	}
	function trim(string){
		return ltrim(rtrim(string));
	}
	
	function ucase(string){
		return string.toUpperCase();
	}
	function lcase(string){
		return string.toLowerCase();
	}

/**
 * DHTML date validation script. Courtesy of SmartWebby.com (http://www.smartwebby.com/dhtml/)
 *
 * Modified 12/20/2003 by John Larson to allow MM/DD and MM/DD/YY format in addition to
 * MM/DD/YYYY already implemented.
 */
function stripCharsInBag(s, bag){
	var i;
    var returnString = "";
    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.
    for (i = 0; i < s.length; i++){   
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) returnString += c;
    }
    return returnString;
}

function extractCharsInBag(s, bag){
	var i;
    var returnString = "";
    // Search through string's characters one by one.
    // If character is in bag, append to returnString.
    for (i = 0; i < s.length; i++){   
        var c = s.charAt(i);
        if (bag.indexOf(c) != -1) returnString += c;
    }
    return returnString;
}

function daysInFebruary (year){
	// February has 29 days in any year evenly divisible by four,
    // EXCEPT for centurial years which are not also divisible by 400.
    return (((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0))) ? 29 : 28 );
}

function isDate(dtStr){
	var daysInMonth = Array(0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
	var pos1=dtStr.indexOf("/")
	var pos2=dtStr.indexOf("/",pos1+1)
	var strMonth=dtStr.substring(0,pos1)
	var strDay=dtStr.substring(pos1+1,pos2)
	var strYear=dtStr.substring(pos2+1)

	var strTodaysYear = new String(new Date().getFullYear());
	if (pos2 < 0) // no year given, so assume this year
		strYr = strTodaysYear;
	else if (strYear.length == 2) // assume only last two digits given, so append first two
		strYr = strTodaysYear.substring(0, 2) + strYear;
	else if (strYear.length == 4) // standard format.
		strYr=strYear
	else
		return false;  // bad year

	if (strDay.charAt(0)=="0" && strDay.length>1) strDay=strDay.substring(1)
	if (strMonth.charAt(0)=="0" && strMonth.length>1) strMonth=strMonth.substring(1)
	for (var i = 1; i <= 3; i++) {
		if (strYr.charAt(0)=="0" && strYr.length>1) strYr=strYr.substring(1)
	}
	month=parseInt(strMonth)
	day=parseInt(strDay)
	year=parseInt(strYr)

	if (pos1==-1){
		//alert("The date format should be : mm/dd/yyyy")
		return false
	}
	if (strMonth.length<1 || month<1 || month>12){
		//alert("Please enter a valid month")
		return false
	}
	if (strDay.length<1 || day<1 || 
      (month==2 && day>daysInFebruary(year)) || day > daysInMonth[month]){
		//alert("Please enter a valid day")
		return false
	}
	
	if (!isInteger(stripCharsInBag(dtStr, "/"))) {
		alert("Please enter a valid date")
		return false
	}
	return true
}


function isDate(dtStr) {
	var daysInMonth = Array(0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	
	var dateParts = dtStr.split('/');
	if(dateParts.length < 2)
		return false;
	
	dbug.log('1');
	// work out the year, allowing for its omission:
	var strTodaysYear = new String(new Date().getFullYear());
	if(dateParts.length == 2)
		strYr = strTodaysYear; // omitted, assume this year
	else {
		strYear = dateParts[2];
		if (strYear.length == 2) // assume only last two digits given, so prepend first two
			strYr = strTodaysYear.substring(0, 2) + strYear;
		else if (strYear.length == 4) // standard format.
			strYr = strYear
		else
			return false;  // bad year
	}
	dbug.log('2');
	var theYear	= properInt(strYr, "nan")
	if(theYear == "nan")
		return false;
	
	dbug.log('3');
	var theMonth, theDay;
	switch(Date.$culture) {
		case 'GB':
			theMonth	= properInt(dateParts[1], 0);
			theDay		= properInt(dateParts[0], 0);
			break;
		default:
			theMonth	= properInt(dateParts[0], 0);
			theDay		= properInt(dateParts[1], 0);
	}
	
	if (theMonth < 1  ||  theMonth > 12)
		return false
	dbug.log('4');
	
	if (theDay < 1  || 
       (theMonth==2 && theDay > daysInFebruary(theYear)) || theDay > daysInMonth[theMonth])
		return false
	
	dbug.log('5');
	return true;
}


/*******/









	
	function tidyPhoneNumber(textInput) {
		with (textInput) {
		  if (value != "") {
		    if (value.indexOf("x") == -1) {
				rawNumber = value;
				rawExtension = ""
			}
			else {  // we'll strip off the extension portion
				rawNumber    = value.substring(0, value.indexOf("x"));
				rawExtension = value.substring(value.indexOf("x"));
			}
			
			// let's now get the numerals from the number:
			rawDigits = extractCharsInBag(rawNumber, "0123456789");
			
			// Strip off a leading one if present:
			if (rawDigits.charAt(0) == '1')
				rawDigits = rawDigits.substring(1);
				
			// Now we expect the number to have 10 digits.
			if (rawDigits.length == 10)  // we can put it into the format (xxx) xxx-xxxx
				phoneNumber =  "(" + rawDigits.substring(0, 3) + ") " +
				               rawDigits.substring(3, 6) + "-" + rawDigits.substring(6, 10);
			else // we'll not mess around with it
				phoneNumber = rawNumber;
			
			// Now let's tend to the extension:
			extension = extractCharsInBag(rawExtension, "0123456789");
			if (extension.length > 0)
				extension = " x" + extension;
				
			// Both parts done, so let's set the value with our result:
			value = phoneNumber + extension;
		  }
		}
	}
	
	
	function isValidCCNumber(CCNumber) {
		if (CCNumber.length > 19  ||  CCNumber.length < 13)
			return (false);
	
		sum = 0; mul = 1; l = CCNumber.length;
		for (i = 0; i < l; i++) {
			digit = CCNumber.substring(l-i-1,l-i);
			tproduct = parseInt(digit, 10)*mul;
			if (tproduct >= 10)
				sum += (tproduct % 10) + 1;
			else
				sum += tproduct;
			if (mul == 1)
				mul++;
			else
				mul--;
		}
	
		return ((sum % 10) == 0);
	}
	
	function tidyCCNumber(CCNumber) {
		return extractCharsInBag(CCNumber, "1234567890");
	}
	
	
	
	function toggleEditMode(itemHolderSet, toEdit) {
		
		// Special case: if itemHolderSet is a table, its item holders are the cells:
		if($type(itemHolderSet) == 'element'  &&  itemHolderSet.tagName.toLowerCase() == 'table')
			itemHolderSet = itemHolderSet.getElements('td');
		
		itemHolderSet.each(function(theHolder) {
			if(toEdit) {
				var preEditLabel = $E('span.preEditLabel', theHolder);
				if(preEditLabel)
					swapSections(preEditLabel, $E('span.editControl', theHolder));
			}
			else {
				var editControl = $E('span.editControl', theHolder);
				if(editControl)
					swapSections(editControl, $E('span.preEditLabel', theHolder));
			}
		});
	}
	
	
	function isRadioChoiceMade(radioInput) {
		var result = false;
		if (radioInput.length) {
			for (var i=0; i < radioInput.length; i++) {
				result |= radioInput[i].checked;
			}
		}
		else
			result = radioInput.checked;
		
		return result;
	}
	
	
	function setSelectOptions(theSelect, valueSet, labelSet) {
		theSelect.options.length = 0;
		if(!labelSet)
			labelSet = valueSet;
		
		for(var i=0; i < valueSet.length; i++)
			if(labelSet[i].length > 0)
				theSelect.options.add(new Option(labelSet[i], valueSet[i]));
	}

	
	
	function handleDateScrolling(dateInput, e) {
	
		var key = (window.Event) ? e.which : e.keyCode;
		if(isDate(dateInput.value)) {
			switch(key) {
				case 38: // up
				    var d = new Date(dateInput.value);
				    d.setDate(d.getDate() + 1);
				    dateInput.value = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
					break;
				
				case 40: // down
				    var d = new Date(dateInput.value);
				    d.setDate(d.getDate() - 1);
				    dateInput.value = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
					break;
			}
		}
	}
	
	
	function swapSections(oldSection, newSection, duration) {
		
		oldSection = $(oldSection);
		newSection = $(newSection);
		
		if(!duration)
			duration = 200;
		
		if(newSection.style.display == 'none') { // only swap if not already swapped!
			var oldSectionFx = oldSection.get('tween', { property : 'opacity', duration : duration });
			var newSectionFx = newSection.get('tween', { property : 'opacity', duration : duration });
			oldSectionFx.start(1,0).chain(function() {
				newSection.style.visibility = 'hidden';
				oldSection.style.display = 'none';
				newSection.style.display = '';
				newSectionFx.start(0, 1);
			});
		}
	}
	
	
	function getQueryStringOfFormElements(formElements) {
		
		var queryString = [];
		formElements.each(function(el){
			var name = el.name;
			var value = el.getValue();
			if (value === false || !name || el.disabled) return;
			var qs = function(val){
				queryString.push(name + '=' + encodeURIComponent(val));
			};
			if ($type(value) == 'array') value.each(qs);
			else qs(value);
		});
		return queryString.join('&');
	}

	
	function switchSelectToFreeStyle(theSelect) {
		if(theSelect.selectedIndex == theSelect.options.length-1) {
			var newInput = new Element('input');
			newInput.type = 'text';
			newInput.className = theSelect.className;
			newInput.name = theSelect.name;
			theSelect.replaceWith(newInput);
			newInput.setStyle('width', parseInt(theSelect.getStyle('width')) + (
				parseInt(theSelect.getStyle('padding-left')) +
				parseInt(theSelect.getStyle('padding-right'))) - (
				parseInt(newInput.getStyle('padding-left')) +
				parseInt(newInput.getStyle('padding-right'))) -2 + 'px');
			dbug.log(theSelect.getStyle('width'));
			dbug.log(newInput.getStyle('width'));
			newInput.focus();
			return newInput;
		}
	}
	
	
	function swapToHoverSrc(theImage) {
		if(theImage.src.indexOf('_on') == -1)
			theImage.src = theImage.src.replace(/.gif$/, '_on.gif');
	}
	function swapFromHoverSrc(theImage) {
		theImage.src = theImage.src.replace(/_on.gif$/, '.gif');
	}
		
		
	
var ObjectRange = new Class({
	initialize: function(start, end, exclusive) {
		this.start = start;
		this.end = end;
		this.exclusive = exclusive;
	},

	each: function(iterator) {
		var value = this.start;
		while (this.include(value)) {
			iterator(value);
			value = value.succ();
		}
	},

	include: function(value) {
		if (value < this.start)
			return false;
		if (this.exclusive)
			return value < this.end;
		return value <= this.end;
	}
});

var $R = function(start, end, exclusive) {
	return new ObjectRange(start, end, exclusive);
};

	
	function currentDirectoryURL() {
		return location.href.substring(0, location.href.lastIndexOf('/'));
	}
	function currentDirectorySecureURL(SSLIsAvailable) {
		var result = location.href.substring(0, location.href.lastIndexOf('/'));
		if(SSLIsAvailable)
			return result.replace('http://', 'https://');
		else
			return result;
	}


	function countNodes(element) {
		var children = $(element).getChildren();
		var result = children.length;
		children.each(function(theElement) {
			result += countNodes(theElement);
		});
		return result;
	}
	

/* Sans-mootools, univeral function:
function countNodes(element) {
	var children = element.childNodes;
	var result = children.length;
    for(var i=0; i< children.length; i++) {
    	result += countNodes(children[i]);
    }
	return result;
}
countNodes(document.body);
*/

