var _clfResult = null;
var _xmlutil = new XMLUtils();
var _docElement = null;
var _clfdoc = null;
var _feedbackFlavor = 1; //0-no feedback, 1-yes/no, 2-yes/no+comment, 3-QA

function initHighlight(clfxmlElement, docElement, sidebarElement, nameTopics, nameSocialTags, nameTerms, nameRelations) {
	var docElm = id2elm(docElement);
	while (docElm.firstChild != null)
		docElm.removeChild(docElm.firstChild);
	var sidebarElm = id2elm(sidebarElement);
	while (sidebarElm.firstChild != null)
		sidebarElm.removeChild(sidebarElm.firstChild);
	// wzTooltip
	if (typeof(clf_wzTooltip) == 'undefined')
		window.clf_wzTooltip = false;
	try {
		_clfResult = new ExtractionResults();
		_clfdoc = new CLFXML(id2elm(clfxmlElement).value);
		enhanceDocument(_clfdoc);
		showDocument(_clfdoc, docElm);
		_clfResult.sort();
		showSidebar(sidebarElm, nameTopics, nameSocialTags, nameTerms, nameRelations);
	} catch (exc) {
		var errmsg = "Unsupported Document";
		if (exc.message.indexOf("CLFERROR: ") == 0)
			errmsg = exc.message.substr(10);
		var strings = errmsg.split("\n");
		docElm.appendChild(document.createTextNode(strings[0]));
		for (var i=1; i < strings.length; i++) {
			docElm.appendChild(document.createElement("BR"));
			docElm.appendChild(document.createTextNode(strings[i]));
		}
	}
}

function id2elm(idorelm) {
    if (typeof idorelm == "string")
    	idorelm = document.getElementById(idorelm);
    return idorelm;
}

// Add Frames information inside Document fragment
function enhanceDocument(clfXML) {
	var _clfXML = clfXML;
	var frameElements = [];
	function clfFrameElement(type, id, name, offset, length) {
		this.type = type; // 1->Begin, 2->End
		this.id = id;
		this.name = name; // can be null if type = 2 (End)
		this.offset = offset;
		this.length = length;
	}
	function addToFrameElementsList(frameID, meta, offset, len) {
		frameElements.push(new clfFrameElement(2, frameID, null, offset + len, len));
		frameElements.push(new clfFrameElement(1, frameID, meta._category, offset, len));
		if (frameID > 0) {
			meta['_offset'] = offset;
			meta['_length'] = len;
			_clfResult.addResult(meta._category, meta._isTerm ? meta._name : frameID.toString(), frameID, meta._isTerm, meta);
		}
	}
	function addTopic(topicName, topicScore) {
		_clfResult.addFeature("topics", topicName, topicScore);
	}
	function addSocialTag(stName, stScore) {
		_clfResult.addFeature("socialtags", stName, stScore);
	}	
	function sortFrames() {
		function sortByOffsetDesc(a, b) {
			// arrange the open & close with minimum overlapping
			if (a.offset != b.offset)
				return b.offset - a.offset;
			if (a.type != b.type)
				return a.type - b.type;
			if (a.length != b.length)
				return (a.type == 1)?a.length - b.length:b.length - a.length;
			if (a.id != b.id)
				return (a.type == 1)?a.id - b.id:b.id - a.id;
			return 0;
		}
		frameElements.sort(sortByOffsetDesc);
	}
	function sortFeatures() {
		function sortByScore(a, b) {
			return b.score - a.score;
		}
		_clfResult.getFeature('topics').sort(sortByScore);
		_clfResult.getFeature('socialtags').sort(sortByScore);
	}
	function addFramesToDocument() {
		var documentString = _clfXML.getDocumentSTR();
		var insertionStr = "";
		for(var s=0; s < frameElements.length; s++) {
			var frameElm = frameElements[s];
			if (frameElm.id < 0) {
				if (frameElm.type == 1)
					insertionStr = '<clfBTH id="' + frameElm.id + '"/>';
				else
					insertionStr = '<clfETH id="' + frameElm.id + '"/>';
			} else {
				if (frameElm.type == 1)
					insertionStr = _xmlutil.createclfBHNode(frameElm.id, frameElm.name);
				else
					insertionStr = '<clfEH id="' + frameElm.id + '"/>';
			}
			documentString = documentString.insert(insertionStr, frameElm.offset);
		}
		_clfXML.setTaggedDocument(documentString);
	}
	if (clfXML.isXSLT())
		clfxsltparserAddFrames(clfXML, addToFrameElementsList);
	else if (clfXML.isRDF())
		clfrdfparserAddFrames(clfXML, addToFrameElementsList, addTopic, addSocialTag);
	else
		clfxmlparserAddFrames(clfXML, addToFrameElementsList, addTopic);
	sortFrames();
	sortFeatures();
	addFramesToDocument();
}

