/**
 * Copyright Kronos, Inc. All rights reserved. Do not use in any way.
 * Author: dross@kronos.com
 *
 * Utility functions for accessing DOM elements.
 * Functions that end with 'ByFilter' take a function reference which should return true when
 * the given element meets some test determined by the filter function reference. These kinds
 * of functions are useful when you need to operate on the list of elements that are being found
 * by providing a function reference that does the work while also testing which elements to
 * operate on.
 */

/**
 * Toggle, Add or Remove the given className from the given
 * dom.className property.
 * --> To force an Add only, set forceAddOrRemoveOnly to true.
 * --> To force a Remove only, set forceAddOrRemoveOnly to false.
 * For example usage: Used IN the following files:
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\js\com\kronos\dom-utils.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\js\com\kronos\table-rows.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\html_v1\scripts\table.js
	Workspaces\wtk.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wfs\html\scripts\self-scheduling.js
	Workspaces\wtk.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\mss\html\scripts\table.js
	Workspaces\wtk.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\calendar\html\scripts\calendar.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\visuallanguage\button.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\visuallanguage\data-changed-indicator.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\visuallanguage\tabbar.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\visuallanguage\tabular.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\suitenav\scripts\dom-utils.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\suitenav\scripts\suite-nav-menu.js
 */
function tarClassName(dom, className, forceAddOrRemoveOnly){
	if(!dom) return
	var re=new RegExp('(^|[ \t]+)'+norm(className)+'([ \t]+|$)', 'ig')
	var isClass=re.test(dom.className)
	if('undefined'==(''+forceAddOrRemoveOnly)){
		// undefined means toggle current
		forceAddOrRemoveOnly=!isClass
	}
	if(forceAddOrRemoveOnly){
		// true means force add
		add()
	}else{
		// false means force remove
		remove()
	}
	function add(){
		if(!isClass){
			// only add if we need to
			dom.className+=' '+className
		}
	}
	function remove(){
		if(isClass){
			// only remove if we need to
			dom.className=norm(dom.className.replace(re, ' '))
		}
	}
}

/*
 * Given a dom object determine if the className attribute contains the given className value.
 * Supports multi-classname values, like class="Foo Bar Tabular"
 * For example use: see used in files:
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\js\com\kronos\dom-utils.js
	Workspaces\wtk.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wfs\html\scripts\self-scheduling.js
	Workspaces\wtk.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\mss\html\scripts\table.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\visuallanguage\tabbar.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\visuallanguage\data-changed-indicator.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\suitenav\scripts\suite-nav-menu.js
 */
function isClass(dom, className){
	//identifyObj(dom, 'is class '+className+': '+test(dom, className))
	//return test(dom, className)
	//function test(dom, className){
		return (new RegExp('(^|[ \t]+)'+norm(className)+'([ \t]+|$)', 'ig')).test(dom.className)
	//}
}

/*
 * Given a dom object find an ancestor element with the given className. Uses the isCalss function
 * to determine the className.
 * Returns the first element which returns true from the isClass() function.
 * Note: the given dom element is also tested in case it satisfies the isClass() test.
 * For example use: see used in files:
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\visuallanguage\tabbar.js
 */
function getAncestorByClassName(element, className){
	return getAncestorByFilter(element, function(element){return isClass(element, className)})
}

/**
 * Given a dom object and a tagName, find an ancestor element with the given tag name.
 * For example use: see used in files:
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\js\com\kronos\table-rows.js
	Workspaces\wtk.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\mss\html\scripts\table.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\visuallanguage\button.js
 */
function getAncestorByTagName(dom, name){
	var re=new RegExp('(^|\|)'+name+'(\|\$)', 'ig')
	while(dom){
		if(re.test(dom.tagName)){
			return dom
		}
		dom=dom.parentNode
	}
}

