/*
 * clustering.js
 *
 * This javascript contains several functions which are based on
 * some clever people's codes, and they are noted accordingly.
 *
 * Hideo Joho <hideo@dcs.gla.ac.uk>
 *
 */
var activeDocID = '';

function hlDoc(docId,flag) {
	var docId = docId;
	var flag = flag;
	document.getElementById(docId).style.backgroundColor = (flag ? "#f7f7f7" : "#ffffff");
	return true;
}

function view(url) {
	var url = url;
	
	window.open(url,'','','');
}

/*
 * The following functions, which do a spelling suggesting
 * using Yahoo Web Search API, is based on:
 * http://videoontheweb.wordpress.com/2007/02/09/yahoo-spelling-service-api-ajax-version/
 */
function handleYahooSpellingResults(json_result){
  if (json_result.ResultSet && json_result.ResultSet.Result) {
      var result = json_result.ResultSet.Result;
      document.getElementById('spelling').innerHTML = '<span style="color:red">Did you mean:</span> '
      + '<a href="' + script + '?q=' + encodeURI(result.replace(/ /g, '+')) + '" title="Submit a new qurey with this spelling">'
      + result + '</a><br/><span style="color:#666">Note: the search may have already been using the suggested spelling.</span>';
      document.getElementById('spelling').style.display = "block";
  }
}
    
function spellCheck(q){
    // alert(encodeURI(q));
    document.getElementById('spelling_json_container').src =
    'http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion?appid=a_jRnmHV34E7Apcof1mT55EkjudSKDEbhKzulncApkJKEmegOhqgOz2PB6kXFI5MLw--&query='
     + encodeURI(q) +
    '&output=json&callback=handleYahooSpellingResults';
}

/*
 * The following function, which does an incremental search,
 * is based on: http://namazu.org/~satoru/blog/archives/000008.html
 */
function filterDoc(string, arr) {
	if(string.length > 1 && arr.length > 0) {
		try {
			var filterword = string;
			var string = "\\b\(" + string + "\)";
			var replaced = "<span class=\"hl\">\$1</span>";
			var regex = new RegExp(string, "ig");
			var tmp = new Object();
			var member = new Array();
			for (var i = 0; i < arr.length; i++) {
				if(arr[i].title.match(regex) || arr[i].snippet.match(regex) || arr[i].curl.match(regex)) {
					tmp['title'] = arr[i].title.replace(regex, replaced);
					tmp['url'] = arr[i].url;
					tmp['snippet'] = arr[i].snippet.replace(regex, replaced);
					tmp['curl'] = arr[i].curl.replace(regex, replaced) + " - " + arr[i].size;
					member[member.length] = { docid:data[i].docid, title:tmp['title'], snippet:tmp['snippet'], url:tmp['url'], curl:tmp['curl'] };
				}
			}
			return member;
		} catch (e) {
			// Ignore syntax errors
		}
	} else {
		return;
	}
}

function iterFilterDoc(string, arr, flag) {
	var tmp = string.split(/ /);
	var words = new Array();

	// Remove short words from string
	for (var i = 0; i < tmp.length; i++) {
		if(tmp[i].length > 1) { words.push(tmp[i]); }
	}
	if(words.length == 0 || arr.length == 0) { return; }

	// Count matches for all words
	var members = new Object();
	for (var i = 0; i < words.length; i++) {
		var match = "\\b\(" + words[i] + "\)";
		var regex = new RegExp(match, "i");
		for (var j = 0; j < arr.length; j++) {
			if(arr[j].title.match(regex) || arr[j].snippet.match(regex) || arr[j].curl.match(regex)) {
				// Key: position in arr; Value: number of hits
				if(members[j]) { members[j] = (members[j] + 1); }
				else { members[j] = 1; }
			}
		}
	}

	// flag: 1 -> AND; flag: 0 -> OR
	var result = Array();
	for (var x in members) {
		if(flag == 1) {
			if(members[x] == words.length) { result.push(arr[x]); }
		} else {
			result.push(arr[x]);
		}
	}

	return result;
}

