var CURRENT = null;
var HIGHLIGHT_SPANS = [];
var HIGHLIGHT_CURRENT_SPAN = 0;
var URL = '/shcol_search';
var SHOW_ERRORS = false;
var CURRENT_HIGHLIGHT = null;
var QUERY_TERMS = '';
var TERMID = 0;
var LIMIT = 0;
var ITEMS_PER_PAGE = 30;
var NO_EXPAND = false;
var TITLE_TRUNCATE_LENGTH = 50;
var STOP_WORDS = '';
var DEBUG_MODE = false;
var CURRENT_SERIES_ID;
var CURRENT_ITEM_SCROLLED_TO;
var HIT_CONTEXT_MENU;
var HIT_CONTEXT_MENU_TIMEOUT;


/**
 * Add a term clause row
 *
 * @param HTMLButton btn
 */
function addTerm(btn)
{
	var div = document.createElement('DIV');
	div.className = 'term additional';
	div.innerHTML = '<select name="o[]" class="operator"><option value="AND">AND</option><option value="OR">OR</option><option value="NOT">NOT</option><option value="NEAR">NEAR</option><!--<option value="ADJACENT">ADJACENT</option>--></select><select name="s[]" title="Scope (where to search)"><option value="content">--Any--</option><!--<option value="title">Titles</option><option value="description">Descriptions</option>--><option value="ref">References</option><!--<option value="both">Titles and Descriptions</option>--></select><input type="text" name="q[]"/><span style="padding-left:2px;"></span><button class="add" onclick="addTerm(this);">+</button><button class="remove" onclick="removeTerm(this);">-</button>';
	btn.parentNode.parentNode.insertBefore(div,btn.parentNode.nextSibling);
}
/**
 * Add the expandall/collapseall control
 */
function addSeriesControls()
{
	var controls = document.createElement('DIV');
	controls.className = 'controls';
	var ul = document.createElement('UL');
	ul.className = 'controls tree';
	var li = document.createElement('LI');
	li.innerHTML = 'Collapse All';
	li.onclick = function(){seriesToggleAll(this);}
	ul.appendChild(li);
	controls.appendChild(ul);
	document.getElementById('series').insertBefore(controls,document.getElementById('series').firstChild);
	
	//alert(controls.innerHTML);
}
/**
 * Helper function to capitalize a string
 *
 * @param String str
 */
function capitalize(str) 
{
	if(str==undefined){return '';}
	return str.toLowerCase().replace(/\b[a-z]/g, cnvrt);
    function cnvrt() 
    {
    	return arguments[0].toUpperCase();
	}
}
/**
 * Create the mini hit context menu
 */
function createHitContextMenu()
{
	if(undefined==HIT_CONTEXT_MENU)
	{
		HIT_CONTEXT_MENU = document.createElement('DIV');
		HIT_CONTEXT_MENU.style.visibility = 'hidden';
		document.getElementsByTagName('BODY')[0].appendChild(HIT_CONTEXT_MENU);
		HIT_CONTEXT_MENU.className = 'hitContextMenu';
		var ul = document.createElement('UL');
		HIT_CONTEXT_MENU.appendChild(ul);
		var li = document.createElement('LI');
		li.className = 'prev';
		li.onclick = function(){getPrevMatch(CURRENT_HIGHLIGHT);}
		li.innerHTML = '<span>Go to previous hit</span>';
		ul.appendChild(li);
		var li = document.createElement('LI');
		li.className = 'next';
		li.onclick = function(){getNextMatch(CURRENT_HIGHLIGHT);}
		li.innerHTML = '<span>Go to next hit</span>';
		ul.appendChild(li);
		var li = document.createElement('LI');
		li.className = 'first';
		li.onclick = function(){getPrevMatch(HIGHLIGHT_SPANS[1]);}
		li.innerHTML = '<span>Go to first hit</span>';
		ul.appendChild(li);
		var li = document.createElement('LI');
		li.innerHTML = '<span>Go to last hit</span>';
		li.className = 'last';
		li.onclick = function(){getPrevMatch(HIGHLIGHT_SPANS[HIGHLIGHT_SPANS.length-2]);}
		ul.appendChild(li);
		var li = document.createElement('LI');
		li.innerHTML = '<span>Go to currently selected item</span>';
		li.className = 'current';
		li.onclick = function(){myScrollTo(document.getElementById('series'), document.getElementById('itemnode_'+CURRENT.itemID));}
		ul.appendChild(li);
		
		
		var lis = HIT_CONTEXT_MENU.getElementsByTagName('LI');
		for(var i=0;i<lis.length;i++)
		{
			lis[i].onmouseover = function(){this.className+= ' hover';}
			lis[i].onmouseout = function(){this.className = this.className.split(' hover').join('');}
		}
	}
}
/**
 * Called when a date field loses focus
 *
 * @param HTMLInputElement input
 */