/*
 * Given a dom object and a function reference, find an ancestor element for which the function reference returns true. 
 * Uses the function reference function to determine which element to return.
 * Returns the first element for which the function reference returns true.
 * The function reference is invoked with each element in the ancestory including the dom object passed in.
 * Note: the given dom element is also tested in case it satisfies the function reference test.
 * For example use: see used in files:
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\suitenav\scripts\suite-nav-menu.js
 */
function getAncestorByFilter(element, isParentFilter){
	while(element){
		if(isParentFilter(element)){
			return element
		}else{
			element=element.parentNode
		}
	}
}

/*
 * Given a dom object and a function reference, find the elements for which the function reference returns true.
 * @param element The start position of the search
 * @param filter The function reference which will test each element for inclusion
 * @param tagNameOptional The tagName to use to limit the starting search results. Defaults to '*'
 * @param resultArrayOptional The array to append results to. Usefull when aggregating elements from different filters.
 * For example use: see used in files:
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\suitenav\scripts\suite-nav-menu.js 
 */
function getElementsByFilter(element, filter, tagNameOptional, resultArrayOptional){
	var out = (resultArrayOptional? resultArrayOptional: [])
	if(element){
		var array=element.getElementsByTagName((tagNameOptional?tagNameOptional:'*'))
		for(i=0; i<array.length; i++){
			if(filter(array[i], i)){
				out[out.length]=array[i]
			}
		}
	}
	return out
}

/*
 * Given a dom object and a function reference, find the direct children elements for which the function reference returns true.
 * For example use: see used in files:
	Workspaces\wtk.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wfs\html\scripts\self-scheduling.js
 */
function getChildrenByFilter(element, filter){
	var out=new Array()
	var children=(element.children?element.children:element.childNodes)
	for(var i=0; i<children.length; i++){
		if(filter(children[i], i)){
			out[out.length++]=children[i]
		}
	}
	return out
}

function getPreviousSiblingWithSameTagName(element){
	return getPreviousSiblingByFilter(element, filter)
	function filter(previousSibling, element){
		return previousSibling && element && (previousSibling.tagName == element.tagName)
	}
}

function getPreviousSiblingByFilter(element, filter){
	if(element){
		var previousSibling = element.previousSibling
		while(previousSibling){
			if(filter(previousSibling, element)){
				return previousSibling
			}
			previousSibling = previousSibling.previousSibling
		}
	}
	return // undefined
}

function getNextSiblingWithSameTagName(element){
	return getNextSiblingByFilter(element, filter)
	function filter(nextSibling, element){
		return nextSibling && element && (nextSibling.tagName == element.tagName)
	}
}

function getNextSiblingByFilter(element, filter){
	if(element){
		var nextSibling = element.nextSibling
		while(nextSibling){
			if(filter(nextSibling, element)){
				return nextSibling
			}
			nextSibling = nextSibling.nextSibling
		}
	}
	return // undefined
}

function removeAllChildren(dom){
	return getChildrenByFilter(dom, remove)
	function remove(child){
		dom.removeChild(child)
	}
}

/**
 * Given a string of valid HTML code, return a dom instance of that HTML block.
 * For example use: see used in files:
	Workspaces\wtk.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wfso\html\scripts\icon.js
 */
function createElement(str){
	var div=document.createElement('div')
	div.innerHTML=str
	return div.firstChild
}

/*
 * Given a dom object, fieldName, fieldValue, and optional fieldType, find the enclosing
 * form of the dom object and find (or create) the given field.
 @param dom The element for which to find the form (may be the form itself)
 @param fieldName The name of the field to find or create
 @param fieldValue The value of the field to set
 @param fieldTaype The type of field to create if not found. default is hidden.
 */