/*
 * The follwoing function is based on
 * http://www.nsftools.com/misc/SearchAndHighlight.htm
 *
 */
function hlTerm(bodyText, searchTerm) {
  var highlightStartTag = "<span class=hl>";
  var highlightEndTag = "</span>";
  
  var bodyText = bodyText;
  var searchTerm = searchTerm;
  var newText = "";
  var i = -1;
  var lcSearchTerm = searchTerm.toLowerCase();
  var lcBodyText = bodyText.toLowerCase();
    
  while (bodyText.length > 0) {
    i = lcBodyText.indexOf(lcSearchTerm, i+1);
    if (i < 0) {
      newText += bodyText;
      bodyText = "";
    } else {
      // skip anything inside an HTML tag
      if (bodyText.lastIndexOf(">", i) >= bodyText.lastIndexOf("<", i)) {
        // skip anything inside a <script> block
        if (lcBodyText.lastIndexOf("/script>", i) >= lcBodyText.lastIndexOf("<script", i)) {
          newText += bodyText.substring(0, i) + highlightStartTag + bodyText.substr(i, searchTerm.length) + highlightEndTag;
          bodyText = bodyText.substr(i + searchTerm.length);
          lcBodyText = bodyText.toLowerCase();
          i = -1;
        }
      }
    }
  }
  return newText;
}

function iterHlTerm(texts, string) {
	if(!string) { return texts; }
	var tmp = string.split(/ /);
	var words = new Array();
	var result = texts;

	// Remove short words from string
	for (var i = 0; i < tmp.length; i++) {
		if(tmp[i].length > 1) { words.push(tmp[i]); }
	}
	if(words.length == 0 || result.length == 0) { return result; }

	for (var i = 0; i < words.length; i++) {
		result = hlTerm(result, words[i]);
	}

	return result;
}

function manualFilterDoc (string) {
	if(!string || string.length == 0) {
		filterGroup('all','');
		return;
	}
	if(string.length < 2) {
		return;
	}
	document.getElementById('matchedDocs').style.display = "none";
	
	var matched = iterFilterDoc(string, data, 1);
	var output = '';
	if(matched) {
		for(var i = 0; i < matched.length; i++) {
			if(matched[i].docid == activeDocID) {
				output = output + "<div class=\"result\"><div class=\"activeTitle\"><a title=\"View this page\" name=\"" + matched[i].docid + "\" href=\"" + matched[i].url + "\" onClick=\"fromGroup('manual: " + string + "');\" target=\"_blank\">" + matched[i].title + "</a>&nbsp;<img src=\"external.png\" /></div>\n";
				output = output + "<div class=\"activeSnippet\">" + matched[i].snippet + " - <a class=\"goworkspace\" href=\"#\" onClick=\"fromGroup('manual: " + string + "');showData(" + matched[i].docid + ");return false;\" title=\"Show this in Workspace\">Show&nbsp;this&nbsp;in&nbsp;Workspace</a></div>\n";
				output = output + "<div class=\"activeMisc\">" + (matched[i].docid + 1) + ": " + matched[i].curl + " - " + matched[i].size + "</div></div>\n";
			} else {
				output = output + "<div class=\"result\"><div class=\"title\"><a title=\"View this page\" name=\"" + matched[i].docid + "\" href=\"" + matched[i].url + "\" onClick=\"fromGroup('manual: " + string + "');\" target=\"_blank\">" + matched[i].title + "</a>&nbsp;<img src=\"external.png\" /></div>\n";
				output = output + "<div class=\"snippet\">" + matched[i].snippet + " - <a class=\"goworkspace\" href=\"#\" onClick=\"fromGroup('manual: " + string + "');showData(" + matched[i].docid + ");return false;\" title=\"Show this in Workspace\">Show&nbsp;this&nbsp;in&nbsp;Workspace</a></div>\n";
				output = output + "<div class=\"misc\">" + (matched[i].docid + 1) + ": " + matched[i].curl + " - " + matched[i].size + "</div></div>\n";
			}
		}
		output = iterHlTerm(output, string);
		output = output + "<p class=\"gotop\"><a href=\"javascript:window.scroll(0,0);\" title=\"Go to the top of page\">&uarr; Top</a></p></div>\n";
	}
	output = "<div class=\"glabel\">" + string + " (" + matched.length + ") <span class=\"small\">in the top 100 results</span></div>" + output;
	
	// Add find more link
	output = output + "<div><a href=\"#\" onClick=\"sendQuery();return false;\">More results for <b>" + document.getElementById('originalQuery').value + " <i>" + string + "</i></b></a></div>";
	
	// Update workspace
	document.getElementById('manualMatchedDocs').innerHTML = output;
	document.getElementById('filterword').value = string;
	filterGroup();

	return true;
}

