//---------------------------------------------------------------------
// WAF - Web/Windows Application Framework
// Copyright © 2010 The Enticy Group, LLC
//
// Notes: Miscellaneous WAF Javascript functions
//
// Revisions :
//	2003-07-08	Conrad	Added ScrollAndFocus()
//	2005-08-24	Conrad	Made "constants" of URLPARM_*
//	2005-09-05	Conrad	Added front-end adding/deleting of child table rows
//	2006-02-14	Conrad	Pulled out ERROR_MESSAGE[] and WINDOW_STYLE[] constants
//	2007-09-07	Conrad	Added putValueInIFrame()
//	2009-10-14	Roopa	Added JQuery code for handling collapse/expand of child tables.
//---------------------------------------------------------------------

// We want to use "const" but IE6's version of JavaScript can't handle it
var URLPARM_ACTION = '_act';
var URLPARM_FKEYENTRY = '_fke';
var URLPARM_CHANGEDFIELDNAME = '_cfn';

var ERROR_MESSAGE = new Array();
ERROR_MESSAGE['NOMOREROWS'] = 'Cannot add any more rows.';

var WINDOW_STYLE = new Array();
WINDOW_STYLE['POPUP'] = 'width=800,height=420,resizable=yes,scrollbars=yes,status=yes';
WINDOW_STYLE['AUTOCOMPLETE'] = 'height=150,width=200,status=no,resizable=yes,toolbar=no,menubar=no,directories=no,location=no,scrollbars=no';
WINDOW_STYLE['HELP'] = 'width=613,height=400,resizable=yes,scrollbars=yes';
WINDOW_STYLE['EMAIL'] = 'width=700,height=500,resizable=yes,scrollbars=yes,status=yes,menu=yes';
WINDOW_STYLE['PRINT'] = 'width=700,height=500,resizable=yes,scrollbars=yes,status=yes,menu=yes';
WINDOW_STYLE['ANYPOPUPDEFAULT'] = 'width=600,height=400,status=no,resizable=no,toolbar=no,menubar=no,directories=no,location=no,scrollbars=no';

// This function is used by foreign keys to call the popup form
function FKPopup(href, field, displayfield) {
	if (field.type == 'text') {
		if (field.value != displayfield.value) href += '&' + URLPARM_FKEYENTRY + '=' + field.value;
	}
	EditPopup(href);
}

// This function is used to call the popup form
function EditPopup(href) {
	var hWnd = window.open(href, '', WINDOW_STYLE['POPUP']);
	if ((document.window != null) && (!hWnd.opener)) hWnd.opener = document.window;
	if (window.focus) hWnd.window.focus();
}

// This function is called to put a value into a foreign key field
function FKUpdate(inputfield, displayfield, valuefield, keyvalue, displayvalue) {
	FieldUpdate(inputfield, displayvalue, displayvalue);
	FieldUpdate(displayfield, displayvalue, displayvalue);
	FieldUpdate(valuefield, keyvalue, displayvalue);
}

// This function is called to put a value into any field
function FieldUpdate(field, value, displayvalue) {
	if (field) {
		if (field.type == 'text') {
			field.value = value;
		} else if (field.type == 'hidden') {
			field.value = value;
		} else {
			// Loop through the existing options trying to find the given key
			var bOptionFound = false;
			for (var i = 0; i < field.length; i++) {
				if (field.options[i].value == value) {
					field.options[i].selected = true;
					bOptionFound = true;
				}
			}
			// If we didn't find it, then we need to add a new one.
			if (!bOptionFound) {
				var oOption = new Option(displayvalue, value, true, true);
				field.options[field.length] = oOption;
			}
		}
	}
}

// This function is called to put data into a valid value field
function VVSet(field, value) {
	if ((field.type == 'text') || (field.type == 'hidden')) {
		field.value = value;
	} else if (field.type == 'select-one') {
		// Loop through the existing options trying to find the given value
		var bOptionFound = false;
		for (var i = 0; i < field.length; i++) {
			if (field.options[i].value == value) {
				field.options[i].selected = true;
				bOptionFound = true;
			}
		}
		// If we didn't find it, then we need to add a new one.
		if (!bOptionFound) {
			var oOption = new Option(value, value, true, true);
			field.options[field.length] = oOption;
		}
	} else {
		// radio buttons
		for (var i = 0; i < field.length; i++) {
			if (field[i].value == value) {
				field[i].checked = true;
			}
		}
	}
}

