//alert("whitesmoke_plugin.local.js");
/*
function WSEnrichmentEngineCollection() {
	this.documentBasePath = null;
	this.documentURL = null;
	this.baseURL = ''; //whitesmoke_plugin',
	this.srcMode = '';
	this.activeEngine = null;
	this.loadedFiles = new Array();
	this.engines = new Array();
	
	this.createEngine = function(settings, editor) {
		var editorNumber = this.engines.length;
		var new_engine = new WSEnrichmentEngine(settings, editor, editorNumber);
		new_engine.initialize();
		this.engines.push(new_engine);
		this.engines[wsEngine.editor.id] = new_engine;
		return new_engine;
	}
}
var g_wsEngineCollection = new WSEnrichmentEngineCollection();
g_wsEngineCollection.init(); //move this call to constructor
*/

var g_oWSEnrichmentsArray = new Array();
/********************************************************************************
Class WhiteSmokePluginEngine
********************************************************************************/
function WhiteSmokePluginEngine() {
	this.documentBasePath = null;
	this.documentURL = null;
	this.baseURL = ''; //whitesmoke_plugin',
	this.srcMode = '';
	this.activeEngine = null;
	this.loadedFiles = [];
}
WhiteSmokePluginEngine.prototype = {
	init: function() {
		this.documentBasePath = document.location.href;
		var pos = this.documentBasePath.indexOf('?');
		if (pos != -1) {
			this.documentBasePath = this.documentBasePath.substring(0, pos);
		}
		this.documentURL = this.documentBasePath;
		this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.lastIndexOf('/'));
		if (!this.baseURL) {
			var elements = [];
			var nl, i, head, baseHREF = '';
			head = document.getElementsByTagName('head')[0];
			if (head) {
				for (i = 0, nl = head.getElementsByTagName('script'); i < nl.length; i++) 
					elements.push(nl[i]);
			}
			for (i = 0, nl = document.getElementsByTagName('script'); i < nl.length; i++)
				elements.push(nl[i]);
			nl = document.getElementsByTagName('base');
			for (i = 0; i < nl.length; i++) {
				if (nl[i].href) baseHREF = nl[i].href;
			}
			for (i = 0; i < elements.length; i++) {
				if (elements[i].src && 
					(elements[i].src.indexOf("whitesmoke_plugin.js") != -1 || 
					 elements[i].src.indexOf("whitesmoke_plugin_src.js") != -1 || 
					 elements[i].src.indexOf("whitesmoke_plugin_dev.js") != -1 || 
					 elements[i].src.indexOf("whitesmoke_plugin.local.js") != -1))
				{
					src = elements[i].src;
					this.srcMode = (src.indexOf('_src') != -1) ? '_src': '';
					this.srcMode = (src.indexOf('_dev') != -1) ? '_src': this.srcMode;
					src = src.substring(0, src.lastIndexOf('/'));
					if (baseHREF !== '' && src.indexOf('://') == -1)
						this.baseURL = baseHREF + src;
					else
						this.baseURL = src;
					//alert("this.baseURL = " + this.baseURL);
					break;
				}
			}
		}
 		//this.loadCSS("css/whitesmoke_popup.css");
		//this.loadCSS("whitesmoke_plugin/css/whitesmoke_popup.css");
	},
	loadCSS: function(url) {
		var ar = url.replace(/\s+/, '').split(',');
		var skip = false;
		for (var x = 0, csslen = ar.length; x < csslen; x++) {
			if (ar[x] != null && ar[x] != 'null' && ar[x].length > 0) {
				for (var i = 0; i < this.loadedFiles.length; i++) {
					if (this.loadedFiles[i] == ar[x]) {
						skip = true;
						break;
					}
				}
				if (!skip) {
					document.write('<link href="' + ar[x] + '" rel="stylesheet" type="text/css" />');
					this.loadedFiles[this.loadedFiles.length] = ar[x];
				}
			}
		}
	},
	importCSS: function(doc, css) {
		var css_ary = css.replace(/\s+/, '').split(',');
		var csslen, elm, headArr, x, css_file;
		for (x = 0, csslen = css_ary.length; x < csslen; x++) {
			css_file = css_ary[x];
			if (css_file != null && css_file != 'null' && css_file.length > 0) {
				if (css_file.indexOf('://') == -1 && css_file.charAt(0) != '/') css_file = this.documentBasePath + "/" + css_file;
				WSDebug.log("Adding stylesheet: " + css_file, "WhiteSmoke.importCSS");
				if (typeof(doc.createStyleSheet) == "undefined") {
					elm = doc.createElement("link");
					elm.rel = "stylesheet";
					elm.href = css_file;
					if ((headArr = doc.getElementsByTagName("head")) != null && headArr.length > 0) {
						headArr[0].appendChild(elm);
					}
				} else {
					WSDebug.log("using createStyleSheet", "importCSS");
					doc.createStyleSheet(css_file);
				}
			}
		}
	},
	//add to object c all the properties of object m (c inherit m)
	add: function(c, m) {
		var n;
		for (n in m) {
			if (m.hasOwnProperty(n)) {
				c.prototype[n] = m[n];
			}
		}
	},
	extend: function(c, m) {
		var n;
		for (n in m) {
			if (m.hasOwnProperty(n))
				c[n] = m[n];
		}
	},
	cleanWSContentById: function(sContent, sIdPrefix, sTagName) {
		var sNewContent = "";
		var nPos = 0;
		for (; nPos < sContent.length; ++nPos) {
			var j = sContent.indexOf(sIdPrefix, nPos);
			if (j >= 2 && (sContent.charAt(j - 1) == "=" || sContent.charAt(j - 2) == "=")) {
				while (sContent.charAt(j) != "<") {--j;
				}
				if (j >= 0) {
					sNewContent += sContent.substr(nPos, j - nPos);
					var nStart = sContent.indexOf(">", j);
					if (nStart >= 0) {++nStart;
						var nEnd = sContent.indexOf("</", nStart);
						if (nEnd >= 0) {
							sNewContent += sContent.substr(nStart, nEnd - nStart);
							var tag = "</" + sTagName + ">";
							nPos = nEnd + tag.length - 1;
						} else {}
					} else {}
				}
			} else {
				sNewContent += sContent.substr(nPos);
				break;
			}
		}
		return sNewContent;
	},
	cleanWSContent: function(sContent) {
		var sNewContent = this.cleanWSContentById(sContent, "wsWord", "span");
		return sNewContent;
	},
	createEngine: function(settings, editor) {
		//return g_oWSEnrichmentsArray.createEngine(settings, editor);
		var editorNumber = g_oWSEnrichmentsArray.length;
		var wsEngine = new WSEnrichmentEngine(settings, editor, editorNumber);
		wsEngine.initialize();
		g_oWSEnrichmentsArray.push(wsEngine);
		g_oWSEnrichmentsArray[wsEngine.editor.id] = wsEngine;
		return wsEngine;
	}
};

var whitesmokePlugin = new WhiteSmokePluginEngine();
whitesmokePlugin.init();