// Show the Sidebar inside the htmlElement
function showSidebar(sidebarElm, nameTopics, nameSocilaTags, nameTerms, nameRelations) {
	// create the Terms & Relations part
	var htmlTopics = document.createElement("div");
	var htmlSocialTags = document.createElement("div");
	var htmlTerms = document.createElement("div");
	var htmlRelations = document.createElement("div");
	htmlTopics.id = "CLFTopicsSidebar";
	htmlSocialTags.id = "CLFSocialTagsSidebar";
	htmlTerms.id = "CLFTermsSidebar";
	htmlRelations.id = "CLFRelationsSidebar";
	var sidebarTopicsWriter = new CLFSidebarWriter(htmlTopics);
	var sidebarSocialTagsWriter = new CLFSidebarWriter(htmlSocialTags);
	var sidebarTermsWriter = new CLFSidebarWriter(htmlTerms);
	var sidebarRelationsWriter = new CLFSidebarWriter(htmlRelations);
	sidebarTopicsWriter.addHeader(nameTopics);
	sidebarSocialTagsWriter.addHeader(nameSocilaTags);
	sidebarTermsWriter.addHeader(nameTerms, true);
	sidebarRelationsWriter.addHeader(nameRelations, false);
	for (var i=0; i < _clfResult.getCategs().length; i++) {
		var categName = _clfResult.getCategs()[i];
		if (_clfResult.isTerm(categName)) {
			sidebarTermsWriter.addCategory(categName, i);
			for (var j=0; j < _clfResult.getCategTerms(categName).length; j++)
				sidebarTermsWriter.addTerm(_clfResult.getCategTerms(categName)[j], j);
		} else {
			sidebarRelationsWriter.addCategory(categName, i);
			for (var j=0; j < _clfResult.getCategTerms(categName).length; j++)
				sidebarRelationsWriter.addRelation(_clfResult.getCategTerms(categName)[j], j);
		}
	}
	// create the topics section
	var allTopics = _clfResult.getFeature('topics');
	for (var i = 0; i < allTopics.length; i++)
		sidebarTopicsWriter.addTopic(allTopics[i]['name'], allTopics[i]['score']);
	// create the social tags section
	var allSocialtags = _clfResult.getFeature('socialtags');
	for (var i = allSocialtags.length - 1; i > -1; i--)
		sidebarSocialTagsWriter.addSocialTag(allSocialtags[i]['name'], allSocialtags[i]['score']);
	// create the menu part
	var htmlMenu = document.createElement("div");
	htmlMenu.id = "CLFMenuSidebar";
	var menuElm = new SidebarElement(null, null, "CLFMenuItemsSidebar", null);
	menuElm.addCMD_CollapseExpandAll();
	menuElm.addCMD_MarkNextPrev();
	htmlMenu.appendChild(menuElm.getElement());
	
	// create the sidebar wrapper
	var htmlSidebarWrp = document.createElement("div");
	htmlSidebarWrp.id = "CLFMainSidebar";
	if (htmlTopics.childNodes.length > 1)
		htmlSidebarWrp.appendChild(htmlTopics);
	if (htmlSocialTags.childNodes.length > 1)
		htmlSidebarWrp.appendChild(htmlSocialTags);
	if (htmlTerms.childNodes.length > 1)
	    htmlSidebarWrp.appendChild(htmlTerms);
	if (htmlRelations.childNodes.length > 1)
	    htmlSidebarWrp.appendChild(htmlRelations);
	
	// add all to page
	sidebarElm.appendChild(htmlMenu);
	sidebarElm.appendChild(htmlSidebarWrp);
}