function dateFieldBlur(input)
{
	if(input.value=='')
	{
		input.className+= " waiting";
		input.value = 'yyyy-mm-dd';
	}
	else
	{
		input.className = input.className.replace(new RegExp("\s?waiting\s?"),"");
		if(input.value!='yyyy-mm-dd')
		{
			dateFieldValidate(input);
		}
	}
}
/**
 * Called when a date field is clicked
 *
 * @param HTMLInputElement input
 */
function dateFieldClick(input)
{
	if(input.value=='yyyy-mm-dd')
	{
		input.value = '';
		input.className = input.className.replace(new RegExp("\s?waiting\s?"),"");
	}
	else
	{
		dateFieldValidate(input);
	}
}
/**
 * Perform a BASIC date validation on the value in a date field
 *
 * @param HTMLInputElement input
 */
function dateFieldValidate(input)
{
	var m,year,month,day;
	
	input._valid = true;
	input.value = input.value.split(' ').join('');
	
	m = input.value.match(/^(\d{1,4})((\d{2}))((\d{2}))$/);
	if(null!=m)
	{
		input.value = m[1]+'-'+m[3]+'-'+m[5];
	}
	
	m = input.value.match(/^(\d{1,4})(\-(\d{2}))?(\-(\d{2}))?$/)
	if(null!=m)
	{
		if(undefined!=m[1])
		{
			year = m[1];
		}
		
		if(undefined!=m[3])
		{
			month = m[3];
			if(month<=0 || month>12)
			{
				input._valid = false;
			}
		}
		if(undefined!=m[5])
		{
			day = m[5];
			if(day<=0 || day>31)
			{
				input._valid = false;
			}
		}
	}
	else
	{
		input._valid = false;
	}
	input.className = input.className.replace(new RegExp("\s?waiting\s?"),"");
	if(false==input._valid)
	{
		input.className+= ' waiting';
	}
	
	return input._valid;
}
/**
 * draw the result list
 *
 * @param XML xml
 */
function drawResultList(xml)
{
	var ul,li,nextLimit,prevLimit;
	var overviewContainer = document.getElementById('resultsOverview');
	var container = document.getElementById('results');
	var items = xml.getElementsByTagName('item');
	try{
		var start = parseInt(xml.getElementsByTagName('start')[0].firstChild.nodeValue);
		var end = parseInt(xml.getElementsByTagName('end')[0].firstChild.nodeValue);
		var totalRecords = xml.getElementsByTagName('totalRecords')[0].firstChild.nodeValue;
	}catch(e){
		if(SHOW_ERRORS){alert('XML error drawing results: '+e);}
	}
	STOP_WORDS = xml.getElementsByTagName('stopWords')[0].firstChild.nodeValue;
	var queryString = QUERY_TERMS = xml.getElementsByTagName('queryString')[0].firstChild.nodeValue;
	var timeTaken = xml.getElementsByTagName('timeTaken')[0].firstChild.nodeValue;
	var indexRecords = xml.getElementsByTagName('indexTotalDocuments')[0].firstChild.nodeValue;
	
	overviewContainer.innerHTML = 'Results <b>'+start+'</b> - <b>'+end+'</b> of <b>'+totalRecords+'</b> <!--for <b>'+queryString+'</b> -->(<b>'+timeTaken+'</b> seconds).<!-- Total documents in index: <b>'+indexRecords+'</b>-->';
	container.innerHTML = '';
	
	/**
	 * Create a record nav
	 */
	var nav = document.createElement('UL');
	nav.className = 'paging';
	var next = document.createElement('LI');
	if( start > 1 )
	{
		var prev = document.createElement('LI');
		prev.className = 'prev';
		prev.innerHTML = 'Prev';
		prev.onclick = function(){LIMIT = start-ITEMS_PER_PAGE-1;getResults();}
		nav.appendChild(prev);
	}
	if( start < totalRecords - ITEMS_PER_PAGE )
	{
		next.innerHTML = 'Next';
		next.className = 'next';
		next.onclick = function(){LIMIT = start+ITEMS_PER_PAGE-1;getResults();}
		nav.appendChild(next);		
	}
	overviewContainer.appendChild(nav);
	
	ul = document.createElement('UL');
	container.appendChild(ul);
	for(var i=0;i<items.length;i++)
	{
		var title = items[i].getElementsByTagName('name')[0].firstChild.nodeValue;
		title = title.split('<br/>').join(' ');
		if(title.length>TITLE_TRUNCATE_LENGTH)
		{
			title = '<span title="'+title+'">'+title.substring(0,TITLE_TRUNCATE_LENGTH-3)+'...</span>';
		}
		
		li = document.createElement('LI');
		li.itemID = items[i].getElementsByTagName('ID')[0].firstChild.nodeValue;
		li.topParent = items[i].getElementsByTagName('top_parent')[0].firstChild.nodeValue;
		li.innerHTML= '<strong>'+items[i].getElementsByTagName('ref')[0].firstChild.nodeValue+'</strong> ';
		li.innerHTML+= title;
		li.innerHTML+= ' ('+items[i].getElementsByTagName('type')[0].firstChild.nodeValue+')';
		try{			
			if(items[i].getElementsByTagName('ID')[0].firstChild.nodeValue != items[i].getElementsByTagName('top_parent')[0].firstChild.nodeValue)
			{
				var catalogue = items[i].getElementsByTagName('top_parent_name')[0].firstChild.nodeValue;
				catalogue = catalogue.split('<br/>').join(' ');
				if(catalogue.length>TITLE_TRUNCATE_LENGTH)
				{
					li.innerHTML+= ' <span class="topref" title="'+catalogue+'">'+catalogue.substring(0,TITLE_TRUNCATE_LENGTH-3)+'...</span>';
				}
				else
				{
					li.innerHTML+= ' <span class="topref">'+catalogue+' '+items[i].getElementsByTagName('top_parent_ref')[0].firstChild.nodeValue+'</span>';
				}
			}
		}catch(e){
			
		}
		
		li.onmouseover = function(){this.className = this.className.replace(/ over/,'')+' over';}
		li.onmouseout = function(){this.className = this.className.replace(/ over/,'');}
		li.onclick = function(){
			this.className = this.className.replace(/ active|loaded/,'')+' active';
			getSeries(this.topParent,this);
		}
		ul.appendChild(li);
	}
	//container.innerHTML+= xml.getElementsByTagName('parsedQuery')[0].firstChild.nodeValue
}
/**
 * Render the series tree
 */