function addFilterWord(string) {
	var filterword = document.getElementById('filterword').value;
	var newstring = '';
	if(filterword == "") {
		newstring = string;
	} else {
		newstring = filterword + " " + string;
	}
	manualFilterDoc(newstring);
	waittofade('filterword', 0);
	return true;
}

function removeFilterWord() {
	var filterword = document.getElementById('filterword').value;
	var newstring = '';
	if(filterword == "") {
		filterGroup('all','');
		return;
	}
	newstring = filterword.replace(/\w+$/, '');
	newstring = newstring.replace(/ +$/, '');
	if(newstring == "") {
		filterGroup('all','');
		return;
	}
	manualFilterDoc(newstring);
	waittofade('filterword', 0);
	return true;
}

function filterGroup(group,string) {
	var group = group;
	var string = string;
  var t = document.getElementsByTagName('div');

	document.getElementById('matchedDocs').style.display = "block";
		
	for (var i = 0; i < t.length; i++) {
		if(t[i].className == 'group') {
			if(group == 'all') {
				t[i].style.display = "block";
				document.getElementById('filterword').value = '';
			} else {
				t[i].style.display = "none";
			}
		}
	}
	if(group && string) {
		document.getElementById(group).style.display = "block";
		document.getElementById('filterword').value = string;
		document.getElementById('manualMatchedDocs').innerHTML = "<div><a href=\"#\" onClick=\"sendQuery();return false;\">More results for <b>" + document.getElementById('originalQuery').value + " <i>" + string + "</i></b></a></div>";
		waittofade('filterword', 50);
	}

    return true;
}