function findOrCreateFieldForEnclosingForm(dom, fieldName, fieldValue, fieldType){
	var form=getAncestorByTagName(dom, 'FORM')
	if(form){
		var field
		var isCheckbox=(/checkbox/i).test(fieldType)
		if(isCheckbox){
			field=$(fieldName+fieldValue)//form.elements[fieldName+fieldValue]
		}else{
			field=form.elements[fieldName]
		}
		if(!field){
			//info('creating new field for "'+fieldName+'"')
			field=document.createElement('INPUT')
			field.type=(fieldType?fieldType:'hidden')
			field.name=fieldName
			if(isCheckbox){
				field.id=fieldName+fieldValue
			}else{
				field.id=fieldName
			}
			form.appendChild(field)
			if(!form.elements)form.elements[fieldName]=field
		}
		field.value=fieldValue
		return field
	}
}

/*
 Given a dom element and a boolean flag, set the Hover class on the element.
 */
function hover(dom, out){
	//info('hover('+identifyObj(dom)+','+out+')')
	// TODO: make 0==remove, 1== add, currently opposite is true
	tarClassName(dom, 'Hover', !out)
}

/*
 * Given a string, return the string with all white space replaced with a single space. 
 * Also trims leading and trailing white space.
 */
function norm(str){
	return trim(str).replace(/[ \t\n]*$/, '')
}
function trim(str){
	return (str?str:'').replace(/^[ \t\n]*/, '')
}
/*
 * Given an id, find the element with the given id.
 */
function $(id){
	return document.getElementById(id)
}

/*
 * Given a message, upate the element with the id = 'info'.
 * If the element is not found, the message will be buffered.
 */
function info(msg){
	var info=$('info')
	if(info){
		if(document['com.kronos.debug:buffer']){
			info.value=document['com.kronos.debug:buffer']
			document['com.kronos.debug:buffer']=''
		}
		info.value+=msg+'\n'
	}else{
		document['com.kronos.debug:buffer']+=msg+'\n'
	}
}

/*
 * This is supposed to calculate the position from the given element to the top.
 * I am not confident in how this works anymore.
 */
function absoluteTop(element){
	return absolute(element.parentNode, 'offsetTop')
}

/*
 * This is supposed to calculate the position from the given element to the left of the browser.
 * I am not confident in how this works anymore.
 */
function absoluteLeft(element){
	return absolute(element.parentNode, 'offsetLeft')
}
function absolute(element, position){
	var result=0
	while(element){
		result +=integer(element[position])
		element=element.parentNode
	}
	return result
}

// DAR:TODO rename intValue
function integer(value){
	value=parseInt(value,10)
	return value?value:0
}

/*
 * Given an dom object, find any style information regarding height and width of the object.
 * The result is sent to the info() method.
 */
function demensions(element){
	var out=new Array()
	var tag=identifyObj(element)
	var inspect=[element, element.style, element.runtimeStyle, element.currentStyle]
	var objNames=['', '.style', '.runtimeStyle', '.currentStyle']
	for(var i=0; i<inspect.length; i++){
		var element=inspect[i]
		if(element){
			out[out.length]=tag+objNames[i]+'.position='+element.position
			for(var property in element){
				if(demensions.RE.test(property)){
					out[out.length]=tag+objNames[i]+'.'+property+'='+element[property]
				}
			}
		}
	}

	out.sort()
	info(out.join('\n'))

}
demensions.RE=/(top|left|width|height)/

/*
 * Given a dom object, find all fields and values of the object.
 * The result is sent to the info() method.
 */
function showObj(obj){
	var out=new Array()
	if(typeof(obj)=='string'){
		out[0]=obj
	}else {
		try{
			for(var i in obj){
				var val=null
				try{
					val=obj[i]
				}catch(e){
					val='[' + e.message + ']'
				}
				if(typeof(val)=='function'){
					val='[function]'
				}
				if('toString'==i){
					val=obj.toString()
				}else if('innerHTML'==i){
					val='[html content skipped, length: '+val.length+']'
				}else if('outerHTML'==i){
					val='[html content skipped, length: '+val.length+']'
				}else if('innerText'==i){
					val='[text content skipped, length: '+val.length+']'
				}else if('outerText'==i){
					val='[text content skipped, length: '+val.length+']'
				}else if('cssText'==i){
					val='[text content skipped, length: '+val.length+']'
				}
				out[out.length]=i + '=' + val
			}
		}catch(e){
			out[out.length++]='[' + e.message + ']'
		}
	}
	if(obj && obj.attributes){
		for(var i=0; i<obj.attributes.length; i++){
			out[out.length++] = '@'+ obj.attributes[i].name +'='+obj.attributes[i].value
		}
	}
	out.sort()
	info(out.join('\n'))
}