function drawSeries(xml)
{
	var ref,title,ul,description='';
	var container = document.getElementById('series');
	
	
	try{title = xml.getElementsByTagName('name')[0].firstChild.nodeValue;}catch(e){title = '<em>'+item.getElementsByTagName('type')[0].firstChild.nodeValue+'</em>';}
	try{ref = xml.getElementsByTagName('ref')[0].firstChild.nodeValue;}catch(e){ref = '<em>-</em>';}
	
	container.innerHTML = '<h2>Reference: '+ref+'</h2><h3>'+title+'</h3>';
	
	myScrollTo(document.getElementById('series'), document.getElementById('series').firstChild);
	
	try{
		if(xml.getElementsByTagName('description').length>0)
		{
			/**
			 * Have to do this as Firefox (rather UNhelpfully) auto splits long 
			 * text nodes into adjacent ones
			 */
			description = '<div class="description">';
			var descriptionNode = xml.getElementsByTagName('description')[0];
			for(var i=0;i<descriptionNode.childNodes.length;i++)
			{
				try{
					//alert(descriptionNode.childNodes[i].nodeValue);
					description+= descriptionNode.childNodes[i].nodeValue.split('&lt;').join('<').split('&gt;').join('>');
				}catch(e){
					
				}
			}
			description+= '</div>';
		}
		
		//description = xml.getElementsByTagName('description')[0].firstChild.nodeValue.split('&lt;').join('<').split('&gt;').join('>');
		container.innerHTML+=description+'<h4>Catalogue</h4>';
		var h = container.getElementsByTagName('h4');
		for(var i in h)
		{
			try{
				h[i].innerHTML = capitalize(h[i].innerHTML);
			}catch(e){
				
			}
		}
	}catch(e){
		alert(e);
	}
	
	var subs = xml.getElementsByTagName('items')[0].childNodes;
	
	ul = document.createElement('UL');
	ul.id='seriesData';
	ul.className = 'tree';
	for(var i=0;i<subs.length;i++)
	{
		drawSubSeries(subs[i],ul);
	}
	container.appendChild(ul);
	
	// Highlight the search terms
	highlightTerms();
	
	// Assign behaviours to the labels
	var labels = document.getElementById('series').getElementsByTagName('span');
	for(var i=0;i<labels.length;i++)
	{		
		if(labels[i].className=='label')
		{
			//alert(labels[i].innerHTML);
			labels[i].onmouseover = function(){
				this.className = 'label over'
			}
			labels[i].onmouseout = function(){this.className = 'label';}
			labels[i].onclick = function(){
				toggleSeries(this.parentNode);
			}
		}
	}

	// Add controls
	addSeriesControls();
}
/**
 * Render the series tree
 *
 * @param xmlNode item
 * @param HTMLULElement ul
 */