function groupDocs(string) {
	var string = string;
	var terms = new Array();
	terms = extractTerms(string);

	var groups = new Array();
	var docs = new Array();
	for (var i = 0; i < terms.length; i++) {
		docs = filterDoc(terms[i], data);
		groups[groups.length] = {word:terms[i], members:docs};
	}
	
	var output = '';
	var output2 = '';
	for (var i = 0; i < groups.length; i++) {
		if(groups[i].members.length == 1) {
			output2 = output2 + "<a class=\"uniqword\" href=\"#\" onClick=\"manualFilterDoc('" + groups[i].word + "');return false;\" title=\"Show the results of this keyword\">" + groups[i].word + "</a>&nbsp; ";
		} else {
			output2 = output2 + "<a class=\"filterword\" href=\"#\" onClick=\"filterGroup('group" + i + "','" + groups[i].word + "');return false;\" title=\"Show the results of this keyword\">" + groups[i].word + "&nbsp;(" + groups[i].members.length + ")</a>&nbsp;";
			output2 = output2 + "<a class=\"filterword\" href=\"#\" onClick=\"addFilterWord('" + groups[i].word + "');return false;\" title=\"Add this keyword\">+</a>&nbsp; ";

			output = output + "<div class=\"group\" id=\"group" + i + "\">\n";
			output = output + "<div class=\"glabel\">" + groups[i].word + "&nbsp;(" + groups[i].members.length + ") <span class=\"small\">in the top 100 results</span></div>\n";
			// output = output + printQForm(groups[i].word);
			
			for (var j = 0; j < groups[i].members.length; j++) {
				if(groups[i].members[j].docid == activeDocID) {
					output = output + "<div class=\"result\"><div class=\"activeTitle\"><a href=\"" + groups[i].members[j].url + "\" onClick=\"fromGroup('" + groups[i].word + "');\" title=\"View this page\" name=\"" + groups[i].members[j].docid + "\" target=\"_blank\">" + groups[i].members[j].title + "</a>&nbsp;<img src=\"external.png\" /></div>\n";
					output = output + "<div class=\"activeSnippet\">" + groups[i].members[j].snippet + " - <a class=\"goworkspace\" href=\"javascript:showData(" + groups[i].members[j].docid + ");\" onClick=\"fromGroup('" + groups[i].word + "');\" title=\"Show this in Workspace\">Show&nbsp;this&nbsp;in&nbsp;Workspace</a></div>\n";
					output = output + "<div class=\"activeMisc\">" + (groups[i].members[j].docid + 1) + ": " + groups[i].members[j].curl + "</div></div>\n";
				} else {
					output = output + "<div class=\"result\"><div class=\"title\"><a href=\"" + groups[i].members[j].url + "\" onClick=\"fromGroup('" + groups[i].word + "');\" title=\"View this page\" name=\"" + groups[i].members[j].docid + "\" target=\"_blank\">" + groups[i].members[j].title + "</a>&nbsp;<img src=\"external.png\" /></div>\n";
					output = output + "<div class=\"snippet\">" + groups[i].members[j].snippet + " - <a class=\"goworkspace\" href=\"javascript:showData(" + groups[i].members[j].docid + ");\" onClick=\"fromGroup('" + groups[i].word + "');\" title=\"Show this in Workspace\">Show&nbsp;this&nbsp;in&nbsp;Workspace</a></div>\n";
					output = output + "<div class=\"misc\">" + (groups[i].members[j].docid + 1) + ": " + groups[i].members[j].curl + "</div></div>\n";
				}
			}
			output = output + "<p class=\"gotop\"><a href=\"javascript:window.scroll(0,0);\" title=\"Go to the top of page\">&uarr; Top</a></p></div>\n";
		}
	}
	
	// Workspace query box
	output2 = output2 + "<form class=\"filterword\" onSubmit=\"return false;\"><input type=\"text\" id=\"originalQuery\" value=\"" + query + "\" /> + <input type=\"text\" id=\"filterword\" onKeyUp=\"manualFilterDoc(this.value);\" title=\"Add or type any keyword you want\"/>\n";
	output2 = output2 + "<input type=\"button\" name=\"Submit\" value=\"Search\" onClick=\"sendQuery();\"/></form>";
	
	// Update the workspace
	document.getElementById('matchedTermsList').innerHTML = output2;
	document.getElementById('matchedDocs').innerHTML = output;
}

function sendQuery() {
	var url = script + "?q=" + document.getElementById('originalQuery').value.replace(/ /g, '+') + "+" + document.getElementById('filterword').value.replace(/ /g, '+');
	window.location = url;
	return true;
}

function fromGroup(group) {
	// Just for logging
	return true;
}

function printQForm (word) {
	var word = word;
	var output = "<div class=\"querybox\">";
	output = output + "<form name=\"qform\" action=\"" + script + "\" method=\"get\" onSubmit=\"return validateQuery(this.value);\">\n";
	output = output + "<b>" + query + "</b> + <input type=\"text\" name=\"q\" class=\"upbox\" value=\"" + word + "\" />\n";
	output = output + "<input type=\"submit\" name=\"Submit\" value=\"Update Main Result\" /></form>\n";
	output = output + "</div>";
	
	return output;
}