/*
 * HOOK for showing dom elements over native ui controls.
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\suitenav\scripts\suite-nav-menu.js
 */
function wrapFloatOverAppletWorkaround(element){
	// note you will need to append the iframe to a element
	// can contain the iframe and the popup as siblings!
	// element must be positioned and have a z-index > 1
	// for iframe to work automatically otherwise you will 
	// need to adjust the iframe's position to make it fit ....
	if(element){
		// remove the iframe when not showing float
		element._kron_getIFrame=function(){
			return this['com.kronos.float-over-applet:iframe']
		}
		element._kron_removeIFrame=function(){
			var iframe=this._kron_getIFrame()
			if(iframe){
				this.parentNode.removeChild(iframe)
			}
		}
		// insert the iframe when showing the float
		element._kron_insertIFrame=function(){
			var iframe=this._kron_getIFrame()
			if(!iframe){
				iframe=createElement('<iframe class="HideApplet" scrolling="no" disabled="true" hidefocus="true" frameborder="0" src="/blank.html" style="position:absolute;z-index:1;" width="0" height="0"></iframe>')
				this['com.kronos.float-over-applet:iframe']=iframe
			}
			iframe.style.top=this.offsetTop
			iframe.style.left=this.offsetLeft
			iframe.style.width=this.offsetWidth
			iframe.style.height=this.offsetHeight
			this.parentNode.appendChild(iframe)
			return iframe
		}
		// note you will need to append the returned iframe to an element
		// that can contain the iframe and the popup as siblings!
		return element._kron_insertIFrame()
	}
}

/*
 * Given an element and a css-like selector, find the first element that matches the selector.
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\js\com\kronos\behaviors.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\js\com\kronos\table-rows.js
	Workspaces\wtk.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\mss\html\scripts\table.js
	Workspaces\wfp.06.00.qa.int.es.uirefresh\staging_files\web_server\applications\wpk\html\visuallanguage\tabular.js 
 */
function getElementBySelector(element, selector){
	return getElementsBySelector(element, selector)[0]
}

/*
 * Given an element and a css-like selector, find all the elements that match the selector.
 */
