// ====== Utility functions =========
function print(characters){
	document.write(characters)
}
function LF(){print('<br>')}

function println(characters){
	print(characters);LF()
}


/*=======================================
	Array utility functions
  =======================================*/
function printArray(array,separator){
	var i,str='',sep
	sep=separator||'\n'
	for (i in array){
		str+=i+': ' 
		str+=array[i]+sep
	}
	return str
}

/* =============================================
		Load a select list from an array.  The 
		array format must be

		[['val1','text1'], ['val2','text2'],...]
   ============================================= */
function loadOptionsFromArray(select,array) {
	var option
	var options=select.options

	// Sort by name
	array.sort(sortfunc)

	options.length = 0
	for (n=0;n < array.length;n++) {
		option=array[n]
		options[n] = new Option(option[1],option[0])
	}


	function sortfunc(a,b){
		var A = a[1].toLowerCase()
		var B = b[1].toLowerCase()
		if (A < B) {return -1}
		if (A > B) {return 1}
		return 0
	}
}


/* ==============================================
        See if array contains a value
   ==============================================*/
function inArray(array, value){
	return (value in array)
	var i
	for (i in array){
		if (array[i]==value){return true}
	}
	return false
}

// ======= Does an associative array have any members? ========
function objectHasCount(object){
	var has_member = false
	for (var a in object){
		has_member = true
		break
	}
	return has_member
}


/* ==============================================
        For an associative array, return an array
		of its keys
   ==============================================*/
function keys(source){
	var k,result=[]
	for (k in source){
		result.push[k]
	}
	return result
}

/* ==============================================
        For an associative array, return a new
		associative array whose keys are the 
		distinct values of the original array,
		and whose values are lists of the original 
		keys that have that value.  The values
		of the new array must be lists to handle
		the case where there are duplicate values 
		in the original array.
   ==============================================*/
function inverseKeys(source){
	var k,value,result={}
	for (k in source){
		value=source[k]
		if (!result[value]){
			result[value]=[]
		}
		result[value].push(k)
	}
	return result
}

/* ==============================================
       Sort an hash on its keys when it is 
	   indexed by a string instead of by serial 
	   numbers (0,1,...).
	   The sort is case-insensitive.

	   CAUTION: May fail if there are duplicate values!
   ==============================================*/
function sortHashBykey(object){
	if (!object){return new Object()}
	var ByValue

	// Compare function for case-insensitive sort
	function comparefunc(a,b){
		var A,B
		if (!(a&&b)){return 0}
		
		A=a.toLowerCase()
		B=b.toLowerCase()
		if (A<B){return -1}
		if (A==B){return 0}
		return 1
	}

	//  Fill list with the keys
	var Keys=new Array()
	var k
	for (k in object){
		Keys.push(k)
	}
	
	Keys.sort(comparefunc)

	//Rebuild sorted array
	var result=new Object()
	var Key
	for (k in Keys){
		Key=Keys[k]
		result[Key]=object[Key]
		}

	return result
}


/* ==============================================
       Sort an hash on its (string) values
	   The sort is case-insensitive.

	   CAUTION: May fail if there are duplicate values!
   ==============================================*/
function sortArrayByValue(array){
	if (!array){return new Object()}
	var Values=new Array()
	var ByValue
	var result
	var n,i=0
	var Value

	//  Fill list with the keys
	for (n in array){
		Value=array[n]
		if (Value) {
			Values.push(Value)
		}
	}

//	ByValue=new Array(Values.length)
//	result=new Array(Values.length)
	ByValue=new Object()


	// Compare function for case-insensitive sort
	function comparefunc(a,b){
		var A,B
		if (!(a&&b)){return 0}
		
		A=a.toLowerCase()
		B=b.toLowerCase()
		if (A<B){return -1}
		if (A==B){return 0}
		return 1
	}
	
	Values.sort(comparefunc)

	// Index the original index items by the keys
	for (n in array){
		Value=array[n]
		if (Value) {
			try
			{
				ByValue[Value]=n	
			}
			catch (e)
			{
				//???
			}
		}
	}

	//Rebuild sorted array
	result=new Object()
	for (n in Values){
		Value=Values[n]
		if (Value) {
			result[ByValue[Value]]=Value
		}
	}

	return result
}

/* ==============================================
       Sort an array on its (numeric) values when it is 
	   indexed by a string instead of by serial 
	   numbers (0,1,...).
   ==============================================*/
function sortArrayByValueNumber(array){
	if (!array){return new Object()}
	var Values=new Object()
	var ByValue
	var result
	var n,i=0,Value

	//  Fill list with the values
	for (n in array){
		Values[i]=array[n]
		i++
	}

	ByValue=new Array(Values.length)
	result=new Array(Values.length)

	// Compare function for case-insensitive sort
	function comparefunc(a,b){
		var A,B
		if (!(a&&b)){return 0}
		
		A=Number(a)
		B=Number(b)

		if (A<B){return -1}
		if (A==B){return 0}
		return 1
	}
	
	Values.sort(comparefunc)

	// Index the original index items by the values
	for (n in array){
		ByValue[array[n]]=n
	}

	//Rebuild sorted array
	for (n in Values){
		Value=Values[n]
		result[ByValue[Value]]=Value
	}

	return result
}

/* ==============================================
		Page-related functions
   ==============================================*/