function drawSubSeries(item,ul)
{
	var title,subs,descriptionNode,descriptionContainer;
	
	try{title = item.getElementsByTagName('name')[0].firstChild.nodeValue;}catch(e){title = '<em>'+item.getElementsByTagName('type')[0].firstChild.nodeValue+'</em>';}
	try{title+= ' <span class="ref">Ref: <strong>'+item.getElementsByTagName('ref')[0].firstChild.nodeValue+'</strong></span>';}catch(e){}
	try{title+= ' <span class="ref unitdate">Unit Date: <strong>'+item.getElementsByTagName('unit_date')[0].firstChild.nodeValue+'</strong></span>';}catch(e){}
	
	var li = document.createElement('LI');
	li.id = 'itemnode_'+item.getElementsByTagName('ID')[0].firstChild.nodeValue;
	//li.topParent = items[i].getElementsByTagName('top_parent')[0].firstChild.nodeValue;
	
	var label = document.createElement('span');
	label.className = 'label';
	label.innerHTML = title;
	try{
		if(item.parentNode.parentNode.parentNode.parentNode)
		{
			//Don't show the description for the catalogue node			
			for(var i=0;i<item.childNodes.length;i++)
			{
				if(item.childNodes[i].nodeName=='description' && item.childNodes[i].innerHTML!='')
				{
					descriptionNode = item.childNodes[i];
					break;
				}
			}
			if(descriptionNode!==undefined)
			{
				//alert(descriptionNode.firstChild.nodeValue);return;
				try{
					//alert(descriptionNode.childNodes[i].nodeValue);
					label.innerHTML+= '<div class="description">'+descriptionNode.firstChild.nodeValue.split('&lt;').join('<').split('&gt;').join('>')+'</div>';
				}catch(e){
					
				}				
			}
		}
	}catch(e){
	}
	
	li.appendChild(label);
	
	ul.appendChild(li);
	
	if(subs = item.getElementsByTagName('items')[0])	
	{
		subs = subs.childNodes;
		ul = document.createElement('UL');
		for(var i=0;i<subs.length;i++)
		{
			drawSubSeries(subs[i],ul);
		}
		li.appendChild(ul);
	}
}
/**
 * Hide the loading graphic
 */
function hideLoader()
{
	document.getElementById('series').className = '';
	document.getElementById('loader').style.display = 'none';
}
/**
 * Initialise the controls and stuff
 */
function init()
{
	
	sizeControls();
	try{
		document.getElementById('submitter').onclick = function(){
			LIMIT=0;getResults();
		}
	}catch(e){
		
	}
}
/**
 * Scroll to the prev match in the result
 */
function getPrevMatch(span)
{
	NO_EXPAND = true;
	getMatch(span,-1);
}
/**
 * Scroll to the next match in the result
 */
function getNextMatch(span)
{
	NO_EXPAND = true;
	getMatch(span,1);
}
/**
 * Scroll to the next/prev match
 * 
 * @param HTMLSpanElement span
 * @param integer incrementor (1 | -1) for next/prev respectively
 */
function getMatch(span,incrementor)
{
	try{
		if(CURRENT_HIGHLIGHT!=null)
		{
			CURRENT_HIGHLIGHT.className = CURRENT_HIGHLIGHT.className.split(' currentHighlighted').join('');
		}	
		
		// What is the search string
		var str = span.childNodes[1].nodeValue.toLowerCase();
		var i = 1;
		CURRENT_HIGHLIGHT = HIGHLIGHT_SPANS[span._index+incrementor];
		while(CURRENT_HIGHLIGHT.childNodes[1].nodeValue.toLowerCase()!=str && i<100)
		{
			CURRENT_HIGHLIGHT = HIGHLIGHT_SPANS[span._index+(incrementor*i++)];
		}
		// Recursively expand the current span's parents
			
		el = CURRENT_HIGHLIGHT;
		while(el)
		{
			if(el.nodeName.toLowerCase()=='li' && el.className=='collapsed')
			{
				toggleSeries(el,true);
			}
			el = el.parentNode;
		}
		
		//$(CURRENT_HIGHLIGHT);
		
		myScrollTo(document.getElementById('series'), CURRENT_HIGHLIGHT);
		//Effect.ScrollTo(CURRENT_HIGHLIGHT);
		
		//CURRENT_HIGHLIGHT.scrollIntoView();
		CURRENT_HIGHLIGHT.className+=' currentHighlighted';
	}catch(e){
		
	}
}
/**
 * Retrieve the results from the server
 */