// Show the Document fragment inside the htmlElement
function showDocument(clfXML, htmlElement) {
	// display a rawtext as best as you can
	function displayTXT(str, writer) {
		var tagRX = /<(\/?)([a-zA-Z0-9_\.-]+)(\s+id="([^"><]+)")?(\s+category="([^"><]+)")?(\s+(([a-zA-Z0-9_\.-]+=["'][^"'><]*["'])|([^ <>]+=[^ <>]+)))*(\/?)>/g;
		var omitstarttags = { 'document': true, 'text': true, 'doc': true };
		var stillinstart = true;
		var currPos = 0;
		var inTable = false;
		var rxres = null;
		while (rxres = tagRX.exec(str)) {
			addString(writer, str.substring(currPos, rxres.index), inTable || behavior.parseNewLine, !inTable && behavior.parseNewLine);
			currPos = tagRX.lastIndex;
			switch (rxres[2].toLowerCase()) {
			case 'clfeh':
				writer.endHighlight(rxres[4]);
				break;
			case 'clfbh':
				writer.beginHighlight(rxres[4], rxres[6]);
				break;
			case 'clfeth':
				writer.endHighlight(rxres[4]);
				break;
			case 'clfbth':
				writer.beginHighlight(rxres[4], "TermInsideFrame");
				break;
			case 'table':
			case 'td':
			case 'th':
				break;
			case 'p':
			case 'br':
				writer.addP();
				break;
			case 'tr':
				inTable = rxres[1] != '/';
				if (rxres[1] == '')
					writer.addTableRow();
				break;
			default:
				if (rxres[1] == '') {
					if (!stillinstart || !omitstarttags[rxres[2].toLowerCase()]) {
						stillinstart = false;
						if (behavior.ShowHeaders)
							writer.addHeaderElement(rxres[2].capitalize());
						else if (! inTable)
							writer.addP();
					}
				}
			}
		}
		addString(writer, str.substring(currPos, str.length), inTable || behavior.parseNewLine, !inTable && behavior.parseNewLine);
		writer.eod();
	}
	function addString(writer, str, replaceSpace, replaceNL) {
		writer.addTextElement();
		if (replaceSpace)
			str = str.replace(/ /g, "\u00A0");
		if (replaceNL) {
			var smalltxts = str.split("\n");
			writer.appendStr(smalltxts[0]);
			for (var j = 1; j < smalltxts.length; j++) {
				writer.addP();
				if (smalltxts[j].length > 0)
					writer.appendStr(smalltxts[j]);
			}
		} else {
			writer.appendStr(str);
		}
	}
	var htmlDoc = document.createElement("div");
	htmlDoc.id = "CLFDOCRoot";
	htmlElement.appendChild(htmlDoc);
	var writer = new CLFDOCWriter(htmlDoc);
	var taggedDocument = clfXML.getTaggedDocument();
	displayTXT(taggedDocument, writer);
    _docElement = htmlDoc;
}

// change highlight all
function changeHighlightAll(turnON) {
	for (var i = 0; i < _clfResult.getCategs().length; i++)
		changeHighlight(turnON, i, -1);
}

// change highlight by terms/relations
function changeHighlightByTerm(turnON, onlyTerms) {
	for (var i = 0; i < _clfResult.getCategs().length; i++)
		if (_clfResult.isTerm(_clfResult.getCategs()[i]) == onlyTerms)
			changeHighlight(turnON, i, -1);
}

// change highlight by categ and instance
function changeHighlight(turnON, categID ,instanceID) {
	var categName = _clfResult.getCategs()[categID];
	var from = instanceID;
	var to = instanceID + 1;
	if (instanceID < 0) { // all the category
		from = 0;
		to = _clfResult.getCategTerms(categName).length;
	}
	for (var i = from; i < to; i++) {
		var termName = _clfResult.getCategTerms(categName)[i];
		for (var j = 0; j < _clfResult[categName][termName].length; j++)
			changeSingleHighlight(_clfResult[categName][termName][j], turnON);
	}
	fixCheckboxes(turnON, categID, instanceID);
}

