var spellCheckText = {
	timer: false,
	sendingTimer: false,
	checks: 0,
	richTextEditor: false,
	ajaxURL: siteRoot+"proxy.php",
	updatingHTML: false,
	lastErrors: false,
	currentlyHighlighted: false,
	highlightStuck: false,
	toIgnore: [],
	hlRegexStart: new RegExp("\<span class\=\"?sError\"?\>", "ig"),
	hlRegexEnd: new RegExp("\<\/span\>", "ig"),

	quickJSON: function(url, params, callback) {
		if(!spellrus.docHead) spellrus.docHead = document.getElementsByTagName('head')[0];
		var uId = "s_"+spellrus.getNow();
		var oScript = document.createElement("script");
		oScript.type = 'text/javascript';
		oScript.src = url+'&callback='+callback+'&'+params+'&t='+uId;
		oScript.charset = 'windows-1252';
		oScript.id = uId;
		spellrus.docHead.appendChild(oScript);
	},
	
	fullJSON: function(url, params, callback) {
		var options = {
			method: 'post',
			parameters: params
		};
		if(callback) {
			options.onComplete = function(transport) {
				var data = transport.responseJSON;	
				callback(data);
			};
		}
		new Ajax.Request(url, options);
	},

	sendingData: function() {
		// This timer displays the "* checking..." message if the data takes a noticeable time to return.
		if(spellCheckText.sendingTimer) {
			window.clearInterval(spellCheckText.sendingTimer);
		}
		spellCheckText.sendingTimer = window.setTimeout(function() {
			$("textSuggestions").update("<div style='text-align:center;'><br /><img src='"+siteRoot+"images/ajax-loader-small.gif' style='vertical-align:middle;' border='0' />&nbsp; Checking...</div>");
		}, 1000);
	},

	dataRecieved: function() {
		if(spellCheckText.sendingTimer) {
			window.clearInterval(spellCheckText.sendingTimer);
		}
	},
	
	checkIt: function() {
		++spellCheckText.checks;
		spellCheckText.sendingData();
		spellCheckText.fullJSON(spellCheckText.ajaxURL, {"text": encodeURIComponent(spellCheckText.getTextToCheck())}, spellCheckText.checkResults);
	},

	getTextToCheck: function() {
		if(spellCheckText.richTextEditor) {
			return spellCheckText.richTextEditor.getSnapshot();
		}
		else {
			return $("textCheck").getValue();
		}
	},

	markupErrors: function(word, override) {
		if(spellCheckText.highlightStuck && !override) {
			return;
		}
		if(override) spellCheckText.highlightStuck = true;
		if(spellCheckText.currentlyHighlighted == word) {
			return;
		}
		
		spellCheckText.currentlyHighlighted = word;
		//alert('highlighting '+word);
		//var errors = [word];
		spellCheckText.updatingHTML = true;
		var html = spellCheckText.getTextToCheck();
		html = html.replace(spellCheckText.hlRegexStart, "");
		html = html.replace(spellCheckText.hlRegexEnd, "");
		html = html.replace("&nbsp;", " ");

		var wordRegexG = new RegExp("([^a-zA-Z0-9])"+word+"([^a-zA-Z0-9])", "gm");
		html = ">"+html;
		html = html.replace(wordRegexG, "$1<span class=\"sError\">"+word+"</span>$2");
		html = html.substring(1);

		spellCheckText.richTextEditor.loadSnapshot(html);
		var spans = spellCheckText.richTextEditor.document.$.getElementsByTagName('span');
		for(var i = 0; i < spans.length; ++i) {
			if(spans[i].className == 'sError') {
				// First error highlighted - make sure it's visible
				var element = new CKEDITOR.dom.element(spans[i]);
				element.scrollIntoView();
				break;
			}
		}

		//spellCheckText.richTextEditor.focusManager.blur();
		spellCheckText.updatingHTML = false;
	},
	
	hideErrors: function(override) {
		if(spellCheckText.highlightStuck && !override) {
			return;
		}
		spellCheckText.highlightStuck = false;
		
		spellCheckText.updatingHTML = true;
		var html = spellCheckText.getTextToCheck();
		html = html.replace(spellCheckText.hlRegexStart, "");
		html = html.replace(spellCheckText.hlRegexEnd, "");
		html = html.replace("&nbsp;", " ");
		//alert(html);
		spellCheckText.richTextEditor.loadSnapshot(html);
		spellCheckText.updatingHTML = false;
		spellCheckText.currentlyHighlighted = false;
	},

	ignoreError: function(word) {
		spellCheckText.toIgnore.push(word);
		spellCheckText.hideErrors(true);
		spellCheckText.removeFromLastData(word);
		spellCheckText.reWriteLastCheck();	
		spellCheckText.fullJSON(spellCheckText.ajaxURL, {"call": "saveCorrection", "word": encodeURIComponent(word), "correction": ""}, false);
	},
	
	replaceAWord: function(word, replaceWith) {
		spellCheckText.currentlyHighlighted = false;

		spellCheckText.updatingHTML = true;
		var html = spellCheckText.getTextToCheck();
		html = html.replace(spellCheckText.hlRegexStart, "");
		html = html.replace(spellCheckText.hlRegexEnd, "");
		html = html.replace("&nbsp;", " ");

		var wordRegexG = new RegExp("([^a-zA-Z0-9])"+word+"([^a-zA-Z0-9])", "gm");
		html = ">"+html;
		html = html.replace(wordRegexG, "$1"+replaceWith+"$2");
		html = html.substring(1);

		spellCheckText.richTextEditor.loadSnapshot(html);
		spellCheckText.updatingHTML = false;

		spellCheckText.removeFromLastData(word);
		spellCheckText.reWriteLastCheck();		

		spellCheckText.fullJSON(spellCheckText.ajaxURL, {"call": "saveCorrection", "word": encodeURIComponent(word), "correction": encodeURIComponent(replaceWith)}, false);
	},

	reWriteLastCheck: function() {
		if(spellCheckText.lastData) {
			spellCheckText.checkResults(spellCheckText.lastData);
		}
	},

	removeFromLastData: function(word) {
		for(var i = 0; i < spellCheckText.lastData.errors.length; ++i) {
			var error = spellCheckText.lastData.errors[i];
			if(error.word == word) {
				spellCheckText.lastData.errors[i].word = false;
				break;
			}
		}
	},
	
	checkResults: function(data) {
		spellCheckText.lastData = data;
		spellCheckText.dataRecieved();

		var totalErrors = 0;
		var results = "";
		for(var i = 0; i < data.errors.length; ++i) {
			var error = data.errors[i];
			if(error.word) {
				var isError = true;
				for(var w = 0; w < spellCheckText.toIgnore.length; ++w) {
					if(spellCheckText.toIgnore[w] == error.word) {
						isError = false;
						break;
					}
				}
				if(isError) {
					++totalErrors;
					results += "<div class='spellingError'>";
					results += "<div class='ignoreButton'><img src='"+siteRoot+"images/16-circle-green.png' style='vertical-align:middle;' border='0' /> Not Error</div>";
					results += "<div class='spellingErrorTitle'>Error: <span class='sError'>"+error.word+"</span></div>";
					for(var s = 0; s < error.suggestions.length; ++s) {
						var suggestion = error.suggestions[s];
						if(suggestion) {
							results += "<div class='spellingSuggestion'><span class='word'>"+suggestion.s+"</span>";
							if(suggestion.d) results += " <span class='spellingSuggestionDefinition'>("+suggestion.d+")</span>";
							results += "</div>";
						}
					}
					results += "</div>";
				}
			}
		}
		spellCheckText.lastErrors = data.errors;
		if(results == "") {
			results = "<div style='text-align:center;font-weight:bold;font-size:120%;padding-top:20px;'><img src='"+siteRoot+"images/check2.png' style='vertical-align:middle;' border='0' /> No spelling errors found.</div>";
		}
		var intro = "<div style='text-align:center;padding-top:10px;'>Checked "+data.total_words+" unique word";
		if(data.total_words != 1) intro += "s";
		intro += ". Found "+totalErrors+" spelling error";
		if(totalErrors != 1) intro += "s";
		if(totalErrors > 0) intro += ".<br />Click on a suggestion to correct the word";
		intro += ".<br /></div>";

		var outro = "";
		if(data.one_checked_word_def != "") {
			outro += "<div style='text-align:center;padding-top:20px;'>The definition of <b>"+data.one_checked_word+"</b> is <i>"+data.one_checked_word_def+"</i>.</div>";
		}
		
		$("textSuggestions").update(intro+results+outro);
		spellCheckText.addMouseEvents();
	},

	addMouseEvents: function() {
		$$('.spellingError').each(function(spellingError){
			var word = spellingError.getElementsByClassName('sError');
			word = word[0].innerHTML;
			// Add mouseover events
			spellingError.observe('mouseover', function(){
				spellCheckText.markupErrors(word, false);
			});
			spellingError.observe('mouseout', function(){
				spellCheckText.hideErrors(false);
			});
			// Add events to suggestions
			var spellingSuggestions = spellingError.getElementsByClassName('spellingSuggestion');
			for(var i = 0; i < spellingSuggestions.length; ++i) {
				(function() {
					var suggestionWord = spellingSuggestions[i].getElementsByClassName('word');
					suggestionWord = suggestionWord[0].innerHTML;
					spellingSuggestions[i].observe('click', function(){
						spellCheckText.replaceAWord(word, suggestionWord);
						spellingError.hide();
					});
				})(); 
			}
			// Add events to title clicks
			var spellingErrorTitle = spellingError.getElementsByClassName('spellingErrorTitle');
			spellingErrorTitle = spellingErrorTitle[0];
			spellingErrorTitle.observe('click', function(){
				spellCheckText.markupErrors(word, true);
			});
			// Add event to ignore button
			var ignoreButton = spellingError.getElementsByClassName('ignoreButton');
			ignoreButton = ignoreButton[0];
			ignoreButton.observe('click', function(){
				spellCheckText.ignoreError(word);
				spellingError.hide();
			});

			
		});
	},
	
	newKeyPress: function() {
		if(spellCheckText.updatingHTML) return;
		if(spellCheckText.timer) {
			window.clearInterval(spellCheckText.timer);
		}
		spellCheckText.timer = window.setTimeout(spellCheckText.checkIt, 400);		
	},
	
	checkStartRun: function() {
		if(spellCheckText.getTextToCheck()) {
			spellCheckText.checkIt(); // already some text in there => check it!
		}	
	},

	start: function() {
		$("textCheck").observe('change', spellCheckText.newKeyPress);		
	}
};
spellCheckText.start();