function getResults()
{
	showLoader();
	document.getElementById('results').innerHTML = '';	
	CURRENT_SERIES_ID = null;
	
	var xmlhttp;
	var url = URL+'?';
	var inputs = document.getElementById('searchForm').getElementsByTagName('INPUT');
	var j = 0;
	for(var i=0;i<inputs.length;i++)
	{		
		if(inputs[i].name=='q[]' && inputs[i].value!='')
		{
			url+='&q['+j+']='+escape(inputs[i].value);
			var selects = inputs[i].parentNode.getElementsByTagName('SELECT');
			for(var k=0;k<selects.length;k++)
			{		
				if(selects[k].name=='s[]')
				{
					url+='&s['+j+']='+escape(selects[k].value);
				}	
				else if(selects[k].name=='o[]')
				{
					url+='&o['+j+']='+escape(selects[k].value);
				}		
			}
			j++;
		}		
	}	
	if(document.getElementById('start_date').value && dateFieldValidate(document.getElementById('start_date')))
	{
		url+='&d1='+document.getElementById('start_date').value;
	}
	if(document.getElementById('end_date').value && dateFieldValidate(document.getElementById('end_date')))
	{
		url+='&d2='+document.getElementById('end_date').value;
	}
	
	url+= '&limit='+LIMIT;
	
	
	if(DEBUG_MODE)
	{
		var debug_window = document.getElementById('debug_window');		
		if(undefined==debug_window)
		{
			debug_window = document.createElement('IFRAME');
			debug_window.id = 'debug_window';
			document.getElementsByTagName('BODY')[0].appendChild(debug_window);
		}
		debug_window.src = url;
	}
	
	
	//window.open(url);
	
	if (window.XMLHttpRequest){xmlhttp=new XMLHttpRequest()}else if(window.ActiveXObject){xmlhttp=new ActiveXObject("Microsoft.XMLHTTP")}
	if (xmlhttp!=null)
	{
		xmlhttp.onreadystatechange=function()
		{
			try{
				if(xmlhttp.readyState==4)
				{
					if (xmlhttp.status==200)
					{						
						document.getElementById('series').innerHTML = '<p>Select an item from the results on the left.</p>';
						//alert(xmlhttp.responseText);
						drawResultList(xmlhttp.responseXML);
					}					
					else
					{
						if(SHOW_ERRORS){alert("Problem retrieving XML data");}
					}
					hideLoader();
				}
			}catch(e){
				if(SHOW_ERRORS){alert('Error in httpRequest change handler: '+e);}
				hideLoader();
			}
		}
		xmlhttp.open("GET",url,true)
		xmlhttp.send(null)
	}
	else
	{
		alert("Your browser does not support XMLHTTP.");
		hideLoader();
	}
}
/**
 * Retrieve the results from the server
 */
function getSeries(seriesId,li)
{	
	var xmlhttp;
	
	
	if(CURRENT_SERIES_ID==seriesId)
	{
		// If the series is already loaded, then just scroll to the item
		if(CURRENT)
		{
			CURRENT.className = CURRENT.className.replace(/loaded|active/,'');
		}
		CURRENT = li;
		CURRENT.className = CURRENT.className.replace(/active|loaded/,'')+' loaded';
		//alert(CURRENT.itemID);
		myScrollTo(document.getElementById('series'), document.getElementById('itemnode_'+CURRENT.itemID));
		return;
	}
	
	
	//document.getElementById('series').innerHTML = '';
	
	showLoader();
	var url = URL+'?series='+escape(seriesId);
	
	if(DEBUG_MODE)
	{
		var debug_window = document.getElementById('debug_window');		
		if(undefined==debug_window)
		{
			debug_window = document.createElement('IFRAME');
			debug_window.id = 'debug_window';
			document.getElementsByTagName('BODY')[0].appendChild(debug_window);
		}
		debug_window.src = url;
	}
	
	if (window.XMLHttpRequest){xmlhttp=new XMLHttpRequest()}else if(window.ActiveXObject){xmlhttp=new ActiveXObject("Microsoft.XMLHTTP")}
	if (xmlhttp!=null)
	{
		xmlhttp.onreadystatechange=function()
		{
			try{
				if(xmlhttp.readyState==4)
				{
					if (xmlhttp.status==200)
					{
						document.getElementById('series').innerHTML = '<p>Building display...</p>';
						
						//alert(xmlhttp.responseText);
						try{drawSeries(xmlhttp.responseXML);}catch(e){/*alert(e);*/}
						
						if(CURRENT)
						{
							CURRENT.className = CURRENT.className.replace(/loaded|active/,'');
						}
						CURRENT_SERIES_ID = seriesId;
						CURRENT = li;
						CURRENT.className = CURRENT.className.replace(/active|loaded/,'')+' loaded';
						//alert(CURRENT.itemID);
						myScrollTo(document.getElementById('series'), document.getElementById('itemnode_'+CURRENT.itemID));
					}					
					else
					{
						if(SHOW_ERRORS){alert("Problem retrieving XML data");}
					}
					hideLoader();
				}
			}catch(e){
				if(SHOW_ERRORS){alert('Error in httpRequest change handler: '+e);}
				hideLoader();
			}
		}
		xmlhttp.open("GET",url,true);
		xmlhttp.send(null);
	}
	else
	{
		alert("Your browser does not support XMLHTTP.");
		hideLoader();
	}
}
/**
 * Highlight the search terms
 */