function getElementsBySelector(element, selector){
	// .classname	=> context.className=='classname'
	// #id			=> context.id=='id'
	// [att=val]	=> attribute('att')=='val'
	// [att=val&&att2=val2]	=> similli
	// [att!=val]	=> attribute('att')!='val'
	// [att!=val&&att2!=val2]	=> similli
	// :last-child	=> context.parentNode.lastChild==context
	// :first-child	=> context.parentNode.firstChild==context
	// [n]			=> position()==n
	// [contains(att, val)] => contains(context.getAttribute(att), val)
	var parseSelectorRE=/^(\w+)?(\S+)?/
	var dotClass=/\.(\w+)/
	var poundId=/^#(\w+)/
	var firstChild=/^:first-child/
	var lastChild=/^:last-child/
	var equal=/\[?@?(\w+)=(\w+)\]?/g
	var notEqual=/\[?@?(\w+)!=(\w+)\]?/g
	var position=/\[(\d+)\]/ig
	var attributeExists=/\[(\w+)\]/g
	var contains=/\[?contains\((\w+),(\w+)\)\]?/ig
	//info('searching for '+selector)
	return findElements(element instanceof Array? element: [element], new Selector(selector))
	function findElements(elements, selector){
		if(selector.hasNext()){
			selector.next()
			var foundArray=new Array()
			for(var i=0; i<elements.length; i++){
				foundArray=getElementsByFilter(elements[i], selector_test, selector.tagName, foundArray)
			}
			elements=findElements(foundArray, selector)
		}
		return elements
		function selector_test(element, index){
			return selector.test(element, index)
		}
	}
	function Selector(selector){
		this.tagName=null
		this.selector=null
		this.predicate=null
		this.remainder=selector
		this.test=function(context, index){
			var result=eval(this.predicate)
			//info('testing '+identifyObj(context)+' nodeType '+context.nodeType+' with predicate ('+this.predicate+') = '+result)
			return result
			function position(){ return (index?index:0) }
			function contains(value, str) { return (value?value:'').indexOf(str) > -1 }
			function attribute(name) { return context.getAttribute(name) }
		}
		this.hasNext=function(){
			return (this.remainder?true:false)
		}
		this.next=function(){
			this.selector=this.remainder
			parseSelector(this)
			parsePredicate(this)
		}
		function parseSelector(instance){
			parseSelectorRE.exec(instance.selector)
			instance.tagName=RegExp.$1
			instance.predicate=RegExp.$2

         // This resolves the case where the browser adhere's to the Core JavaScript 1.5 specification
         // which states that the RegExp.rightContext is now deprecated
         //	Old Code:		instance.remainder=trim(RegExp.rightContext)
         instance.remainder=trim(rightContext(instance.selector))
		}
		function parsePredicate(instance){
			var result=instance.predicate
			result=result.replace(dotClass, "isClass(context, '$1')")
				.replace(poundId, "'$1'==context.id")
				.replace(firstChild, "1==context.nodeType&&context.firstChild==context")
				.replace(lastChild, "1==context.nodeType&&context.lastChild==context")
				.replace(equal, "attribute('$1')=='$2'")
				.replace(notEqual, "attribute('$1')!='$2'")
				.replace(position, "$1==position()")
				.replace(contains, "contains(attribute('$1'),'$2')")
				.replace(attributeExists, "attribute('$1')!=undefined")
			// returning true is equivalent to select all elements
			// in other words there is no predicate to evaluate
			instance.predicate=(result?result:true)
		}
	}
}

function getElementsByTagNames(dom, nameOrNames){
	var namesArray
	if(nameOrNames instanceof Array){
		namesArray=nameOrNames
	}else {
		namesArray=(nameOrNames?nameOrNames:'*').split('|')
	}
	var out = new Array()
	if(dom.getElementsByTagName){
		for(var i=0; i<namesArray.length; i++){
			out=out.concat(dom.getElementsByTagName(namesArray[i]))
		}
	}
	return out
}

function invokeAfterLastCall(dom, method, args){
	var timer=document['com.kronos.timer']
	var timerkey='com.kronos.invokeAfterLastCall:timerid'
	var timerid=dom[timerkey]
	dom[timerkey]=timer.callAfterLastDelay(method, args, 15, timerid)
}

function removeLastCall(dom){
	var timer=document['com.kronos.timer']
	var key='com.kronos.invokeAfterLastCall:timerid'
	var timerid=dom[key]
	dom[key]=timer.clearTimerForId(timerid)
}

function identifyObj(dom, msg){
	var out='undefined'
	if(dom){
		out=dom.tagName
		out+=(dom.id?'#'+dom.id:'')
		out+=(dom.className?'['+dom.className+']':'')
	}
	if(msg){
		out+=msg
		info (out)
	}
	return out
}