// This function is called to put data into a valid value field
function VVCopy(tofield, fromfield) {
	if ((fromfield.type == 'text') || (fromfield.type == 'hidden') || (fromfield.type == 'select-one')) {
		VVSet(tofield, fromfield.value);
	} else {
		// radio buttons
		for (var i = 0; i < fromfield.length; i++) {
			if (fromfield[i].checked == true) {
				VVSet(tofield, fromfield[i].value);
			}
		}
	}
}

// This function is called to set the value of a Boolean field
function BoolSet(field, value) {
	if ((field.type == 'text') || (field.type == 'hidden')) {
		field.value = value;
	} else {
		// checkbox
		if (field.value == value) {
			if (!field.checked) {
				// Execute the click(), rather than just changing field.checked.  That way, any event handlers are called.
				field.click();
				//field.checked = true;
			}
		} else {
			if (field.checked) {
				field.click();
				//field.checked = false;
			}
		}
	}
}

// This function is called to copy data between Boolean fields
function BoolCopy(tofield, fromfield) {
	if ((fromfield.type == 'text') || (fromfield.type == 'hidden')) {
		BoolSet(tofield, fromfield.value);
	} else {
		// fromfield is a checkbox
		if (fromfield.checked) {
			BoolSet(tofield, fromfield.value);
		} else {
			BoolSet(tofield, 0);
		}
	}
}

// This function is called for each keydown in a foreign key
function FKKeydownHandler(event, fnAutocomplete, fnChoice, fnNew, fnNavigate) {
	// gets the code for NS or IE
	var keycode = event.keyCode ? event.keyCode :
                event.which ? event.which : event.charCode;
	// We've chosen "Tab" as the autocomplete character, 
	// F2 for choice, F3 for navigate, and F4 for new
	if (keycode == 9 && fnAutocomplete) {
		fnAutocomplete();
		return false;
	} else if (event.keyCode == 113 && fnChoice) {
		fnChoice();
		cancelEvent(event);
		return false;
	} else if (event.keyCode == 114 && fnNavigate) {
		fnNavigate();
		cancelEvent(event);
		return false;
	} else if (event.keyCode == 115 && fnNew) {
		fnNew();
		cancelEvent(event);
		return false;
	} else {
		return true;
	}
}

function cancelEvent(event) {
	if (event.which) {
		// Mozilla 1.3 required to get rid of processing of F3 key
		needToCancelFunctionKey = true;
	} else {
		// IE 6.0 Required to get rid of processing of F3 key
		event.keyCode = 0;
		event.returnValue = false;
	}
}


// This function invokes the autocomplete function by popping up a
// window which will put the value back into the given field.
function FKAutocomplete(field, displayfield, parms) {
	if (field.type == 'text') {
		if (field.value != '' && field.value != displayfield.value) {
			var href = 'WAFPopup.aspx?' + URLPARM_ACTION + '=Autocomplete&' + parms + '&' + URLPARM_FKEYENTRY + '=' + field.value;
			var windowname = '_blank';
			window.open(href, windowname, WINDOW_STYLE['AUTOCOMPLETE']);
		}
	}
}

// This utility function opens a help window
function ShowHelp(url) {
	var hWnd = window.open(url, 'HelpWindow', WINDOW_STYLE['HELP']);
	if (window.focus) hWnd.window.focus();
}

// This function is used to call the email popup window 
function EmailPopup(href) {
	var hWnd = window.open(href, '', WINDOW_STYLE['EMAIL']);
	if (window.focus) hWnd.window.focus();
}

// This function is used to call the print popup window 
function PrintPopup(href) {
	var hWnd = window.open(href, '', WINDOW_STYLE['PRINT']);
	if (window.focus) hWnd.window.focus();
}

// This function is used to popup any window 
function AnyPopup(href, name, windowStyles) {
	if (!name) name = '_blank';
	if (!windowStyles) windowStyles = WINDOW_STYLE['ANYPOPUPDEFAULT'];
	var hWnd = window.open(href, name, windowStyles);
	if (window.focus) hWnd.window.focus();
}

// Trigger the print dialog 
function PrintPage() {
	if (window.print) {
		self.focus();
		self.print();
	}
}

// Functions to support page scrolling and item positioning. Used in handling ReDisplay.
// From http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
function getScrollXY() {
	var horizontalScroll = 0, verticalScroll = 0;
	if (typeof (window.pageYOffset) == 'number') {
		//Netscape compliant
		verticalScroll = window.pageYOffset;
		horizontalScroll = window.pageXOffset;
	} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
		//DOM compliant
		verticalScroll = document.body.scrollTop;
		horizontalScroll = document.body.scrollLeft;
	} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
		//IE6 standards compliant mode
		verticalScroll = document.documentElement.scrollTop;
		horizontalScroll = document.documentElement.scrollLeft;
	}
	return [horizontalScroll, verticalScroll];
}