function highlightTerms()
{
  	// Get search string
  	//var searchString = document.getElementById('keyword').value;
	// Starting node, parent to all nodes you want to search
	var textContainerNode = document.getElementById("series");
	
	// Informational message for search
	var searchInfo = 'Search Results for: ';
	
	var searchTerms = [];
	
	var stopWords = STOP_WORDS;
	stopWords+=' AND OR NOT NEAR ';
	
	// Split search terms on '|' and iterate over resulting array
	
	var searchString = '';
	var inputs = document.getElementById('searchForm').getElementsByTagName('INPUT');
	var j = 0;
	for(var i=0;i<inputs.length;i++)
	{		
		if(inputs[i].name=='q[]')
		{
			try{
				if(inputs[i].parentNode.getElementsByTagName('SELECT')[0].name=='o[]')
				{
					searchString+= ' '+inputs[i].parentNode.getElementsByTagName('SELECT')[0].value+' ';
					searchTerms.push(inputs[i].parentNode.getElementsByTagName('SELECT')[0].value);
				}
			}catch(e){}
				
			searchString+= '"'+inputs[i].value+'"';
			searchTerms.push(inputs[i].value);
		}		
	}
	
	var termId = 0;
	for (var i=0;i<searchTerms.length;i++) 	
	{
		if(searchTerms[i])
		{
			//alert(searchTerms[i]);
			var re = new RegExp("\\b"+searchTerms[i]+"\\b","ig");
			if(null==re.exec(stopWords))
			{			
				// The regex is the secret, it prevents text within tag declarations to be affected
				var regex = new RegExp(">([^<]*)?("+searchTerms[i]+")([^>]*)?<","ig");
				highlightTextNodes(textContainerNode, regex, termId);
				// Add to info-string
				searchInfo += ' <span class="highlighted term'+termId+'"><span class="prev" onclick="getPrevMatch(this.parentNode);">&laquo;</span>'+searchTerms[i]+'<span class="next" onclick="getNextMatch(this.parentNode);">&raquo;</span></span> ';
				termId++;
			}
			else		
			{
				searchInfo += ' <span class="operator">'+searchTerms[i]+'</span>';
			}
		}
	}
	
	
	var dateClause = [];
	if(document.getElementById('start_date').value && document.getElementById('start_date')._valid)
	{
		dateClause.push(document.getElementById('start_date').value);
	}
	if(document.getElementById('end_date').value && document.getElementById('end_date')._valid)
	{
		dateClause.push(document.getElementById('end_date').value);
	}
	if(dateClause.length==2)
	{
		searchInfo += ' between dates <em><strong>'+dateClause.join('</strong></em> and <em><strong>')+'</strong></em>';
	}
	else if(dateClause.length==1)
	{
		searchInfo += ' on date <em><strong>'+dateClause.join('</strong></em> and <em><strong>')+'</strong></em>';
	}
	
	try{
		// Create div describing the search
		var searchTermDiv = document.createElement("H2");
		searchTermDiv.className = 'searchterms';
		searchTermDiv.innerHTML = searchInfo;
		
		// Insert as very first child in searched node
		textContainerNode.insertBefore(searchTermDiv, textContainerNode.childNodes[0]);
		
		
		
		//alert($$('span').length);
		// Create an array of pointers to the terms
		var i,j;
		j = 0;
		HIGHLIGHT_SPANS = [];
		var spans = document.getElementsByTagName('SPAN');
		for(i=0;i<spans.length;i++)
		{
			if(spans[i].className.indexOf('highlighted term')!=-1)
			{					
				spans[i].id = 'hl_'+j;
				spans[i]._index = j++;
				//spans[i].oncontextmenu = function(event){createHitContextMenu();contextmenu = HIT_CONTEXT_MENU;show_contextmenu(event);return false;}
				HIGHLIGHT_SPANS.push(spans[i]);
			}
		}
		//alert(HIGHLIGHT_SPANS.length);
	}catch(e){
		//alert(e);
	}
}
/**
 * Highlight the text nodes
 */
function highlightTextNodes(element, regex, termid)
{
	var tempinnerHTML = element.innerHTML;
	// Do regex replace
	// Inject span with class of 'highlighted termX' for google style highlighting
	element.innerHTML = tempinnerHTML.replace(regex,'>$1<span class="highlighted term'+termid+'"><span class="prev" onclick="getPrevMatch(this.parentNode);">&laquo;</span>$2<span class="next" onclick="getNextMatch(this.parentNode);">&raquo;</span></span>$3<');
}
/**
 * Scroll to a particular element.
 * 
 * @requires jquery and jquery-scrollto plugin
 */
