/* Copyright (c) Aprotim Sanyal. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimers
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

function createDropdown(word, id, options, classname)
{
	var dropdown = document.createElement('span');
	dropdown.className = 'dropdown ' + classname;
	dropdown.appendChild(document.createTextNode(word));
	dropdown.id = id;
	dropdown.onmouseover=function() { this.className+=" over"; }
	dropdown.onmouseout=function() { this.className =  this.className.replace(/ over/g, "");}
	dropdown.onclick=function() {
	   if (this.className.search(" sticky") == -1) { this.className+=" sticky"; }
	   else { this.className =  this.className.replace(/ sticky/g, "");}
	   }
	
	var menu = document.createElement('ol');
	menu.className='options';
	var links = new Array();
	for (var i = 0; i < options.length; ++i)
	{
		var li = document.createElement('li');
		li.appendChild(options[i]);
		menu.appendChild(li);
	}

	dropdown.appendChild(menu);
	return dropdown;
}

function createLinks(optionText, id)
{
   var links = new Array();
   for (var i = 0; i < optionText.length; ++i)
   {
      links[i] = document.createElement('a');
      links[i].href = "#";
      links[i].onclick = new Function( 'replaceWord("' + id + '", "' + optionText[i] + '", "corrected"); return false;' );
      links[i].appendChild(document.createTextNode(optionText[i]));
   }
   return links;
}

function makeEditButton(id, word)
{
   var button = document.createElement('input');
   button.setAttribute('type', 'button');
   button.value = 'edit';
   button.onclick = new Function( 'editWord("' + id + '", "' + word + '");' );
   return button;
}

function makeUndoButton(id)
{
   var undoButton = document.createElement('input');
   undoButton.setAttribute('type','button');
   undoButton.value =  'undo change';
   undoButton.onclick= new Function( 'undoReplace("' + id + '", "' + id +'");' );
   return undoButton;
}

function undoReplace(currID, prevID)
{
      var oldNode = undo[prevID];
      if (oldNode)
      {
         var currNode = document.getElementById(currID);
         currNode.parentNode.replaceChild(oldNode, currNode);
      }
      else
      {
         alert('what are you trying to pull?');
      }
}

function editWord(id, defaultText)
{
   if (document.getElementById)
   {
      var oldNode = document.getElementById(id);
      var replacementNode = document.createElement('input');
      replacementNode.setAttribute('type', 'text');
      replacementNode.value =  defaultText;
      replacementNode.onblur = 
         function()
         {
            replacementNode.parentNode.replaceChild(oldNode, replacementNode);
            replaceWord(id, replacementNode.value, 'maybe');
            delete replacementNode;
         };
      oldNode.parentNode.replaceChild(replacementNode, oldNode);
   }
}

function replaceWord(id, newWord, newclass)
{
   if (document.getElementById)
   {
      var oldNode = document.getElementById(id);
      
      // undo button
      var undoButton = new Array();
      undoButton[0] = makeUndoButton(id);
      
      var replacementNode = createDropdown(newWord, id, undoButton, 'spelling ' + newclass);
      undo[id] = oldNode;
      oldNode.parentNode.replaceChild(replacementNode, oldNode);
   }
}

function checkButton(button, id)
{
   if (checking){
      button.value = "check spelling";
      checking = false;
      stopSpellcheck(id);
   }
   else
   {
      button.value = "stop spellcheck";
      requestSpellcheck(id);
   }
      
}

function requestSpellcheck(id)
{
   if(window.XMLHttpRequest) {
      try {
         req = new XMLHttpRequest();
      } catch(e) {
      req = false;
      }
   // branch for IE/Windows ActiveX version
   } else if(window.ActiveXObject) {
      try {
         req = new ActiveXObject("Msxml2.XMLHTTP");
      } catch(e) {
         try {
            req = new ActiveXObject("Microsoft.XMLHTTP");
         } catch(e) {
            req = false;
         }
      }
   }

   if (!req || !document.getElementById)
   {
      alert('Spellchecking failed!  Sorry.');
      return;
   }
   else
   {
      textBox = document.getElementById(id);
      req.onreadystatechange =
         function(){
            if(req.readyState == 4) 
            {
               processSpellcheck(textBox, req);
            }
         };
      req.open("GET", "spellcheck.pl?text=" + escape(textBox.value), true);
      req.send(null);
   }
}

function stopSpellcheck(id)
{
   textArea.value = "";
   var spellDiv = document.getElementById(id);
   for (var i = 0; i< spellDiv.childNodes.length; ++i)
   {
	if (spellDiv.childNodes[i].onblur) spellDiv.childNodes[i].onblur();
   	if (spellDiv.childNodes[i].nodeType == 3)
	{
		textArea.value += spellDiv.childNodes[i].nodeValue;
	}
	else if (spellDiv.childNodes[i].firstChild.nodeType == 3)
	{
		textArea.value += spellDiv.childNodes[i].firstChild.nodeValue;
	}
   }
   spellDiv.parentNode.replaceChild(textArea, spellDiv);
}

function processSpellcheck(textNode, req)
{
   if (req.status != 200)
   {
      alert('Spellchecking failed!  Sorry.  Received status: '+ req.status + ' ' + req.statusText);
      return;
   }
   else
   {
      checking = true;
      var spellDiv = makeSpellDiv(textNode);
      XMLResp = req.responseXML;
      badNodes = req.responseXML.getElementsByTagName('word');

      var currChar = 0;
      for (var i = 0; i < badNodes.length; ++i)
      {
         var id = textNode.id + '_bad' + i;
	 var word = badNodes[i].getAttribute('name');
	 var offset = parseInt(badNodes[i].getAttribute('offset')) - 1;

         var optionNodes = badNodes[i].getElementsByTagName('choice');

	 var words = new Array();
	 for (var j = 0; j < optionNodes.length; ++j)
	 {
	    words.push(optionNodes[j].firstChild.nodeValue);
	 }

         var options = createLinks(words, id);
	 options.push(makeEditButton(id, word));
         var dropdown = createDropdown(word, id, options, 'spelling misspelling');

	 var preceding_text = textNode.value.slice(currChar, offset);
	 spellDiv.appendChild(document.createTextNode(preceding_text));
	 spellDiv.appendChild(dropdown);
	 currChar = offset + badNodes[i].getAttribute('name').length;
      }
      
      spellDiv.appendChild(document.createTextNode(textNode.value.slice(currChar)));
      textArea = textNode.parentNode.replaceChild(spellDiv, textNode);
   }
}

function makeSpellDiv(replacedNode)
{
   var spellDiv = document.createElement('div');
   spellDiv.style.height = replacedNode.offsetHeight+'px';
   spellDiv.style.width = replacedNode.offsetWidth+'px';
   spellDiv.style.border = "1px solid black";
   spellDiv.style.margin = "0px";
   spellDiv.style.padding = "0px";
   spellDiv.style.fontFamily = "monospace";
   spellDiv.style.overflow = "auto";
   spellDiv.id = replacedNode.id;
   return spellDiv;
}