// From http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
function getSizeXY() {
	var viewPortWidth = 0, viewPortHeight = 0;
	if (typeof (window.innerWidth) == 'number') {
		//Non-IE
		viewPortWidth = window.innerWidth;
		viewPortHeight = window.innerHeight;
	} else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
		//IE 6+ in 'standards compliant mode'
		viewPortWidth = document.documentElement.clientWidth;
		viewPortHeight = document.documentElement.clientHeight;
	} else if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
		//IE 4 compatible
		viewPortWidth = document.body.clientWidth;
		viewPortHeight = document.body.clientHeight;
	}
	return [viewPortWidth, viewPortHeight];
}

// Function invoked on dropdown option change to re-display a form.
// Submits the form with added values to the form action to specify 
// the action and identify the field
function ReDisplayForm(field) {

	// We can only redisplay a form if the field is in a form to begin with.
	if (field.form != null) {
		var ActionURL = field.form.action;
		var addUrl = URLPARM_ACTION + '=ReDisplay&' + URLPARM_CHANGEDFIELDNAME + '=' + field.name + ',' + getScrollXY()[0] + ',' + getScrollXY()[1];

		// Make sure we didn't already add the ReDisplay action.
		// The change event can arrive fast, this will prevent re-entry.
		if (ActionURL.indexOf(URLPARM_ACTION + '=ReDisplay') > 0)
			return false;

		if (ActionURL.indexOf('?') > 0)
			ActionURL += '&' + addUrl;
		else
			ActionURL += '?' + addUrl;

		field.form.action = ActionURL;
		field.form.submit();
	}

	return false;
}

// Called after ReDisplay, this function is used to scroll the 
// page back to the same position from before the redisplay and
// set focus back to the field which triggered the redisplay.
function ScrollAndFocus(field, horizontalScroll, verticalScroll) {
	if (field) {
		window.scrollTo(horizontalScroll, verticalScroll);

		if (field.type != 'hidden') {
			if (field.focus) {
				field.focus();
			}
		}
	}
}

/* Not yet ready for prime-time
// This function is called to submit a given form to a given URL.
// It us used this way: <a href="foo" onclick="return doActionLink('form_id', this.href, 0);">Submit</a>
function doActionLink(formId, href, bPopup) {
// Although a GET can go to an unnamed URL, a POST cannot. (It would generate a 405 error.)
// (You could also get a 405 error if you were trying to POST to an ".html" page.)
if (href.substring(0,1) == '?') {
var sPath = window.location.pathname;
href = sPath.substring(sPath.lastIndexOf('/') + 1) + href;
}
if (bPopup == 1) {
href = 'javascript:ShowHelp(\'' + href + '\')' 
}
//alert(href);
document.forms[formid].action = href; 
document.forms[formid].submit(); 
return false;
}
*/

// This function is called to visually mark a row as deleted.  The actual deleting is not done here.
function toggleRowDeleted(row) {
	toggleClassName(row, 'deleted');
};

// This function finds the first row in a table that is classed with "hidden" and changes it to normal.
function unhideRow(table) {
	toggleNextRow(table, 'hidden', ERROR_MESSAGE['NOMOREROWS']);
}

// This function will toggle the classname of an object (or add the second class if both are missing)
function toggleClassName(e, cn) {
	if (containsToken(e.className, cn, ' ')) {
		e.className = removeToken(e.className, cn, ' ');
	} else {
		e.className = addToken(e.className, cn, ' ');
	}
}

// This function finds the first row in a table that has a given class and changes it to another class.
// If it finds no such row, it can give the user an alert.
function toggleNextRow(table, cls, msg) {
	var rows = table.getElementsByTagName('tbody')[0].getElementsByTagName('tr');
	for (var i = 0; rows[i] != null; i++) {
		if (containsToken(rows[i].className, cls, ' ')) {
			rows[i].className = removeToken(rows[i].className, cls, ' ');
			break;
		}
	}
	if (rows[i] == null) {
		if (msg != null) alert(msg);
	}
}

function containsToken(str, tok, delim) {
	return (delim + notNull(str) + delim).indexOf(delim + tok + delim) != -1
}

function addToken(str, tok, delim) {
	if (containsToken(str, tok, delim)) {
		return str;
	} else {
		if (notNull(str) == '') {
			return tok;
		} else {
			return str + delim + tok;
		}
	}
}