function myScrollTo(container, element)
{
	if(element.nodeName.toLowerCase()=='li')
	{
		if(undefined!=CURRENT_ITEM_SCROLLED_TO)
		{
			CURRENT_ITEM_SCROLLED_TO.className = CURRENT_ITEM_SCROLLED_TO.className.replace(/ currentItem/,'');
		}
		CURRENT_ITEM_SCROLLED_TO = element;
		CURRENT_ITEM_SCROLLED_TO.className+= ' currentItem';
	}
	$(container).scrollTo(element, { duration: 1500,offset:-50 });
}
/**
 * Remove a term clause row
 *
 * @param HTMLButton btn
 */
function removeTerm(btn)
{
	btn.parentNode.parentNode.removeChild(btn.parentNode);
}
/**
 * Reset the search form
 */
function resetSearchForm()
{
	if(confirm('Are you sure?'))
	{
		var container = document.getElementById('searchForm');
		var divs = container.getElementsByTagName('DIV');
		for(var i=divs.length-1;i>=0;i--)
		{
			if(divs[i].className.indexOf('term')!=-1)
			{
				// Extra clauses will have classname="additional" and should be removed
				if(divs[i].className.indexOf('additional')!=-1)
				{
					try{
						divs[i].parentNode.removeChild(divs[i]);
					}catch(e){
						alert('Error: '+e+' when trying to remove div['+i+']');
					}
				}
				else			
				{
					// The first clause row should not be removed, but should be reset
					divs[i].getElementsByTagName('INPUT')[0].value = '';
					// Reset the first SELECT to whatever the value of the first OPTION value is
					divs[i].getElementsByTagName('SELECT')[0].value = divs[i].getElementsByTagName('SELECT')[0].getElementsByTagName('OPTION')[0].value;
				}
			}		
		}	
		// Reset the date fields
		var dateFields = ['start_date','end_date'];
		for(var i=0;i<dateFields.length;i++)
		{
			document.getElementById(dateFields[i]).value = 'yyyy-mm-dd';
			document.getElementById(dateFields[i]).className = 'waiting';
		}
	}
}
/**
 * Toggle (collapse and expand) all series nodes
 *
 * @param element li
 */
function seriesToggleAll(li)
{
	
	var spans = document.getElementById('seriesData').getElementsByTagName('span');
	
	switch(li.className)
	{		
		case 'collapsed':
		li.className = '';	
		li.innerHTML = 'Collapse All';
		break;
				
		default:
		li.className = 'collapsed';
		li.innerHTML = 'Expand All';	
		break;
	}	
	for(var i=0;i<spans.length;i++)
	{
		if(spans[i].parentNode.parentNode==document.getElementById('seriesData'))
		{
			// Don't collapse the top level node
			continue;
		}
		
		try{
			if(spans[i].className=='label')
			{
				var spanLi = spans[i].parentNode;
				try{
					var uls = spanLi.getElementsByTagName('UL');
					if(uls.length>0)
					{						
						switch(li.className)
						{
							case 'collapsed':
							spanLi.className = 'collapsed';
							uls[0].style.display = 'none';
							break;
							
							default:
							spanLi.className = 'expanded';
							uls[0].style.display = 'block';
							break;
							
						}	
					}
					else
					{
						spanLi.className = '';
					}
				}catch(e){
					
				}
			}
		}catch(e){
			if(SHOW_ERRORS){alert(e);}
		}
	}
}
/**
 * Show the loading graphic
 */
function showLoader()
{
	document.getElementById('series').className = 'disabled';
	document.getElementById('loader').style.display = 'block';
}
/**
 * Size the controls
 */
function sizeControls()
{
	//var searchInput = document.getElementById('keyword');
	//searchInput.style.width = '1px';
	//searchInput.style.width = (searchInput.parentNode.offsetWidth - searchInput.offsetLeft) + 'px';
	var results = document.getElementById('results');
	var series = document.getElementById('series');
	var h = 0;
	try{
		if(!document.all)
		{
			h = (window.innerHeight ? window.innerHeight : document.documentElement.clientHeight-30);
			h-= results.offsetTop;
			h-= document.getElementById('footer').offsetHeight;
			h-= 10;
			series.style.height = results.style.height = h  + 'px';
		}
		else
		{
			series.style.height = results.style.height = (window.innerHeight ? window.innerHeight : document.documentElement.clientHeight-30) - 85 - results.offsetTop - (document.getElementById('footer').offsetHeight -10)  + 'px';
			document.getElementById('footer').style.margin = '0px';
		}
		
		if(series.offsetHeight<=400)
		{
			series.style.height = results.style.height = '400px';
		}
	}catch(e){
	}
	
	
	// Find the paging
	/*
	var uls = results.getElementsByTagName('UL');
	for(var i=0;i<uls.length;i++)
	{
		if(uls[i].className=='paging')
		{
			uls[i].style.zIndex = uls[i].style.zIndex;
			//uls[i].style.top = results.scrollTop+'px';
			break;
		}
	}
	*/
}
function toggleSeries(li,force)
{
	if(NO_EXPAND && force==undefined)
	{
		NO_EXPAND = false;
		return;
	}
	try{
		var ul = li.getElementsByTagName('UL')[0];
		switch(ul.style.display)
		{
			case 'none':
			li.className = 'expanded';
			ul.style.display = 'block';
			break;
			
			default:
			li.className = 'collapsed';
			ul.style.display = 'none';
			break;
		}		
	}catch(e){
		//if(SHOW_ERRORS){alert(e);}
	}
}
/**
 * Add window event handlers (onload, resize etc.)
 */