CKEDITOR.replace('textCheck', {
	toolbar: [],
	toolbarCanCollapse: false,
	startupOutlineBlocks: false,
	resize_enabled: false,
	disableNativeSpellChecker: true,
    width: "460px",
    height: "303px",
    startupFocus: true,
    contentsCss: '../spell-check-style.css?v5'
});
var editor = CKEDITOR.instances['textCheck'];
spellCheckText.richTextEditor = editor;
editor.on('key', spellCheckText.newKeyPress);
//editor.on('blur', spellCheckText.markupErrors);
editor.on('focus', function() {
	spellCheckText.hideErrors(true);
});

var FixedPositionHandler = Class.create({
	initialize: function initialize(headerElt) {
	        this.tableHeader = $(headerElt);
	        var offset = this.tableHeader.cumulativeOffset();
	        //alert("Pos: "+offset[0]+" "+offset[1]);
	        this.homePosn = { x: offset[0], y: offset[1] };
	        this.tableHeader.makePositioned();
	        Event.observe(window, 'scroll', this.handleScroll.bind(this));
	        this.handleScroll();
	},
	handleScroll: function handleScroll() {
	        this.scrollOffset = document.viewport.getScrollOffsets().top;
	        if (this.scrollOffset > this.homePosn.y) {
	                this.tableHeader.style.position = 'fixed';
	                this.tableHeader.style.top = 0;
	                //alert(this.homePosn.x);
	                this.tableHeader.style.left = this.homePosn.x+'px';
	                this.tableHeader.style.marginTop = '20px';
	                this.tableHeader.style.marginLeft = '-8px';
	        } else {
	                this.tableHeader.style.position = 'relative';
	                this.tableHeader.style.top = 0;
	                this.tableHeader.style.left = 0;
	                this.tableHeader.style.marginTop = 0;
	                this.tableHeader.style.marginLeft = 0;
	        }
	}
});
document.observe("dom:loaded", function(){
	new FixedPositionHandler($("textCheckContainer"));
});

spellCheckText.checkStartRun();