function removeToken(str, tok, delim) {
	var tempstr = delim + notNull(str) + delim;
	tempstr = tempstr.replace(delim + tok + delim, delim);
	return tempstr.substring(delim.length, tempstr.length - 2 * delim.length + 1);
}

function notNull(str) {
	if (str == null) {
		return '';
	} else {
		return str;
	}
}

// Used to write an HTML value into an IFRAME (for HTML_VIEW_IN_IFRAME fields)
function putValueInIFrame(iframe, html) {
	var oDoc;
	if (document.frames) {
		// Non-standard, but most compatible method -- uses object's NAME
		oDoc = document.frames[iframe].document;
	} else {
		// Standards-compliant method -- uses object's ID
		oDoc = document.getElementById(iframe).contentDocument;
	}
	try {
		oDoc.open();
		oDoc.write(html);
		oDoc.close();
	} catch (e) {
		//alert(ERROR_MESSAGE['IFRAMEWRITEFAILED']);
	}
}

// shows "processing..." instead of specified button/div/span
// NOTE: function expects fully-qualified jQuery expression to match elements:
//		* div -- to match all <div> elements
//		* div.abc -- to match all <div class="abc"> elements
//		* #xyz -- to match all elements with id="xyz"
function actionDisplayProcessing(hide, show, animationImgId) {
	$(hide).hide();
	$(show).show();

	// re-animate image
	// (reset image source to display animated image vs. greyed-out/no-image -- needed for some browsers, especially IE)
	var code = "var img = document.getElementById('" + animationImgId + "'); if(img){ img.src = img.src; }";
	setTimeout(code, 100);

	return true;
}

// jQuery Validate integration - Adds jQuery handlers for forms which request validation.
//if (window.$) {
//	$(document).ready(function() {
//		// Apply validation to all forms marked that way.
//		$("form.validated").validate({
//			errorClass: "InError",
//			errorElement: "div"
//		});
//	});
//}

// jQuery UI integration - Adds jQuery handlers for various UI elements after document loads.
if (window.$) {
	$(document).ready(function() {
		// Apply datepicker functionality to all requested date fields.
		var i = $("input.ShowDateChoice");
		if (i.datepicker) {
			i.datepicker({
				showButtonPanel: true, // add a "done" button that you can click to *not* pick a date
				changeMonth: true, // add a drop-down for the month
				changeYear: true, // add a drop-down for the year
				showOn: 'button', // 'focus', 'button', or 'both': 'button' adds a button after the field
				buttonImage: 'waf/images/calendar.png', // the images to display if we are adding a button to click on to activate the calendar
				buttonImageOnly: true, // true makes the button be an image only, not an bordered button
				buttonText: 'pick a date', // hover text on the "choose" button
				duration: 0, // milliseconds, display immediately
				yearRange: '-100:+20', // show a broad range of years
				constrainInput: false // allow the user to type in the field without validation (allows for entering time)
			});
		}
		// Apply child table collapse/expand to all requested child tables.
		$("a.CollapseLink").click(function() {
			// Show or hide the child table, with an effect
			// Note: this still depends on the structure that the child table DIV follows the secondary title DIV.  Should be fixed.
			$(this).parent().next(".Collapsible").slideToggle("normal").toggleClass("Collapsed");
			$(this).parent().toggleClass("Collapsed");
			// Look for the next collapse state input and toggle it.
			$(this).siblings("input.collapsestate:first").each(function(idx) { $(this).val(3 - $(this).val()); } );
			// Returns false so that the click does not navigate to the href. 
			return false;
		});
		// Child table "Add new row" functionality.
		$("a.NewRow").click(function() {
			// Expand the child table if it is collapsed.
			if ($(this).parent().hasClass("Collapsed")) {
				$(this).parent().next(".Collapsible").slideToggle("normal").toggleClass("Collapsed");
				$(this).parent().toggleClass("Collapsed");
			}
			// Need to store the row in a variable, so we can complain if no more rows can be added.
			var h = $(this).parent().next().find("table.RecordTable tr.hidden:first");
			if ($(h).length)
				$(h).removeClass("hidden");
			else
				alert(ERROR_MESSAGE['NOMOREROWS']);
			return false;
		});
	});
}
/* 
Applications can override this default datepicker settings by changing styles and adding jQuery code.
Example: to show a calendar button on the right of the field and only show the datepicker on button click,
override the style for datecontrol to not display a background image, 
and add the following jscript:
		
$.datepicker.setDefaults({
showOn: 'button',
buttonImageOnly: true,
buttonImage: 'waf/images/calendar.png',
buttonText: 'pick a date'
});
*/