function getChecked(form_name, radioname){
	/* Return name of selected radio button
	   form_name: e.g. 'f1'
	   radioname: name of radio button input elements
	*/
	var selected=''
	var buttons =eval('document.'+form_name+'.'+radioname)
	{
		for (i=0;!buttons[i].checked&&
			i<buttons.length;i++){}
		selected=buttons[i].value
	}
	return selected
}

/* ================================================
		Remove options from a select list
   ================================================*/
function removeOptions(selectObject){
    if (!selectObject||!selectObject.length){return}
	selectObject.length=0;
}


/* ================================================
	Load a select box from an array.  The key
	becomes the option value, and the array item
	becomes the option text.
   ================================================*/
function loadSelectFromArray(selectbox,data){
	//Assume an empty array to start with
	var item,i
	for (i in data){
		if (data[i]) {		    
			with (selectbox){
				options[options.length]=new Option(data[i],i)
			}
		}
	}
}

function addText(message,elementId,displaydoc){
	if (!message){return}
	var n,first,last
	var e1//=document.getElementById(elementId)
	var TextNode
	var doc=displaydoc||document
	
	e1=doc.getElementById(elementId)
	if (!e1){return}

	// Look for embedded line feeds
	n=message.indexOf('\n')
	if (n==-1)
	{
		TextNode=doc.createTextNode(message);
		e1.appendChild(TextNode)
	}
	else  // add <br> nodes for each line feed
	{
		first=message
		while (n >-1) {
			last=first.substring(n+1)
			first=first.substring(0,n)
			TextNode=doc.createTextNode(first)
			e1.appendChild(TextNode)
			e1.appendChild(doc.createElement("br"))
			first=last
			n=last.indexOf('\n')
		}
		if (first) {  // Add last fragment
			TextNode=doc.createTextNode(first)
			e1.appendChild(TextNode)
		}
	}
}

// Remove all children of an element
function clearChildren(elementId,displaydoc){
	var kid
	var e1
	var doc=displaydoc||document
	e1=doc.getElementById(elementId)

	if (!e1){return}
	while (e1.childNodes.length){
		kid=e1.childNodes.item(0)
		e1.removeChild(kid)
	}
}

// Add <br> element to an element
function addBreakToDisplay(elementId,displaydoc){
	var e1
	var doc=displaydoc||document
	e1=doc.getElementById(elementId)
	if (!e1){return}
	e1.appendChild(doc.createElement("br"))
}

function addHrefToDisplay(href,text,elementId,displaydoc){
	var e1//=document.getElementById(elementId)
	var doc=displaydoc||document

	e1=doc.getElementById(elementId)
	if (!e1){return}

	var anch=doc.createElement('a')
	anch.href=href
	anch.target='_show'
	anch.appendChild(doc.createTextNode(text||href))
	e1.appendChild(anch)
}

// Add <b> element to an element, return element reference
function addBoldToDisplay(elementId,displaydoc,id){
	var e1,child
	var doc=displaydoc||document
	var id=id||''
	e1=doc.getElementById(elementId)
	if (!e1){return}
	child=doc.createElement("b")
	if (id){
		child.setAttribute('id',id)
	}
	e1.appendChild(child)
	return child
}

// =========== Set operations ===================
// Return a list containing the intersection (common items) of list_1 and list_2.
function intersection(list_1, list_2){
	if (! (list_1  && list_1.length && list_2 && list_2.length)){ return []}

	var longer = []; shorter = []
	if (list_1.length >= list_2.length){
		longer = list_1
		shorter = list_2
	}
	else {
		longer = list_2
		shorter = list_1
	}

	// Turn longer list into a dictionary
	var dict = {}
	for (var n in longer){
		dict[longer[n]] = true
	}

	// Check each item in shorter list to see if it is in the dictionary
	var item
	var temp_dict = {}
	for (var n in shorter){
		item = shorter[n]
		if (dict[item]){
			temp_dict[item] = true
		}
	}

	// Create output list
	var results = []
	for (var i in temp_dict) {
		results.push(i)
	}

	return results
}

// Return a list containing the union of list_1 and list_2.
function union(list_1, list_2){
	if (! list_1 && list_2){ return []}

	var results = []
	var longer = []; shorter = []
	if (list_1.length >= list_2.length){
		longer = list_1
		shorter = list_2
	}
	else {
		longer = list_2
		shorter = list_1
	}

	// Turn longer list into dictionary and push all its elements into the results
	var dict = {}
	var item
	for (var n in longer){
		item = longer[n]
		dict[item] = true
	}

	// Add non-duplicate items from the shorter list
	for (var n in shorter){
		item = shorter[n]
		if (! dict[item]){
			dict[item] = true
		}
	}

	// Create output list
	for (var i in dict) {
		results.push(i)
	}

	return results
}

// Return list of topics in list_1 that are NOT in list_2
function left_disjunction(list_1, list_2){
	if ( !list_1 ) { return [] }
	if ( list_1 && !list_2 ) { return list_1 }

	// Turn list_2 into a dictionary and add all its elements
	var dict = {}
	var item
	for (var n in list_2){
		item = list_2[n]; 
		dict[item] = true
	}

	// Save non-matches
	var results = []
	for (var n in list_1){
		item = list_1[n]
		if (!dict[item]){
			results.push(item)
		}
	}
	return results
}

// ==============================================
function flash(node) {
	if (!window.flash_node) {
		window.eval("var flash_node;")
	}
	window.flash_node = node || document.body
	window.flash_node.style.backgroundColor = 'red'
	setTimeout("window.flash_node.style.backgroundColor = ''",100)
}