window['com.kronos.template'] = {
	Template: function (template){
		this.apply=function(variables){
			return assign (variables)
		}
		var parsedTemplate = parse()
		function parse () {
			var parsed = new Array()
			var buffer = new Array()
			var isNamedParamOpen = false
			for (var i=0; i<template.length; i++) {
				var chr = template.charAt(i)
				//info('char: ' + chr)
				if('$'==chr){
					chr = template.charAt(++i)
					//info('char: ' + chr)
					if('{'==chr){
						if(isNamedParamOpen) {
							throw 'invalid template string: open named param not closed, expected "}" found "${".'
						}
						//info('starting named param here: ' + buffer.join(''))
						parsed[parsed.length] = buffer.join('')
						isNamedParamOpen = true
						buffer.length = 0
					} else {
						buffer[buffer.length] = '$' + chr
					}
				} else if ('}'==chr) {
					if(isNamedParamOpen) {
						var paramName = buffer.join('')
						//info('what is the param name: ' + paramName)
						isNamedParamOpen = false
						buffer.length = 0
						parsed[parsed.length] = new Function('variables', '{return variables["'+paramName+'"]}')
					}
				} else {
					buffer[buffer.length] = chr
				}
			}
			if(isNamedParamOpen){
				throw 'invalid template string: named param not closed, reached end of template string.'
			}
			parsed[parsed.length] = buffer.join('')
			return parsed
		}
		function assign (variables) {
			var out = new Array()
			for(var i=0; i<parsedTemplate.length; i++) {
				var line = parsedTemplate[i]
				if(typeof(line)=='function'){
					out[out.length] = line(variables)
				}else{
					out[out.length] = line
				}
			}
			return out.join('')
		}
	}
}

/**
 * Given an javascript snippet or a function reference, add it to the body onload event list.
 * @param evalString The javascript snippet or function reference to add to the body onload event.
 */

window['com.kronos.ui.dom-utils'] = {
	doOnload:function (evalString){
		function handler (){
			if(typeof(evalString)=='function'){
				evalString()
			} else {
				eval(evalString)
			}
		}
		if(window.addEventListener){
			window.addEventListener('load', handler, false)
		} else {
			window.attachEvent('onload', handler)
		}
	},
	doOnUnload: function(evalString, windowObject){
		function handler (){
			if(typeof(evalString)=='function'){
				evalString()
			} else {
				eval(evalString)
			}
		}

		var win = windowObject || window

		if(win.addEventListener){
			win.addEventListener('unload', handler, false)
		} else {
			win.attachEvent('onunload', handler)
		}
	},
	doOnBeforeUnload: function(evalString, windowObject){
		function handler (){
			if(typeof(evalString)=='function'){
				evalString()
			} else {
				eval(evalString)
			}
		}
		var win = windowObject || window
		if(win.addEventListener){
			win.addEventListener('beforeunload', handler, false)
		} else {
			win.attachEvent('onbeforeunload', handler)
		}
	}
}

/** This function gets the top-level accessible window object.
  * The function goes up the "parent" hierarchy and stops when it reaches the top-level window or when it cannot access the DOM of the top-level window.
  * We do not use 'top' directly because the current window object can be contained in a frameset which is in a different domain.
  * Currently, all pages are within an iframe which can contain framesets which can contain other framesets.
  * This function can be called from any page in the frameset hierarchy and it will return the window object of the page which contains the iframe.
  */
function getWFCWindow() {
	var currentWindow = window
	var parentWindow = window.parent
	while (currentWindow && parentWindow != currentWindow)
	{
		if (!isWindowAccessible(parentWindow)) {
			return currentWindow
		}
		currentWindow = parentWindow
		parentWindow = parentWindow.parent
	}
	return parentWindow

	function isWindowAccessible(win) {
		try {
			if (win && win.document.body) {
				//this is the window we need
				return true
			}
		}
		catch (error) {
			//element is not accessible; hence returning false
		}
		return false
	}
}

/** This function was added to replicate the RegExp.rightContext functionality that was 
  * deprecated in the JavaScript 1.5 specification.  This is mainly to support the Apple 
  * Safari 2.0.4 browser which is JavaScript 1.5 compliant.
  */
function rightContext(strIn){
   var idx = strIn.indexOf(" ")
   var strOut = ""
   if(0 <= idx){
      strOut = strIn.slice(idx)
   }   
   return strOut
}