/********************************************************************************
Class WSTemplate
********************************************************************************/
function WSTemplate(str) {
	this.template = str.toString();
	this.pattern = /(^|.|\r|\n)(#\{(.*?)\})/;	

	this.evaluate = function(var_object) {
		var source = this.template;
		var result = '';
		var	match_res;
		
		while (source.length > 0) {
			if (match_res = source.match(this.pattern)) {
				//alert(source + " " + source[match_res.index]);
				result += source.slice(0, match_res.index);
				result += this.matchResult(match_res,var_object);
				source = source.slice(match_res.index + match_res[0].length);
			} else {
				result += source,
				source = '';
			}
		}
		return result;
	};
	this.matchResult = function(match_res, var_object) {
		//alert("match_res[1]=" + match_res[1] + ", match_res[2]=" + match_res[2] + ", match_res[3]= " + match_res[3]);
		var before = match_res[1];
		if (before == '\\') return match_res[2];
		return before + this.interpret(var_object[match_res[3]]);
	};
	this.interpret = function(value) {
		return value == null ? '': String(value);
	};
}
/********************************************************************************
Class WSEnrichmentRecord
********************************************************************************/
function WSEnrichmentRecord(sWord, nPos, nLength, nLangType, nWordCount) {
	this.sWord = sWord;
	this.nPos = nPos;
	this.nLength = nLength;
	this.nLangType = nLangType;
	this.nWordCount = nWordCount;
	this.grammar = new Array();
	this.spelling = new Array();
	this.thesaurus = new Array();
	this.enrichment = new Array();
	this.dictionary = new Array();
	
	this.enrichType = {
		MATCHING: 3,
		THESAURUS: 4,
		IDIOM: 5,
		SPELL: 6,
		GRAMMAR: 7,
		DICTIONARY: 8
	};
	
	this.add = function(nEnrichType, sWord, nScore) {
		switch (nEnrichType) {
		case this.enrichType.MATCHING:
			this.enrichment.push(sWord);
			break;
		case this.enrichType.THESAURUS:
			this.thesaurus.push(sWord);
			break;
		case this.enrichType.IDIOM:
			break;
		case this.enrichType.SPELL:
			this.spelling.push(sWord);
			break;
		case this.enrichType.GRAMMAR:
			this.grammar.push(sWord);
			break;
		case this.enrichType.DICTIONARY:
			this.dictionary.push(sWord);
			break;
		default:
			alert("Unsupported enrich type: " + nEnrichType);
		}
	}
}	

/*************************************************************************************
Class WSSummaryResult
*************************************************************************************/
function WSSummaryResult() {
	this.enumEnrichType = {
		MATCHING: 3,
		THESAURUS: 4,
		IDIOM: 5,
		SPELL: 6,
		GRAMMAR: 7,
		DICTIONARY: 8
	};
	this.arrSummary = new Array();
	this.enrichments = 0;
	this.spelling = 0;
	this.grammar = 0;
	this.scoreMsg = "";

	this.add = function(nWordIndex, nEnrichType) {
		//if (this.arrSummary.indexOf(nWordIndex) != -1) {
		if (WSUtils.arrayFind(this.arrSummary,nWordIndex) != -1) {
			return;
		}	
		this.arrSummary.push(nWordIndex);
		switch (nEnrichType) {
			case this.enumEnrichType.THESAURUS:
				this.enrichments++;
				break;
			case this.enumEnrichType.SPELL:
				this.spelling++;
				break;
			case this.enumEnrichType.GRAMMAR:
				this.grammar++;
				break;
		}
	}
}

/********************************************************************************
Class WSEnrichmentEngine
********************************************************************************/
function WSEnrichmentEngine(settings, editor, editorNumber) {
	this.editor = editor;
	this.config = new WSConfiguration();
	this.config.merge(settings);
	this.editorNumber = editorNumber;
	this.gui = new WSGUI(this);
	
	this.sContent = ""; //(this.config.sInitailContent ? this.config.sInitailContent: "");
	this.nPrevKeyCode = null;
	
	this.vTokens = new Array();
	this.vSentenceInfo = new Array();
	this.sOriginalContent = this.sContent;
	this.vEnrichment = new Array();
	this.vAddedWords = new Array();
	this.sParent = "parent";
	this.oParent = parent;
	this.nSelectedIndex = -1;
	this.state = "";
	this.timerID = null;
	this.vDictionaryCache = new Array();
	this.bUndoMode = false; //indicates if an action is generated from an undo command.
	this.undoInfo = new Array();
	this.redoInfo = new Array();
	this.stLastPointedInfo = {
		e: null,
		oMousePos: null,
		sWord: "",
		nLangTYpe: 0,
		nIndex: 0,
		oElement: null,
		vDictionary: new Array()
	};
	this.stPrevElementStyle = {};
	this.vTemplatesMenu = new Array();
}

WSEnrichmentEngine.prototype = {
	initLoops: 100,
	initialize: function() {
		var self = this;
		
		var bHasLoaded = WSUtils.hasFrameFinishedLoaded(this.editor.getInstance());
		//alert("this.initLoops=" + this.initLoops + " bHasLoaded=" + bHasLoaded);
		if (! bHasLoaded) {
			if (this.initLoops--) {
				setTimeout(function() {self.initialize();},20);
				WSDebug.log("Postponing initialize", "initialize");
			} else {
				WSDebug.log("Failed initialize", "initialize");
			}
			//alert(this.editor.getInstance());
			return;
		}
		//whitesmokePlugin.importCSS(this.editor.getDoc(), "css/content.css");
		//whitesmokePlugin.importCSS(this.editor.getDoc(), "whitesmoke_plugin/css/content.css");
		/*
		if (WSUtils.isMSIE) {
			var doc = this.editor.getDoc().body;
			var m = WSDomUtils.getStyle(doc, "margin-bottom");
			if (!parseInt(m)) doc.style.marginBottom = "1px";
		}
		*/
		//whitesmokePlugin.importCSS(this.editor.getDoc(), "css/content.css");
		//whitesmokePlugin.importCSS(this.editor.getDoc(), "whitesmoke_plugin/css/content.css");
		if (this.config.autoCreateToolBar) {
			this.createToolBar();
		}
		this.gui.createUIElements();
		this.attachUIEvents();
		if (this.config.autoCheck.onInit) {
			this.updateContent();
		}
	},
	destroy: function() {},
	createToolBar: function() {
		var items = this.config.toolbar.items.split(",");
		var toolbar_src = "";
		for (var i = 0; i < items.length; i++) {
			toolbar_src += this.createToolBarItemHTML(items[i]);
		}
		var t = new WSTemplate(this.config.toolbar.snippet);
		var str = t.evaluate({
			menubaritems: toolbar_src
		});
		var d = document.createElement("div");
		d.innerHTML = str;
		this.editor.getInstance().parentNode.appendChild(d.firstChild);
	},
	createToolBarItemHTML: function(item) {
		var t = new WSTemplate(this.config.toolbar.itemSnippet);
		//alert(whitesmokePlugin.baseURL + "/images/" + item + ".gif");
		var self = this;
		return t.evaluate({
			//action: "void(whitesmokePlugin.doCommand('" + item + "','" + this.editor.id + "'));",
			action: function() {self.doCommand(item)},
			buttonUrl: whitesmokePlugin.baseURL + "/images/" + item + ".gif"
		});
	}
}

WSEnrichmentEngine.prototype.cleanWSContentById = whitesmokePlugin.cleanWSContentById;
WSEnrichmentEngine.prototype.cleanWSContent = whitesmokePlugin.cleanWSContent;

WSEnrichmentEngine.prototype.doCommand = function(comm) {
	//alert("comm = " + comm + ");
	switch (comm) {
		case "spellcheck":
			this.updateContent();
			break;
		case "redo":
			this.redo();
			break;
		case "undo":
			this.undo();
			break;
		case "config":
			this.openConfigWindow();
			break;
		case "debug":
			WSDebug.openDebugWindow();
			break;
	}
}	
WSEnrichmentEngine.prototype.free = function() {
	this.removeEventHandler();
	this.sContent = null;
	this.vTokens = null;
	this.vEnrichment = null;
	this.vDictionaryCache = null;
	this.editor.setContent("");
}
WSEnrichmentEngine.prototype.getElementById = function(sId) {
	return this.editor.getDoc().getElementById(sId);
}
WSEnrichmentEngine.prototype.getElementByIndex = function(nIndex) {
	var sId = "wsWord" + nIndex;
	return this.getElementById(sId);
}
WSEnrichmentEngine.prototype.openConfigWindow = function() {
	var width = 500;
	var height = 400;
	var options = "";
	var url = whitesmokePlugin.baseURL + "/config.htm";
	var win = "ConfigWindow";
	var leftPos = (screen.availWidth - width) / 2;
	var topPos = (screen.availHeight - height) / 2;
	options += 'width=' + width + ',height=' + height + ',top=' + topPos + ',left=' + leftPos;
	window.open(url, win, options);
}

WSEnrichmentEngine.prototype.getEnrichmentInfo = function(sResponseBody, vTokens) {
	this.warningMessage = "";
	var wsSummary = new WSSummaryResult();

	if (sResponseBody.length == 0) {
		return;
	}
	var vResponse = sResponseBody.split("\n");
	var nWords = parseInt(vResponse[0]);
	var nSize = vResponse.length - 1;
	var sEnrichmentInfo = "";
	var vEnrichInfo = new Array();
	var nTokenOffset = 0;
	for (var j = 0; j < nWords; ++j) {
		var i = j * 9 + 1;
		var nWordIndex = parseInt(vResponse[i]);
		var nWordCount = parseInt(vResponse[i + 2]);
		var nLangType = parseInt(vResponse[i + 3]);
		var nEnrichType = parseInt(vResponse[i + 4]);
		var nScore = parseInt(vResponse[i + 5]);
		var sEnrichWord = vResponse[i + 8];
		wsSummary.add(nWordIndex,nEnrichType);
		if (nWordIndex == -1) {
			if (nEnrichType == 1 || nEnrichType == 2) {
				this.warningMessage = sEnrichWord;
			}
			else if (nEnrichType == 8) {}
			else if (nEnrichType == 9) { //TEXT_STATISTICS
				wsSummary.scoreMsg = this.getStatisticsScore(sEnrichWord);
			}
		}
		else {
			if (!vEnrichInfo[nWordIndex]) {
				var nTokenIndex = nWordIndex + nTokenOffset;
				nTokenOffset += nWordCount - 1;
				var oToken = vTokens[nTokenIndex];
				if (!oToken) {
					vEnrichInfo = [];
					return;
				}
				var nPos = parseInt(oToken.nPos);
				var oTmpToken = vTokens[nTokenIndex + nWordCount - 1];
				var nLength = (parseInt(oTmpToken.nPos) - nPos) + parseInt(oTmpToken.nLength);
				var sWord = "";
				for (var k = 0; k < nWordCount; ++k) {
					if (sWord.length > 0) {
						sWord += " ";
					}
					sWord += vTokens[nTokenIndex + k].sWord;
				}
				//alert("vEnrichInfo["+nWordIndex+"]=("+sWord+","+nPos+","+nLength+","+nLangType+","+nWordCount+")");
				vEnrichInfo[nWordIndex] = new WSEnrichmentRecord(sWord, nPos, nLength, nLangType, nWordCount);
			}
			vEnrichInfo[nWordIndex].add(nEnrichType, sEnrichWord, nScore);
		}
	}
	nTokenOffset = 0;
	for (var i = 0; i < vTokens.length; ++i) {
		if (i < vEnrichInfo.length && vEnrichInfo[i]) {
			nTokenOffset += vEnrichInfo[i].nWordCount - 1;
		} else {
			var j = i + nTokenOffset;
			if (j < vTokens.length) {
				vEnrichInfo[i] = new WSEnrichmentRecord(vTokens[j].sWord, vTokens[j].nPos, vTokens[j].nLength, 0, 1);
			}
		}
	}
	this.gui.displaySummaryNotice(wsSummary);
	return this.wsConvertToEnrichmentInfo(vEnrichInfo);
}

WSEnrichmentEngine.prototype.getStatisticsScore = function(sStatsMessage) {
	//var val = WSDomUtils.getElementValueById(sStatsMessage,"span","wsAftaha_score");
	var val = WSDomUtils.getElementValueById(sStatsMessage,"div","wsFinalScore");
	return val;
}

WSEnrichmentEngine.prototype.wsConvertToEnrichmentInfo = function(vEnrichInfo) {
	var vEnrichment = new Array();
	for (var i = 0; i < vEnrichInfo.length; ++i) {
		var enrichment = vEnrichInfo[i];
		if (enrichment) {
			vEnrichment[vEnrichment.length] = {
				sWord: enrichment.sWord,
				nPos: enrichment.nPos,
				nLength: enrichment.nLength,
				nLangType: enrichment.nLangType,
				s: enrichment.spelling,
				g: enrichment.grammar,
				t: enrichment.thesaurus,
				e: enrichment.enrichment,
				d: enrichment.dictionary
			};
		}
	}
	return vEnrichment;
}

WSEnrichmentEngine.prototype.showContent = function() {
	WSDebug.log("showContent");
	var sContent = this.getEnrichedContent();
	this.editor.setContent(sContent);
	if (this.warningMessage.length > 0) {
		this.gui.showWarningMsg(this.warningMessage);
		this.warningMessage = "";
	}
	setTimeout(this.simpleClosure(this.setWordsEventHandler), 70);
	return true;
}
/*************************************************************************************/
WSEnrichmentEngine.prototype.simpleClosure = function(aMethod) {
	var obj = this;
	return function() {
		aMethod.apply(obj)
	};
}
WSEnrichmentEngine.prototype.eventClosure = function(aMethod) {
	var obj = this;
	return function(e) {
		aMethod.apply(obj, [e])
	};
}

WSEnrichmentEngine.prototype.getSuggestionsLength = function(enrichment) {
	var nLength = 0;
	if (enrichment) {
		if (enrichment.s && enrichment.s.length > 0) {
			nLength = enrichment.s.length;
		} else if (enrichment.g && enrichment.g.length > 0) {
			nLength = enrichment.g.length;
		} else if ((enrichment.t && enrichment.t.length > 0) || (enrichment.e && enrichment.e.length > 0)) {
			nLength = Math.max(enrichment.t.length, enrichment.e.length);
		}
	}
	return Math.min(nLength, this.config.nMaxSuggestions);
}
WSEnrichmentEngine.prototype.getVectorWidth = function(vSuggestions) {
	var nMaxWidth = 0;
	if (vSuggestions) {
		for (var i = 0; i < vSuggestions.length; ++i) {
			if (nMaxWidth < vSuggestions[i].length) {
				nMaxWidth = vSuggestions[i].length;
			}
		}
	}
	return nMaxWidth;
}
WSEnrichmentEngine.prototype.getSuggestionsWidth = function(enrichment) {
	var nMaxWidth = 0;
	if (enrichment) {
		if (enrichment.s && enrichment.s.length > 0) {
			nMaxWidth = Math.max(8, this.getVectorWidth(enrichment.s)) + 3;
		} else if (enrichment.g && enrichment.g.length > 0) {
			nMaxWidth = Math.max(8, this.getVectorWidth(enrichment.g)) + 3;
		} else if ((enrichment.t && enrichment.t.length > 0) || (enrichment.e && enrichment.e.length > 0)) {
			var nMax1 = 0,
			nMax2 = 0;
			if (enrichment.t && enrichment.t.length > 0) {
				nMax1 = Math.max(10, this.getVectorWidth(enrichment.t)) + 3;
			}
			if (enrichment.e && enrichment.e.length > 0) {
				nMax2 = Math.max(10, this.getVectorWidth(enrichment.e)) + 3;
			}
			nMaxWidth = nMax1 + nMax2;
		}
	}
	var pxWidth = nMaxWidth * 8;
	return pxWidth;
}
WSEnrichmentEngine.prototype.onHandleKeyUp = function(e) {
	var nKeyCode = e.keyCode;
	if (nKeyCode == 27) {
		this.hideSuggestions();
	}
	if (nKeyCode != this.nPrevKeyCode) {
		var sKeyValue = String.fromCharCode(nKeyCode);
		if (nKeyCode == 190 || nKeyCode == 46 || sKeyValue == ".") {
			this.nPrevKeyCode = nKeyCode;
			if (this.config.autoCheck.whileTyping) {
				this.updateContent();
			}
		}
		if ((nKeyCode >= 65 && nKeyCode <= 90) || (nKeyCode >= 97 && nKeyCode <= 122)) {
			this.nPrevKeyCode = nKeyCode;
		}
		return true;
	}
	return true;
}
WSEnrichmentEngine.prototype.onHandleMouseUp = function(e) {
	this.hideSuggestions();
	return false;
}
WSEnrichmentEngine.prototype.onMouseClickWord = function(e) {
	this.hideSuggestions();
	WSSharedEnrichmentEngine.stopDictionaryTimer();
	if (e) {
		var oElement = WSDomUtils.getEventElement(e);
		if (!oElement) {
			return false;
		}
		var sWord = oElement.innerHTML;
		var nSelectedIndex = this.getElementIndex(oElement);
		while (nSelectedIndex < 0 && oElement.parentNode) {
			oElement = oElement.parentNode;
			nSelectedIndex = this.getElementIndex(oElement);
		}
		var enrichment = this.vEnrichment[nSelectedIndex];
		if (enrichment) {
			if (enrichment.s && enrichment.s.length > 0) {
				this.showSpellingSuggestions(e, nSelectedIndex);
			}
			else if (enrichment.g && enrichment.g.length > 0) {
				this.showGrammarSuggestions(e, nSelectedIndex);
			}
			else if ((enrichment.t && enrichment.t.length > 0) || (enrichment.e && enrichment.e.length > 0)) {
				this.showEnrichmentSuggestions(e, nSelectedIndex);
			}
		}
	}
	return false;
}
WSEnrichmentEngine.prototype.setWordsEventHandler = function() {
	if (!this.closures) this.closures = [];
	this.closures["onMouseClickWord"] = this.eventClosure(this.onMouseClickWord);
	for (var nIndex = 0; nIndex < this.vEnrichment.length; ++nIndex) {
		var oElement = this.getElementByIndex(nIndex);
		if (oElement) {
			//WSDomUtils.addEvent(oElement, "contextmenu",this.closures["onMouseClickWord"]);
			WSDomUtils.addEvent(oElement, "mouseup", this.closures["onMouseClickWord"]);
		}
	}
}
WSEnrichmentEngine.prototype.onHandleResize = function() {
	this.hideSuggestions();
	var oFeedback = this.gui.getFeedbackElement();
	if (WSDomUtils.isVisible(oFeedback)) {
		WSUtils.centerElement(oFeedback,window);
	}
	//this.hideProgressBar();
}

WSEnrichmentEngine.prototype.onContextMenu = function(e) {
	WSUtils.stopPropagation(e);
}

WSEnrichmentEngine.prototype.attachUIEvents = function() {
	var oEditorWin = this.editor.getWin();
	
	if (!this.closures) {
		this.closures = {};
		this.closures.onHandleKeyUp    = this.eventClosure(this.onHandleKeyUp);
		this.closures.onHandleMouseUp  = this.eventClosure(this.onHandleMouseUp);
		this.closures.onMouseClickWord = this.eventClosure(this.onMouseClickWord);
		this.closures.onHandleResize   = this.eventClosure(this.onHandleResize);
		this.closures.onContextMenu   = this.eventClosure(this.onContextMenu);
		
	}
	if (oEditorWin) {
		//WSDomUtils.addEvent(oEditorWin.document, 'keyup',     this.closures.onHandleKeyUp);
		WSDomUtils.addEvent(oEditorWin.document, 'mousedown', this.closures.onHandleMouseUp);
		WSDomUtils.addEvent(oEditorWin.document, 'mousedown', this.closures.onMouseClickWord);
		WSDomUtils.addEvent(oEditorWin.document, "contextmenu", this.closures.onContextMenu);
		WSDomUtils.addEvent(oEditorWin, 'resize', this.closures.onHandleResize);
		//WSDomUtils.addEvent(oEditorWin.document, 'selectstart', this.closures.onContextMenu);
		//WSDomUtils.addEvent(oEditorWin.document, 'dragstart', this.closures.onContextMenu);
			
		//WSDomUtils.addEvent(oEditorWin,'resize',function(){self.onHandleResize();});
		//WSDomUtils.addEvent(oEditorWin,'resize',this.eventClosure(this.onHandleResize));
		//WSDomUtils.addEvent(oEditorWin,'resize',self.onResize());
	}
}
WSEnrichmentEngine.prototype.removeEventHandler = function() {
	WSDebug.warning("removing events...", "removeEventHandler");

	var oEditorWin = this.editor.getWin();
	if (!this.closures) return;
	if (oEditorWin && this.closures) {
		//WSDomUtils.removeEvent(oEditorWin.document, 'keyup',     this.closures.onHandleKeyUp);
		WSDomUtils.removeEvent(oEditorWin.document, 'mousedown', this.closures.onHandleMouseUp);
		WSDomUtils.removeEvent(oEditorWin.document, 'mousedown', this.closures.onMouseClickWord);
		WSDomUtils.removeEvent(oEditorWin.document, "contextmenu", this.closures.onContextMenu);
		WSDomUtils.removeEvent(oEditorWin, 'resize', this.closures.onHandleResize);		
	}
	for (var nIndex = 0; nIndex < this.vEnrichment.length; ++nIndex) {
		var oElement = this.getElementByIndex(nIndex);
		if (oElement) {
			WSDomUtils.removeEvent(oElement, "mouseup", this.closures["onMouseClickWord"]);
			WSDomUtils.removeEvent(oElement, "mouseover", this.closures["onMouseOverWord"]);
			WSDomUtils.removeEvent(oElement, "mouseout", this.closures["onMouseOutWord"]);
		}
	}
}
WSEnrichmentEngine.prototype.getEnrichedContent = function() {
	var sContent = "";
	var nPrevPos = 0;
	var bBodyExist = false;
	var nBodyPos = this.sContent.indexOf("<body");
	if (nBodyPos < 0) {
		nBodyPos = this.sContent.indexOf("<BODY");
	}
	if (nBodyPos >= 0) {
		WSDebug.warning("Unexpected existance of body", "getEnrichedContent");
		bBodyExist = true;
		nBodyPos += 5;
		sContent += this.sContent.substr(0, nBodyPos);
		var nEndTagPos = this.sContent.indexOf(">", nBodyPos);
		if (nEndTagPos && nEndTagPos >= 0) {++nEndTagPos;
			sContent += this.sContent.substr(nBodyPos, nEndTagPos - nBodyPos);
			nPrevPos = nEndTagPos;
		}
	}
	for (var i = 0; i < this.vEnrichment.length; ++i) {
		var enrichment = this.vEnrichment[i];
		var nPos = enrichment.nPos;
		var nLength = enrichment.nLength;
		var nLangType = enrichment.nLangType;
		var sWord = this.sContent.substr(nPos, nLength);
		for (var j = 0; j < this.vAddedWords.length; ++j) {
			var nTmpPos = this.vAddedWords[j].nPos;
			var nTmpLength = this.vAddedWords[j].nLength;
			var nTmpIndex = this.vAddedWords[j].nIndex;
			var nTmpLangType = this.vAddedWords[j].nLangType;
			if (nTmpPos > nPrevPos && nTmpPos < nPos) {
				sContent += this.sContent.substr(nPrevPos, nTmpPos - nPrevPos);
				var sEnrichedWord = this.sContent.substr(nTmpPos, nTmpLength);
				sContent += this.getFormatedWord(sEnrichedWord, nTmpIndex, nTmpLangType);
				nPrevPos = nTmpPos + nTmpLength;
			}
		}
		sContent += this.sContent.substr(nPrevPos, nPos - nPrevPos);
		nPrevPos = nPos + nLength;
		sContent += this.getFormatedWord(sWord, i, nLangType);
		if (i == this.vEnrichment.length-1 && 
			this.sContent.indexOf("&nbsp;", nPrevPos) < 0) {
			sContent += "&nbsp;";
		}
	}
	sContent += this.sContent.substr(nPrevPos);
	//WSDebug.log("created content: " + WSDomUtils.escapeHTML(sContent), "getEnrichedContent");
	//test cursor: sContent += '<br><div><a onClick="javascript: alert(123);">foo</a></div>';
	return sContent;
}

WSEnrichmentEngine.prototype.getElementIndex = function(oElement) {
	nIndex = -1;
	if (oElement) {
		var sId = oElement.id;
		if (sId) {
			var nStart = sId.indexOf("wsWord");
			if (nStart < 0) {
				return nStart;
			}
			nStart += String("wsWord").length;
			var sIndex = sId.substr(nStart);
			nIndex = parseInt(sIndex);
		}
	}
	return nIndex;
}

WSEnrichmentEngine.prototype.getFormatedWord = function(sWord, nIndex, nLangType) {
	var sContent = "";
	var enrichment = this.vEnrichment[nIndex];
	if (enrichment) {
		var sClassName = this.getClassName(enrichment);
		if (sClassName.length > 0) {
			/*
			grammarWord = '<span id="#{anId}" class="#{}">#{word}</span>';
			enrichWord = '<span id="#{anId}" class="#{}">#{word}</span>';
			spellingWord = '<span id="#{anId}" class="#{}">#{word}</span>';
			*/
			sContent += '<span id="wsWordAdd' + nIndex.toString() + '"></span>';
			sContent += '<span id="wsWord' + nIndex.toString() + '" ';
			sContent += 'class="' + sClassName + '">';
			sContent += sWord;
			sContent += '</span>';
		} else if (sWord.length >= 2 && WSUtils.isAlpha(sWord)) {
			sContent += sWord;
		} else {
			sContent += sWord;
		}
	} else {
		sContent += sWord;
	}
	return sContent;
}
WSEnrichmentEngine.prototype.getClassName = function(enrichment) {
	var sClassName = "";
	if (enrichment) {
		if (enrichment.s && enrichment.s.length > 0) {
			sClassName = this.config.enrichSettings.spelling.className;
		} else if (enrichment.g && enrichment.g.length > 0) {
			sClassName = this.config.enrichSettings.grammar.className;
		} else if ((enrichment.t && enrichment.t.length > 0) || (enrichment.e && enrichment.e.length > 0)) {
			sClassName = this.config.enrichSettings.enrichment.className;
		}
	}
	return sClassName;
}
WSEnrichmentEngine.prototype.updateWordStyle = function(nIndex, enrichment) {
	var sClassName = this.getClassName(enrichment);
	var oElement = this.getElementByIndex(nIndex);
	oElement.className = sClassName;
}
WSEnrichmentEngine.prototype.setEnrichmentInfo = function(oEnrichmentInfo) {
	this.vEnrichment = oEnrichmentInfo;
	if (!this.vEnrichment) {
		this.vEnrichment = [];
		this.nSelectedIndex = -1;
		return;
	}
	if (this.vEnrichment.length == 0) {
		this.nSelectedIndex = -1;
	} else if (this.nSelectedIndex >= this.vEnrichment.length) {
		this.nSelectedIndex = 0;
	}
}
WSEnrichmentEngine.prototype.mergeEnrichmentInfo = function(oEnrichmentInfo) {
	if (oEnrichmentInfo && oEnrichmentInfo.length > 0) {
		oEnrichmentInfo[0].sWord = this.vEnrichment[this.nSelectedIndex].sWord;
		oEnrichmentInfo[0].nPos = this.vEnrichment[this.nSelectedIndex].nPos;
		oEnrichmentInfo[0].nLength = this.vEnrichment[this.nSelectedIndex].nLength;
		this.vEnrichment[this.nSelectedIndex] = oEnrichmentInfo[0];
		this.updateWordStyle(this.nSelectedIndex, oEnrichmentInfo[0]);
		this.nSelectedIndex = -1;
	}
}
WSEnrichmentEngine.prototype.setLastPointedInfo = function(e, oMousePos, sWord, nLastLangType, nLastPointedIndex, oLastPointedElement) {
	this.stLastPointedInfo.e = e;
	this.stLastPointedInfo.oMousePos = oMousePos;
	this.stLastPointedInfo.sWord = sWord;
	this.stLastPointedInfo.nLangType = nLastLangType;
	this.stLastPointedInfo.nIndex = nLastPointedIndex;
	this.stLastPointedInfo.oElement = oLastPointedElement;
	this.stLastPointedInfo.vDictionary = new Array();
}
WSEnrichmentEngine.prototype.setDictionaryInfo = function(oEnrichmentInfo) {
	this.stLastPointedInfo.vDictionary = new Array();
	if (oEnrichmentInfo && oEnrichmentInfo.length > 0) {
		this.stLastPointedInfo.vDictionary = oEnrichmentInfo[0].d;
	}
	var sWord = this.stLastPointedInfo.sWord;
	var nLangType = this.stLastPointedInfo.nLangType;
	if (!this.vDictionaryCache[nLangType]) {
		this.vDictionaryCache[nLangType] = new Array(sWord);
	}
	this.vDictionaryCache[nLangType][sWord] = this.stLastPointedInfo.vDictionary;
	return true;
}
WSEnrichmentEngine.prototype.getDictionaryInfo = function(sWord, nLangType) {
	this.stLastPointedInfo.vDictionary = new Array();
	if (this.vDictionaryCache[nLangType] && this.vDictionaryCache[nLangType][sWord]) {
		this.stLastPointedInfo.vDictionary = this.vDictionaryCache[nLangType][sWord];
		return this.stLastPointedInfo.vDictionary;
	}
	return null;
}

WSEnrichmentEngine.prototype.hideProgressBar = function() {
	var oElement = this.gui.getProgressElement();
	if (oElement) {
		WSDomUtils.hideElement(oElement);
	}
}
WSEnrichmentEngine.prototype.hideDictionary = function() {
	WSSharedEnrichmentEngine.stopDictionaryTimer();
	var oElement = this.gui.getDictionaryElement();
	if (oElement) {
		WSDomUtils.hideElement(oElement);
	}
}

WSEnrichmentEngine.prototype.hideSuggestions = function() {
	this.hideDictionary();
	var oElement = this.gui.getSuggestionsElement();
	if (oElement) {
		WSDomUtils.hideElement(oElement);
	}
	this.markWord( - 1);
}


WSEnrichmentEngine.prototype.getMousePos = function(e) {
	var p;
	try {
		p = WSUtils.getMousePoint(e);
		return p; //{x: p.x, y: p.y};
	}
	catch(exception) {
		alert(exception);
		var oMousePos = this.stLastPointedInfo.oMousePos;
		var nMouseX = oMousePos.X;
		var nMouseY = oMousePos.Y;
		return {x: nMouseX,	y: nMouseY};
	}
}
WSEnrichmentEngine.prototype.setSuggestionsEventHandler = function(oDisplayElement, sName, oFunction) {
	if (!this.closures) this.closures = [];
	if (!this.closures["onMouseOverSuggestion"]) {
		this.closures["onMouseOverSuggestion"] = this.eventClosure(this.onMouseOverSuggestion);
	}
	if (!this.closures["onMouseOutSuggestion"]) {
		this.closures["onMouseOutSuggestion"] = this.eventClosure(this.onMouseOutSuggestion);
	}
	var oElements = oDisplayElement.getElementsByTagName("td");
	for (var i = 0; i < oElements.length; ++i) {
		if (oElements[i].getAttribute('name') == sName) {
			WSDomUtils.addEvent(oElements[i], "mousedown", oFunction);
			WSDomUtils.addEvent(oElements[i], "mouseover", this.closures["onMouseOverSuggestion"]);
			WSDomUtils.addEvent(oElements[i], "mouseout", this.closures["onMouseOutSuggestion"]);
		}
	}
}

WSEnrichmentEngine.prototype.setExplanationEventHandler = function(oDisplayElement, sName, oFunction) {
	var oElements = oDisplayElement.getElementsByTagName("td");
	for (var i = 0; i < oElements.length; ++i) {
		if (oElements[i].getAttribute('name') == sName) {
			WSDomUtils.addEvent(oElements[i], "mousedown", oFunction);
		}
	}
}

WSEnrichmentEngine.prototype.onMouseOverSuggestion = function(e) {
	WSSharedEnrichmentEngine.startDictionaryTimer(e, this);
	var oElement = WSDomUtils.getEventElement(e);
	if (oElement) {
		oElement.className = this.config.suggestionSettings.mouseOver.className;
	}
}
WSEnrichmentEngine.prototype.onMouseOutSuggestion = function(e) {
	WSSharedEnrichmentEngine.stopDictionaryTimer(this);
	var oElement = WSDomUtils.getEventElement(e);
	if (oElement) {
		oElement.className = this.config.suggestionSettings.single.className;
	}
}
WSEnrichmentEngine.prototype.getEnrichmentLangType = function(nLangType) {
	var nEnrichLangType = 0;
	if (nLangType == this.config.stLangType.noun) {
		nEnrichLangType = this.config.stLangType.adjective;
	} else if (nLangType == this.config.stLangType.verb) {
		nEnrichLangType = this.config.stLangType.adverb;
	}
	return nEnrichLangType;
}

WSEnrichmentEngine.prototype.getExplanationHTML = function() {
	var template = new WSTemplate(this.config.explanationHTML);
	var sContent = template.evaluate({
		id: "explanation",
		name: "explanation",
		suggestion: "Explanation",
		className:  this.config.suggestionSettings.explanation.className
	});
	return sContent;
}

WSEnrichmentEngine.prototype.getSuggestionsHTML = function(vSuggestions, enrichSettings, leftBorderHTML, rightBorderHTML) {
	var sContent = "";
	var min_size = Math.min(vSuggestions.length,this.config.nMaxSuggestions);
	var template = new WSTemplate(this.config.suggestionHTML);
	for (var i = 0; i < min_size; ++i) {
		var sClassName = this.config.suggestionSettings.single.className;
		var sName = enrichSettings.name;
		if (vSuggestions[i].substr(0,7) == "remark:" ||
			vSuggestions[i].indexOf("(FORGOT A WORD?)") != -1)
		{
			sClassName = this.config.suggestionSettings.disabled.className;
			sName += "Disabled";
		}	

		sContent += template.evaluate({
			id: enrichSettings.name + i.toString(),
			name: sName,
			suggestion: vSuggestions[i],
			className: sClassName
			//leftBorder: leftBorderHTML,
			//rightBorder: rightBorderHTML
		});
	}

	return sContent;
}
WSEnrichmentEngine.prototype.getExtendedSuggestionsHTML = function(vSuggestions, spacesNum, enrichSettings, leftBorderHTML, rightBorderHTML) {
	var sContent = "";
	var size = vSuggestions.length;
	var template = new WSTemplate(this.config.suggestionHTML);
	for (var i = 0; i < size && i < this.config.nMaxSuggestions; ++i) {

		var sClassName = this.config.suggestionSettings.single.className;
		var sName = enrichSettings.name;
		
		if (vSuggestions[i].substr(0,7) == "remark:" ||
			vSuggestions[i].indexOf("(FORGOT A WORD?)") != -1)
		{
			sClassName = this.config.suggestionSettings.disabled.className;
			sName += "Disabled";
		}	
	
		sContent += template.evaluate({
			id: enrichSettings.name + i.toString(),
			name: sName,
			suggestion: vSuggestions[i],
			className: sClassName
			//leftBorder: leftBorderHTML,
			//rightBorder: rightBorderHTML
		});
	}
	for (i = 0; i < spacesNum && i+size < this.config.nMaxSuggestions; ++i) {
		sContent += template.evaluate({
			id: "0",
			name: "0",
			suggestion: "",
			className: this.config.suggestionSettings.single.className
			//leftBorder: leftBorderHTML,
			//rightBorder: rightBorderHTML
		});
	}
	return sContent;
}

WSEnrichmentEngine.prototype.showSuggestions = function(e, vSuggestions, enrichSettings) {
	var oDisplayElement = this.gui.getSuggestionsElement();
	if (!oDisplayElement) {
		return false;
	}
	var sContent = '';
	if (vSuggestions.length > 0) {
		var tLeft = new WSTemplate(this.config.leftBorderHTML);
		var leftBorder = tLeft.evaluate({
			sColor: enrichSettings.color
		});
		var tRight = new WSTemplate(this.config.rightBorderHTML);
		var rightBorder = tRight.evaluate({
			sColor: enrichSettings.color
		});
		var t = new WSTemplate(this.config.suggestionBox);
		sContent = t.evaluate({
			//color: enrichSettings.color,
			className: enrichSettings.className,
			title: enrichSettings.title,
			suggestions: this.getSuggestionsHTML(vSuggestions, enrichSettings, leftBorder, rightBorder),
			explanation: (enrichSettings.showExplanation? this.getExplanationHTML() : "")
		});
		//alert(sContent);
	}
	oDisplayElement.innerHTML = sContent;
	this.setSuggestionsEventHandler(oDisplayElement, enrichSettings.name, this.eventClosure(this.onReplaceWord));
	if (enrichSettings.showExplanation) {
		this.setExplanationEventHandler(oDisplayElement, "explanation", this.eventClosure(this.onClickExplanation));
	}	
	this.gui.displaySuggestions(e, oDisplayElement, this.nSelectedIndex);
	return true;
}

WSEnrichmentEngine.prototype.show2Suggestions = function(e, vESuggestions, vTSuggestions) {
	if (vESuggestions.length == 0 && vTSuggestions.length == 0) {
		return false;
	}
	var oDisplayElement = this.gui.getSuggestionsElement();
	if (!oDisplayElement) {
		return false;
	}
	var enrichmentSuggestion = '';
	var leftovers = Math.min(vTSuggestions.length, this.config.nMaxSuggestions) - Math.min(vESuggestions.length, this.config.nMaxSuggestions);
	if (vESuggestions.length > 0) {
		var tLeft = new WSTemplate(this.config.leftBorderHTML);
		var leftBorder = tLeft.evaluate({
			sColor: "blue"
		});
		var tRight = new WSTemplate(this.config.rightBorderHTML);
		var rightBorder = tRight.evaluate({
			sColor: "lightBlue"
		});
		var t = new WSTemplate(this.config.extendedSuggestionHTML);
		enrichmentSuggestion = t.evaluate({
			className: this.config.enrichSettings.enrichment.className,
			title: this.config.enrichSettings.enrichment.title,
			suggestions: this.getExtendedSuggestionsHTML(vESuggestions, leftovers, this.config.enrichSettings.enrichment, leftBorder, rightBorder)
		});
	}
	var thesaurusSuggestion = '';
	leftovers *= -1;
	//leftovers = (-1) * leftovers;
	if (vTSuggestions.length > 0) {
		var tRight = new WSTemplate(this.config.rightBorderHTML);
		var rightBorder = tRight.evaluate({
			sColor: this.config.enrichSettings.thesaurus.color //"blue"
		});
		var t2 = new WSTemplate(this.config.extendedSuggestionHTML);
		thesaurusSuggestion = t2.evaluate({
			className: this.config.enrichSettings.thesaurus.className,
			title: this.config.enrichSettings.thesaurus.title,
			suggestions: this.getExtendedSuggestionsHTML(vTSuggestions, leftovers, this.config.enrichSettings.thesaurus, "", rightBorder)
		});
	}
	var sContent = '';
	var t3 = new WSTemplate(this.config.extendedSuggestionBox);
	sContent = t3.evaluate({
		enrichmentSuggestion: enrichmentSuggestion,
		thesaurusSuggestion: thesaurusSuggestion
	});
	oDisplayElement.innerHTML = sContent;
	var sEnrichmentName = this.config.enrichSettings.enrichment.name;
	var sThesaurusName  = this.config.enrichSettings.thesaurus.name;
	this.setSuggestionsEventHandler(oDisplayElement, sEnrichmentName, this.eventClosure(this.onAddWord));
	this.setSuggestionsEventHandler(oDisplayElement, sThesaurusName, this.eventClosure(this.onReplaceWord));
	this.gui.displaySuggestions(e, oDisplayElement, this.nSelectedIndex);
	return true;
}
WSEnrichmentEngine.prototype.onAddWord = function(e) {
	var oElement = WSDomUtils.getEventElement(e);
	if (oElement) {
		var sNewWord = oElement.innerHTML;
		var nLangType = this.vEnrichment[this.nSelectedIndex].nLangType;
		var nEnrichmentLangType = this.getEnrichmentLangType(nLangType);
		this.addWord(sNewWord, nEnrichmentLangType);
	}
}
WSEnrichmentEngine.prototype.markWord = function(nNewIndex) {
	var nPrevIndex = this.nSelectedIndex;
	if (nPrevIndex >= 0) {
		var oPrevElement = this.getElementByIndex(nPrevIndex);
		if (oPrevElement && oPrevElement.style) {
			if (this.stPrevElementStyle != null) {
				oPrevElement.style.textDecoration = this.stPrevElementStyle.textDecoration;
				oPrevElement.style.borderBottomStyle = this.stPrevElementStyle.borderBottomStyle;
			}
		}
	}
	if (nNewIndex >= 0) {
		var oElement = this.getElementByIndex(nNewIndex);
		if (oElement && oElement.style) {
			this.stPrevElementStyle.textDecoration = oElement.style.textDecoration;
			this.stPrevElementStyle.borderBottomStyle = oElement.style.borderBottomStyle;
			//oElement.style.borderBottomStyle = "solid";
		} 
	}
}
WSEnrichmentEngine.prototype.showSpellingSuggestions = function(e, nIndex) {
	this.markWord(nIndex);
	this.state = "s";
	this.nSelectedIndex = nIndex;
	var enrichment = this.vEnrichment[this.nSelectedIndex]; {
		return this.showSuggestions(e, enrichment.s, this.config.enrichSettings.spelling);
	}
}
WSEnrichmentEngine.prototype.showGrammarSuggestions = function(e, nIndex) {
	if (false) {
		this.gui.showTrialMessage();
	} else {
		this.markWord(nIndex);
		this.state = "g";
		this.nSelectedIndex = nIndex;
		var enrichment = this.vEnrichment[this.nSelectedIndex];
		return this.showSuggestions(e, enrichment.g, this.config.enrichSettings.grammar);
	}
}
WSEnrichmentEngine.prototype.showEnrichmentSuggestions = function(e, nIndex) {
	this.markWord(nIndex);
	this.state = "e";
	this.nSelectedIndex = nIndex;
	var enrichment = this.vEnrichment[this.nSelectedIndex];
	return this.show2Suggestions(e, enrichment.e, enrichment.t);//,this.config.enrichSettings.enrichment,this.config.enrichSettings.thesaurus);
}
WSEnrichmentEngine.prototype.addUndoInfo = function(func) {
	if (! this.bUndoMode) {
		var new_func = function() { this.bUndoMode=true; func(); this.bUndoMode=false; };
		this.undoInfo.push({func: new_func, nIndex: this.nSelectedIndex});
		this.redoInfo = new Array();
	}	
}
WSEnrichmentEngine.prototype.getFilteredEditorContent = function() {
	var sContent = this.editor.getContent();
	if (! this.config.isHTMLMode()) {
		sContent = WSUtils.html2Text(sContent);
	}
	var sNewContent = this.cleanWSContent(sContent);
	//Remove the previously added nbsp
	if (sNewContent.substr(sNewContent.length-6,6) == "&nbsp;") {
		sNewContent = sNewContent.substr(0, sNewContent.length - 6);
	}
	return sNewContent;
}
WSEnrichmentEngine.prototype.getFilteredTemplateContent = function() {
	var sContent = "";
	var oEditorFrame = this.editor.getInstance();
	if (oEditorFrame) {
		var oContentFrame = oEditorFrame.frames['content'];
		sContent = oContentFrame.document.body.innerHTML;
	}
	return sContent;
}
WSEnrichmentEngine.prototype.updateContent = function() {
	var sNewContent = this.getFilteredEditorContent();
	WSDebug.log("collected content: " + sNewContent, "updateContent");
	this.querySentence(sNewContent);
	return sNewContent;
}

WSEnrichmentEngine.prototype.onClickExplanation = function(e) {
	this.hideSuggestions();
	this.gui.showExplanationMsg();
}
WSEnrichmentEngine.prototype.onReplaceWord = function(e) {
	var oElement = WSDomUtils.getEventElement(e);
	if (oElement) {
		var sNewWord = oElement.innerHTML;
		var nLangType = this.vEnrichment[this.nSelectedIndex].nLangType;
		this.replaceWord(sNewWord, nLangType);
	}
	return true;
}
WSEnrichmentEngine.prototype.replaceWord = function(newWord, nLangType) {
	this.hideSuggestions();
	var enrichment = this.vEnrichment[this.nSelectedIndex];
	var oldWord = enrichment.sWord;
	enrichment.sWord = newWord;
	var oElement = this.getElementByIndex(this.nSelectedIndex);
	oElement.className = this.config.enrichSettings.general.className;
	this.replaceElementText(oElement, oldWord, newWord);
	var bIsThesaurus = false;
	for (var i = 0; i < enrichment.t.length; ++i) {
		if (enrichment.t[i] == newWord) {
			//enrichment.t[i] = oldWord;
			bIsThesaurus = true;
		}
	}
	var self = this;
	this.addUndoInfo(function() { self.replaceWord(oldWord,nLangType); });
	if (!bIsThesaurus && this.config.autoCheck.onChange) {
		this.queryWord(newWord, nLangType);
	}
}
WSEnrichmentEngine.prototype.replaceElementText = function(oElement, oldText, newText) {
	var sContent = oElement.innerHTML;
	var sNewContent = sContent.replace(oldText, newText);
	oElement.innerHTML = sNewContent;
}
WSEnrichmentEngine.prototype.addWord = function(newWord, nLangType) {
	this.hideSuggestions();
	var sId = "wsWordAdd" + this.nSelectedIndex;
	var oElement = this.getElementById(sId);
	oElement.innerHTML += newWord + " ";
	var self = this;
	this.addUndoInfo(function() { self.deleteWord(sId,newWord,nLangType); });
	return true;
}
WSEnrichmentEngine.prototype.deleteWord = function(sElementId, sWord, nLangType) {
	this.hideSuggestions();
	var oElement = this.getElementById(sElementId);
	this.replaceElementText(oElement, sWord, "");
	var self = this;
	this.addUndoInfo(function() { self.addWord(sWord,nLangType); });
}
WSEnrichmentEngine.prototype.undo = function() {
	if (this.undoInfo.length > 0) {
		var stUndo = this.undoInfo.pop();
		this.redoInfo.push(stUndo);
		this.nSelectedIndex = stUndo.nIndex;
		stUndo.func();
	}	
}
WSEnrichmentEngine.prototype.redo = function() {
	if (this.redoInfo.length > 0) {
		var stRedo = this.redoInfo.pop();
		this.undoInfo.push(stRedo);
		this.nSelectedIndex = stRedo.nIndex;
		stRedo.func();
	}
}
WSEnrichmentEngine.prototype.testQuerySentence = function() {
	var sSentence = "He is patatoes.";
	WSDebug.log("on querySentence, sentence = [\n" + sSentence + "\n]", "querySentence");
	this.sContent = sSentence;
	var vTokens = this.tokenize(sSentence);
	var sMessage = "";
	for (var i = 0; i < vTokens.length; ++i) {
		sMessage += vTokens[i].sWord;
		sMessage += " ";
	}
	this.gui.showProgressDialog(true);
	sMessage += this.queryLoginInfo();
	sMessage += "v\n";
	sMessage += "998\n";
	sMessage = this.queryLoginInfo();
	sMessage += "l\n";
	return this.sendToServer("handleTestQuerySentenceResponse", "", 0, sMessage);
}
WSEnrichmentEngine.prototype.queryLoginInfo = function() {
	var mess = "3\n";
	mess += "0\n";
	mess += this.config.userId + "\n";
	return mess;
}
WSEnrichmentEngine.prototype.handleTestQuerySentenceResponse = function(sResponseData) {
	WSDebug.log("Receiving response from server..", "handleQuerySentenceResponse");
	this.gui.showProgressDialog(false);
	if (sResponseData) {
		var oEnrichmentInfo = this.getEnrichmentInfo(sResponseData, this.vTokens, this);
		this.setEnrichmentInfo(oEnrichmentInfo);
	}
	this.showContent();
}

WSEnrichmentEngine.prototype.onHandleError = function(sResponseData) {
	WSDebug.warning("Not a valid member (" + sResponseData + ")");
	this.gui.showErrorMsg(sResponseData);
}
WSEnrichmentEngine.prototype.sendToServer = function(sCallBack, sQueryType, nLangType, sMessage) {
	WSDebug.log("{callback: " + sCallBack + ",querytype: " + sQueryType + ", langtype: " + nLangType + "message: " + sMessage + "}", "sendToServer");
	return this.sendToServerAJAXExtended(sCallBack, sQueryType, nLangType, sMessage);
}
WSEnrichmentEngine.prototype.sendToServerAJAXExtended = function(sCallBack, sQueryType, nLangType, sMessage) {
	if (sMessage.length <= this.config.nMaxContentLength) {
		var xmlhttp = null;
		var self = this;
		//var xmlhttp = new XMLHttpRequest();
		//var xmlhttp = new XMLHTTP(this.config.sAJAXExURL);
		//var xmlhttp = new getHTTPObjectUser();

		var call_prefix = "";
		if (this.config.sendMethod.iframe == 1) {
			xmlhttp = new WSIFrameRequest();
			call_prefix = "parent.g_oWSEnrichmentsArray[" + this.editorNumber + "].";
		}
		else if (this.config.sendMethod.ajax_ex == 1)	{
			var call_prefix = "self.";
			xmlhttp = new XMLHTTP(this.config.sAJAXExURL);
		}
		else { //if (self.config.sendMethod.ajax == 1)
			var call_prefix = "self.";
			xmlhttp = new XMLHttpRequest();
		}
		sCallBack = call_prefix + sCallBack;
		var sErrorCallBack = call_prefix + "onHandleError";
		
		
		xmlhttp.onerror = function(description) {
			alert("description\n"+description);
			this.onHandleError(description);
		}
		xmlhttp.onreadystatechange = function() {			
			if (xmlhttp.readyState == 4) {
				//alert("xmlhttp.responseText:\n" + xmlhttp.responseText);
				//var sCode = xmlhttp.responseText;
				//alert(sCode);
				//sCode = sCode.replace(/\\\\/g,"\\");
				//var eval_str = sCallBack + "(" + sCode + ");";
				//var eval_str = sCode;
				//alert(xmlhttp.responseText);
				//eval(xmlhttp.responseText); //self.eval(sCode);
				//if (self.config.sendMethod.iframe != 1)
				{
					var upperResponseText = xmlhttp.responseText.toUpperCase();
					var nStart = upperResponseText.indexOf("<S" + "CRIPT");
					if (nStart >= 0) {
						nStart = upperResponseText.indexOf(">", nStart) + 1;
						var nFinish = upperResponseText.indexOf("</SC" + "RIPT>", nStart);
						if (nFinish >= 0) {
							var sCode = xmlhttp.responseText.substr(nStart, nFinish - nStart);
							//alert("sCode = " + sCode);
							//sCode = sCode.replace(/\\\\/g,"\\");
							//alert(sCallBack + "." + sCode);
							//eval(sCallBack + "." + sCode); //self.eval(sCode);
							//alert("sCode = " + sCode);
							//eval(sCode); //self.eval(sCode);
						}
					}
				}
			}
		}
		var sProfile = this.config.profile;
		var sURL = "";
		if (sQueryType) {
			sURL = this.config.sServerURL + "?user_id=" + this.config.userId + "&callback=" + sCallBack + "&error_callback="+sErrorCallBack+"&profile=" + sProfile + "&lang_type=" + nLangType + "&query_type=" + sQueryType + "&message=" + encodeURI(sMessage);
		} else {
			sURL = this.config.sServerURL + "?user_id=" + this.config.userId + "&callback=" + sCallBack + "&error_callback="+sErrorCallBack+"&profile=" + sProfile + "&lang_type=" + nLangType + "&message=" + encodeURI(sMessage);
		}
		xmlhttp.open('POST', sURL);
		xmlhttp.send(null);
	} else {
		this.gui.showLengthExceededMsg();
		return false;
	}
	return true;
}
WSEnrichmentEngine.prototype.querySentence = function(sSentence) {
	WSDebug.log("on querySentence, sentence = [\n" + sSentence + "\n]", "querySentence");
	this.sContent = sSentence;
	var vTokens = this.tokenize(sSentence);
	var sMessage = "";
	for (var i = 0; i < vTokens.length; ++i) {
		sMessage += vTokens[i].sWord;
		sMessage += " ";
	}
	this.gui.showProgressDialog(true);
	return this.sendToServer("handleQuerySentenceResponse", "sentence", 0, sMessage);
}
WSEnrichmentEngine.prototype.handleQuerySentenceResponse = function(sResponseData) {
	WSDebug.log("Receiving response from server: " + sResponseData, "handleQuerySentenceResponse");
	this.gui.showProgressDialog(false);
	if (sResponseData) {
		var oEnrichmentInfo = this.getEnrichmentInfo(sResponseData, this.vTokens);
		this.setEnrichmentInfo(oEnrichmentInfo);
	}
	this.showContent();
}
WSEnrichmentEngine.prototype.queryWord = function(sWord, nLangType) {
	this.gui.showProgressDialog(true);
	return this.sendToServer("handleQueryWordResponse", "word", nLangType, sWord);
}
WSEnrichmentEngine.prototype.handleQueryWordResponse = function(sResponseData) {
	this.gui.showProgressDialog(false);
	if (sResponseData) {
		var oEnrichmentInfo = this.getEnrichmentInfo(sResponseData, this.vTokens);
		this.mergeEnrichmentInfo(oEnrichmentInfo);
	}
}
WSEnrichmentEngine.prototype.queryDictionary = function(sWord, nLangType) {
	if (this.getDictionaryInfo(sWord, nLangType) != null) {
		this.gui.showDictionaryResult();
		return true;
	} else {
		return this.sendToServer("handleQueryDictionaryResponse", "dictionary", nLangType, sWord);
	}
}
WSEnrichmentEngine.prototype.handleQueryDictionaryResponse = function(sResponseData) {
	if (sResponseData) {
		var oEnrichmentInfo = this.getEnrichmentInfo(sResponseData, this.vTokens);
		this.setDictionaryInfo(oEnrichmentInfo);
	}
	this.gui.showDictionaryResult();
}
WSEnrichmentEngine.prototype.queryTemplateList = function() {
	return this.sendToServer("handleQueryTemplateListResponse", "templateList", 0, "");
}
WSEnrichmentEngine.prototype.setTemplateContent = function(sResponseData) {
	var oEditorFrame = this.editor.getInstance();
	if (oEditorFrame) {
		var oContentFrame = oEditorFrame.frames['content'];
		oContentFrame.document.open();
		oContentFrame.document.write(sResponseData);
		oContentFrame.document.close();
		return true;
	}
	return false;
}
WSEnrichmentEngine.prototype.queryTemplate = function(sName) {
	return this.sendToServer("handleQueryTemplateResponse", "template", 0, sName);
}
WSEnrichmentEngine.prototype.tokenize = function(sContent) {
	var tokenizer = new WSHTMLTokenizer();
	this.vTokens = tokenizer.parseHTML(sContent);
	return this.vTokens;
}
WSEnrichmentEngine.prototype.reTokenize = function(sContent) {
	var tokenizer = new WSHTMLTokenizer();
	var vTokens = new Array();
	if (this.config.isHTMLMode()) {
		vTokens = tokenizer.parseHTML(sContent);
	} else {
		vTokens = tokenizer.parseText(sContent);
	}
	return this.vTokens;
}
