/* 
* Name:
*	html_element_search.js
*
* Description:
*	Library of genericized JavaScript functions for general-purpose work.
*
* Pre-conditions:
*	None
*
* Post-conditions:
*	Defines the following functions:
*		isIntertechIframe				Is the given document object the src of an Intertech iframe?
*		getAllFrames					Return an array of all frames and iframes from a point in the frame hierarchy.
*		getRelatedElements				Get an HTML element array where IDs or classes match a regex. Can search all (i)frames.
*
* Log:
*	Randall Betta		08/23/2006
*		- Creation
*	Randall Betta		10/10/2006
*		- Fixed a bug in getRelatedElements() that prevented searches confined to one frame from working.
*
*/


/*
* Name:
*	isIntertechIframe
*
* Description:
*	Returns true if the given document comprises the contents of an iframe built using Intertech
*	functions.
*	
* Pre-conditions:
*	docObject		REQUIRED	The HTML DOM "document" object to test.
*
* Post-conditions:
*	A boolean value: true if the given document comprises the contents of an Intertech iframe.
*
* Log:
*	Randall Betta		08/23/2006
*		- Creation
*
*/
function isIntertechIframe(docObj) {
	var docUrl;
	var iframeRegex;
	
	// Obtain the URL of the current document.
	docUrl = docObj.URL;
	
	// Define a regex which will determine if the current page resides in the cached iframe directory.
	// This regex will work even if multiple question marks appear in the query string.
	iframeRegex = '([^?])*[/]pages[/]iframe[/]([0-9])+[.]php([?](.)*)*$';
	
	// Decide if this page is an iframe cache file.
	return docUrl.match(iframeRegex);

} // End function: isIntertechIframe






/*
* Name:
*	getAllFrames
*
* Description:
*	Returns an array of window elements of all (grand)child iframe and frame HTML elements 
*	in the given window, including itself. This function is recursive. Note that a window is 
*	the same as an (i)frame in JavaScript.
*	
* Pre-conditions:
*	windowObj		REQUIRED	The topmost window object to include in the array.
*
* Post-conditions:
*	An array of references to HTML (i)frame tags that exist inside the given window.
*
* Log:
*	Randall Betta		08/24/2006
*		- Creation
*
*/
function getAllFrames(windowObj) {

	var windowFrames;			// All frames in the current window object.
	var allWindows;				// An array of all framed window objects to return.
	var childFrames;			// All descendant (i)frames.
	var currentWindow;			// A temporary variable for storing an (i)frame's window object.
	var frameIndex;				// Counter variable.
	var childIndex;				// Counter variable.

	// Initialize the array that will store the windows of (i)frames.
	allWindows = new Array();

	// Determine if this document has any frames. If not, return an empty array.
	if ((windowObj.frames) ? windowObj.frames.length > 0 : false) { // If: this window has frames.
		// Obtain all iframe elements in this window using the javascript frames array. Note that 
		// this will include ordinary frames too, though this is not relevant for our purposes.
		windowFrames = windowObj.frames;

		// Iterate through (i)frames in this window.
		for (frameIndex = 0; frameIndex < windowFrames.length; frameIndex++) { // For: iterate through frames.
		
			// Store the current iframe's window object in this iteration.
			currentWindow = windowFrames[frameIndex];
			
			// Obtain an array of all descendant (i)frames inside the child (i)frame, plus itself.
			allWindows = allWindows.concat(getAllFrames(currentWindow));	

		} // End for: iterate through (i)frames.
		
	} // End if: this window contains (i)frames.
	
	// Store this window itself in the returned array of window objects.
	allWindows[allWindows.length] = windowObj;
	
	return allWindows;
	
} // End function: getAllFrames









/*
* Name:
*	getRelatedElements
*
* Description:
*	Returns an array of all HTML elements of the same type whose class or id property matches
*	a given regex. This function will optionally search the entire iframe hierarchy up and down, 
*	including any pages not generated by Intertech functions.
*	
* Pre-conditions:
*	htmlElement		REQUIRED	Case-sensitive string of what kinds of HTML elements to search (e.g. "div").
*	pattern			REQUIRED	The regex to use to decide whether to return an element.
*	useId			REQUIRED	Boolean: if true, match the HTML id against the regex. If false, use class.
*	searchAllFrames	REQUIRED	Boolean: if true, traverse all (i)frames.
*
* Post-conditions:
*	An array of references to HTML tags whose id or class properties match the regex is returned.
*
* Log:
*	Randall Betta		08/23/2006
*		- Creation
*	Randall Betta		10/10/2006
*		- Fixed a bug that prevented searches confined to only one frame from working.
*
*/
function getRelatedElements(htmlElement, pattern, useId, searchAllFrames) { 

	var docObj;				// A temporary variable: HTML DOM "document" object.
	var winIndex;			// A counter for the current window.
	var htmlElts;			// An array of references to HTML elements.
	var elt;				// A temporary variable: reference to an HTML element.
	var eltIndex;			// A counter for the current elt.
	var matchingElts;		// The returned array of references to matching HTML elements.
	var eltText;			// The text of the HTML element property to compare against the pattern.
	var searchWindows;		// An array of all HTML DOM "window" objects to search.
	var thisDocFound;		// A boolean: used when 
	
	// Initialize the matching elements array.
	matchingElts = new Array();
	
	// Determine whether we need to search this document or all (i)framed documents.
	if (searchAllFrames) { // If: search all frames.
		// Obtain references to all frames.
		searchWindows = getAllFrames(top);		
	}
	else { // Else: search only this document.
		searchWindows = new Array();
		searchWindows[0] = window;
	} // End else: search only this document,
	
	
	// Iterate through all documents to be searched.
	for (winIndex = 0; winIndex < searchWindows.length; winIndex++) { // For: iterate through windows to search in.
		try {
			// Store a reference to the current document object.
			docObj = searchWindows[winIndex].document;
			// Obtain an array of all HTML elements of the desired type in the current document object.
			htmlElts = docObj.getElementsByTagName(htmlElement);
		}
		catch (exc) {
			// Permission will be denied to access elements on a page from a different domain.
			// Silently skip this document if this error occurs.
			continue;
		}
		
		// Iterate through the HTML elements.
		for (eltIndex = 0; eltIndex < htmlElts.length; eltIndex++) { // For: iterate through HTML elements.
			try {
				// Store a reference to the current HTML element.
				elt = htmlElts[eltIndex];
				// Determine if this element is part of the set we are looking for.
				if (useId) { // If: the match criterion is the HTML element ID property.
					eltText = (elt.id) ? elt.id.toString() : '';
				}
				else { // Else: the match criterion is the HTML element CSS class property.
					eltText = (elt.className) ? elt.className.toString() : '';
				} // End else: the match criterion is the HTML element CSS class property.
				
				// Test whether the class or ID property (as appropriate) matches the regex.
				if (eltText.match(pattern)) { // If: the property matches the regex.
					// Append this element to the array.
					matchingElts[matchingElts.length] = elt;
				} // End if: the property matches the regex.
			}
			catch (exc) {
				// Permission will be denied to access elements on a page from a different domain.
				// Silently skip this document if this error occurs.
				continue;
			}
			
		} // End for: iterate through HTML elements.
		
	} // End for: iterate through windows to search in.
	
	return matchingElts;

} // End function: getRelatedElements