function changeSingleHighlight(frameID, turnON) {
	var id = frameID;
	frameID = "CLFH" + frameID + ".";
	for (var j=0; j<9; j++) {
		var clfid = frameID + j
		var elm = document.getElementById(clfid);
		if (elm == null)
			break;
		if (turnON) {
// IE7 do not support css2
//				if (! RegExp('\\b' + 'CLFHighlight' + '\\b').test(elm.className))
//					elm.className += elm.className?' '+className:className;
			if (elm.className.indexOf('CLFHighlight') < 0) {
				elm.className += 'CLFHighlight';
				if (_clfResult.isTermID(id))
					elm.className += ' CLFAnyTermHighlight';
				else
					elm.className += ' CLFAnyEventHighlight';
			}
			// tootltip
			elm.onmouseover = clfShowTip;
		} else {
// IE7 do not support css2
//				var rep = elm.className.match(' CLFHighlight')?' '+className:className;
//				elm.className = elm.className.replace(rep, '');
			elm.className = elm.className.replace('CLFHighlight', '');
			if (_clfResult.isTermID(id))
				elm.className = elm.className.replace(' CLFAnyTermHighlight', '');
			else
				elm.className = elm.className.replace(' CLFAnyEventHighlight', '');
			// tootltip
			elm.onmouseover = null;
		}
	}
	changeTermInsideFrameHighlight(id, turnON);
}

function clfShowTip(e) {
	var elm = this;
	var delim = "<BR><BR>";
	var txt = new StringBuilder();
	while (elm && (elm.tagName == "SPAN" || elm.tagName == "A")) {
		if (elm.attributes && elm.attributes.id)
			if (elm.className.indexOf('CLFAnyTermHighlight') * elm.className.indexOf('CLFAnyEventHighlight') < 1 ) {
				var clfid = elm.attributes.id.value.substring(4, elm.attributes.id.value.length - 2);
				if (_clfResult.getMeta(clfid)._tooltip == null)
					_clfResult.getMeta(clfid)['_tooltip'] = convertTooltip2HTML(createTooltipFromMeta(_clfResult.getMeta(clfid)));
				txt.Append(_clfResult.getMeta(clfid)._tooltip);
				txt.Append(delim);
			}
		elm = elm.parentNode;
	}
	txt.Pop();
	txt = txt.ToString();
	clf_tolltip.gentip(txt);
	// cancel bubbling
	if (!e)
		var e = window.event;
	e.cancelBubble = true;
	if (e.stopPropagation)
		e.stopPropagation();
}

function createTooltipFromMeta(meta) {
	var tooltip = new StringBuilder();
	if (meta._isTerm) {
		tooltip.Append(meta._name);
		tooltip.Append(' (');
		tooltip.Append(meta._category.addSpaces());
		tooltip.Append(')');
	} else
		tooltip.Append(meta._category.addSpaces());
	if (meta._relevance != null) {
		tooltip.Append('\n Relevance: ');
		tooltip.Append(meta._relevance);
		tooltip.Append('%');
	}
	if (meta._count != null) {
		tooltip.Append('\n Count: ');
		tooltip.Append(meta._count);
	}
	for (var k in meta) {
		if (k.indexOf('_') == 0 || meta[k] == null)
			continue;
		tooltip.Append('\n ');
		tooltip.Append(k.replace(/\d+$/, ""));
		tooltip.Append(': ');
		if (meta[k].length > 40) {
			tooltip.Append(meta[k].substr(0,38));
			tooltip.Append('...');
		} else
			tooltip.Append(meta[k]);
	}
	return tooltip.ToString();
}

function convertTooltip2HTML(tooltip) {
	var buf = new StringBuilder();
	addTooltipAsHTML(buf, tooltip);
	return buf.ToString();
}

function addTooltipAsHTML(buffer, tooltip) {
	tooltip = tooltip.replace(/ /g, '&nbsp;');
	var lines = tooltip.split('\n');
	buffer.Append("<b>");
	buffer.Append(lines[0]);
	buffer.Append("</b>");
	for (var i=1; i<lines.length; i++) {
		buffer.Append("<br>");
		buffer.Append(lines[i]);
	}
}