function showData(docid) {
	var docid = docid;
	activeDocID = docid;

	document.getElementById('activeTitle').innerHTML = "<a title=\"View this page\" href=\"" + data[docid].url + "\" target=\"_blank\">" + data[docid].title + "</a>&nbsp;<img src=\"external.png\" />";
	document.getElementById('activeSnippet').innerHTML = data[docid].snippet;
	document.getElementById('activeMisc').innerHTML = data[docid].curl + " - " + data[docid].size;

	// document.getElementById('filterword').value = '';
	document.getElementById('matchedDocs').innerHTML = '';

	waittofade('active', 200);
	var vc = visualCtrl('workspace','div',1);
	var vc2 = visualCtrl('step2','div',0);

	groupDocs(data[docid].title + " " + data[docid].snippet);

	window.scroll(0,0);
}

function extractTerms(string) {
	var string = string;
	var bold = "<b>[^<]+<\/b>";
	var regex = new RegExp(bold, "ig");
	string = string.replace(regex, ''); /* Remove <b> ... </b> (i.e. queries) */
	var tokens = new Array();
	var seen = new Object();
	var terms = new Array();

	tokens = string.split(/\W+/);
	for (var i = 0; i < tokens.length; i++) {
		if(!seen[tokens[i].toLowerCase()] && !isStopword(tokens[i]) && tokens[i].length > 1 && !tokens[i].match(/^\d{1,2}$/)
		&& tokens[i] != 39 && tokens[i] != 'amp' && tokens[i] != 'quot' && tokens[i] != 'gt' && tokens[i] != 'lt') {
			terms[terms.length] = tokens[i];
			seen[tokens[i].toLowerCase()] = true;
		}
	}
	terms.sort(charOrdA);
	
	return terms;
}

/*
 * The following function, case free sorting, was taken from
 * http://javascript.about.com/library/blsort1.htm
 *
 */
function charOrdA(a, b){
	a = a.toLowerCase(); b = b.toLowerCase();
	if (a>b) return 1;
	if (a <b) return -1;
	return 0;
}

function visualCtrl (name, tag, flag) {
    var t = document.getElementsByTagName(tag);
    for (var i = 0; i < t.length; i++) {
        if (t[i].className == name) {
            t[i].style.display = (flag ? "inline" : "none");
        }
    }
    return true;
}

function submitonce(theform) {
	document.all.submit.disabled = true;
	return true;
}

function cleanString (string) {
	var string = string;
	string = string.replace(/<b>...<\/b>/g, "");
	return string.replace(/([^a-zA-Z<> ]+)/g, " ");
}

function validateQuery(value) {
	var terms = value;
	var illegalChars = '!?/\\~=_;{[]}*&|\\\'@#,';
	if (terms.length == 0) {
		alert('Please enter one or more search terms in the textbox.');
		return false;
	}
	for (var i = 0; i < terms.length; i++) {
		if (illegalChars.indexOf(terms.charAt(i)) != -1) {
			alert("Your search cannot contain any of the following characters: " + illegalChars);
			return false;
		}
	}
	// vc = visualCtrl('elapsed','p',0);

	return true;
}

/*
 * THE 37 Signal's Yellow Fade Technique
 * http://www.37signals.com/svn/archives/000558.php
 *
 * Copyright (C) 37 Signals
 *
 */
var Color= new Array();
Color[1] = "ff";
Color[2] = "ee";
Color[3] = "dd";
Color[4] = "cc";
Color[5] = "bb";
Color[6] = "aa";
Color[7] = "99";

function waittofade(x, sec) {
  if (document.getElementById(x)) {
    setTimeout("fadeIn(7,'"+x+"')", sec); // 200
  }
}

function fadeIn(where, x) {
  if (where >= 1) {
      document.getElementById(x).style.backgroundColor = "#ffff" + Color[where];
    if (where > 1) {
      where -= 1;
      setTimeout("fadeIn("+where+",'"+x+"')", 400);
    } else {
      where -= 1;
      setTimeout("fadeIn("+where+",'"+x+"')", 400);
      document.getElementById(x).style.backgroundColor = "#ffffff";
    }
  }
}