if(window.attachEvent)
{
	window.attachEvent('onload',init);
	window.attachEvent('onresize',sizeControls);
}
else if(window.addEventListener)
{
	window.addEventListener('load',init,false);
	window.addEventListener('resize',sizeControls,false);
}














/**
 * Right click menu for hits
 */
var mouse_x = 0;
var mouse_y = 0;
var distance_to_right_edge = 0;
var distance_to_bottom = 0;
var contextmenu = null;

addLoadEvent(onstart);

function onstart() {
  createHitContextMenu();//document.getElementById('thecontextmenu');
  contextmenu = HIT_CONTEXT_MENU;
  addGenericEvent(document,'mousemove',mousemove);
  document.getElementById('series').oncontextmenu = show_contextmenu;
  addGenericEvent(document,'click',hide_contextmenu);
}


function context_menuitem_highlight(element, color) {
  element.className = 'highlight';
}

function context_menuitem_unhighlight(element) {
  element.className = '';
}

function show_contextmenu(event) {

  get_page_boundaries();
  
  contextmenu.style.left = mouse_x+"px";
  contextmenu.style.top = mouse_y+"px";
  contextmenu.style.visibility = "visible";
  
  // adjust menu if near window edge
  if (distance_to_right_edge < contextmenu.offsetWidth)
    contextmenu.style.left = 2+mouse_x - contextmenu.offsetWidth+"px";  // The 2+ is not some dumb kludge - 
  if (distance_to_bottom < contextmenu.offsetHeight)                    // it places the menu just under the pointer,
    contextmenu.style.top = 2+mouse_y - contextmenu.offsetHeight+"px";  // instead of just outside
  
  try {
    window.getSelection().collapseToStart();  // try to compensate for tendency to treat right-clicking as text selection
  } catch (e) {} // do nothing
  
  // prevent the event from bubbling up and causing the regular browser context menu to appear.
  	try{event.cancelBubble = true;}catch(e){}
	try{if (event.stopPropagation) event.stopPropagation(); }catch(e){}
  	try{if (event.preventDefault) event.preventDefault(); }catch(e){}
  
  return false;
}

function hide_contextmenu() {
  contextmenu.style.visibility = "hidden";
}


function addLoadEvent(func) {
  if (window.addEventListener)
    window.addEventListener("load",func,false);
  else if (document.addEventListener)
    document.addEventListener("load",func,false);
  else if (window.attachEvent)
    window.attachEvent("onload",func);
  else if (document.attachEvent)
    document.attachEvent("onload",func);
}

function addGenericEvent(source, trigger, func) {
  if (source.addEventListener)
    source.addEventListener(trigger,func,false);
  else if (source.attachEvent)
    source.attachEvent("on"+trigger,func);
}

function window_x() {
  if (window.screenX)
    return window.screenX
  else if (window.screenLeft)
    return window.screenLeft;
}

function window_y() {
  if (window.screenY)
    return window.screenY
  else if (window.screenTop)
    return window.screenTop;
}

function mousemove(e) { 
  if (e && e.clientX && typeof(window.scrollY) == 'number') { // Moz
    mouse_x = e.clientX + window.scrollX;
    mouse_y = e.clientY + window.scrollY;
    event_target = e.target;
  }
  else if (window.event) { // IE
    if (document.documentElement)   // Explorer 6 Strict
    {
      mouse_x = window.event.clientX + document.documentElement.scrollLeft - 4;
      mouse_y = window.event.clientY + document.documentElement.scrollTop - 4;
    }
    else if (document.body) // all other Explorers
    {
      mouse_x=window.event.clientX+document.body.scrollLeft-4;
      mouse_y=window.event.clientY+document.body.scrollTop-4;
    }
 
    mouse_window_x = window.event.clientX;
    mouse_window_y = window.event.clientY;
  }
}

function get_page_boundaries()
{
  if (window.innerWidth) {
    distance_to_right_edge = window.innerWidth-(mouse_x - window.scrollX)
    distance_to_bottom = window.innerHeight-(mouse_y - window.scrollY);
    
    //alert(window.innerHeight+' '+mouse_y);
  } else if (document.body.clientWidth) {
    distance_to_right_edge = document.body.clientWidth-mouse_x;
    distance_to_bottom = document.body.clientHeight-mouse_y;
  }
}