function changeTermInsideFrameHighlight(frameID, turnON) {
	if (_clfResult.isTermID(frameID))
		return;
	var termID = frameID * -1;
	termID = "CLFH" + termID + ".";
	for (var j=0; j<9; j++) {
		var clfid = termID + j
		var elm = document.getElementById(clfid);
		if (elm == null)
			break;
		if (turnON) {
			if (elm.className.indexOf('CLFHighlight') < 0)
				elm.className += 'CLFHighlight';
		} else {
			elm.className = elm.className.replace('CLFHighlight', '');
		}
	}
}

function toggleInstancesVisibility(categID) {
	var insDiv = document.getElementById("CLFSBInstances" + categID);
	var insImg = document.getElementById("toggleVisibilityImage" + categID);
	if (insDiv.style.display == "none") {
		insDiv.style.display = "block";
		insImg.src = _imagePath + "/collapsesmall.gif";
	} else {
		insDiv.style.display = "none";
		insImg.src = _imagePath + "/expandsmall.gif";
	}
}

function collapseExpandAll(collapse) {
	var i = 0;
	while (true) {
		var insDiv = document.getElementById("CLFSBInstances" + i);
		var insImg = document.getElementById("toggleVisibilityImage" + i);
		if (insDiv == null)
			break;
		if (collapse) {
			insDiv.style.display = "none";
			insImg.src = _imagePath + "/expandsmall.gif";
		} else {
			insDiv.style.display = "block";
			insImg.src = _imagePath + "/collapsesmall.gif";
		}
		i++;
	}
}

function getState() {
	var ret = "";
	var i = 0;
	while (true) {
		var insDiv = document.getElementById("CLFSBInstances" + i);
		if (insDiv == null)
			break;
		var sbDiv = document.getElementById("CLFSideBar." + i + ".-1");
		var name = sbDiv.nextSibling.data;
		var select = sbDiv.src.charAt(sbDiv.src.length-5) == 'V';
		var open = insDiv.style.display.length != 4;
		ret += name + "," + open + "," + select + ";";
		i++;
	}
	return ret;
}

function setState(state) {
	var openListHash = new Object();
	var selectListHash = new Object();
	if (state == null)
		return;
	var line = state.split(";");
	for (var i=0; i<line.length; i++) {
		var vals = line[i].split(",");
		if (vals.length != 3)
			continue;
		if (vals[1].length == 4)
			openListHash[vals[0]] = "";
		if (vals[2].length == 4)
			selectListHash[vals[0]] = "";
	}
	var i = 0;
	while (true) {
		var sbDiv = document.getElementById("CLFSideBar." + i + ".-1");
		if (sbDiv == null)
			break;
		var name = sbDiv.nextSibling.data.toLowerCase();
		if (openListHash[name] == null)
			toggleInstancesVisibility(i);
		changeHighlight(selectListHash[name] != null, i, -1);
		i++;
	}
}

function fixCheckboxes(turnON, categID, instanceID) {
	function getCheckboxElemByID(categID, instanceID) {
		return document.getElementById("CLFSideBar." + categID + "." + instanceID);
	}
	function changeState(element, turnON) {
		if (turnON == null)
			element.src = element.src.replace(/.\.gif/, "C.gif");
		else if (turnON)
			element.src = element.src.replace(/.\.gif/, "V.gif");
		else
			element.src = element.src.replace(/.\.gif/, "X.gif");
	}
	function isCheck(element) {
		return (element.src.charAt(element.src.length - 5) == "V");
	}
	// fix himself
	changeState(getCheckboxElemByID(categID, instanceID), turnON);
	// fix others
	if (instanceID < 0) {
		// turnON categ:
		//   * check all terms of categ
		// turnOFF categ:
		//   * uncheck all terms of categ
		for (var i = 0; i < 999; i++) {
			var checkElem = getCheckboxElemByID(categID, i);
			if (checkElem == null)
				break;
			changeState(checkElem, turnON);
		}
		return;
	}
	// CATEG: check / uncheck / intermediate
	var thereischecked = false;
	var thereisunchecked = false;
	for (var i = 0; true; i++) {
		var checkElem = getCheckboxElemByID(categID, i);
		if (checkElem == null)
			break;
		if (isCheck(checkElem))
			thereischecked = true;
		else
			thereisunchecked = true;
	}
	if (thereischecked && thereisunchecked)
		changeState(getCheckboxElemByID(categID, -1), null);
	else
		changeState(getCheckboxElemByID(categID, -1), thereischecked);
}
