/****
 GoogieSpell v2
   Google spell checker for your own web-apps :)
   Copyright Amir Salihefendic 2006
 AUTHOR
   4mir Salihefendic (http://amix.dk) - amix@amix.dk
 VERSION
	 2.2 (19/02/06 22:55:11)
 LICENSE
  LGPL (read more in LGPL.txt)
 SITE
   http://amix.dk/googiespell
****/
var REQUEST;

var ERROR_WINDOW; //The drop down thingie
var LANGUAGE_WINDOW; //The drop down thingie
var EDIT_LAYER; //The layer where the suggestions are presented

var ORGINAL_TEXT;
var CURRENT_RESULTS;
var CURRENT_TEXT_AREA;
var CURRENT_ELM;
var CURRENT_LANG_SPAN;

var TA_SCROLL_TOP = 0; //TA = TextArea
var EL_SCROLL_TOP = 0; // EL = EditLayer

var item_onmouseover = function(e) { getEventElm(e).style.backgroundColor = "#FBEC72"; };
var item_onmouseout = function(e) { getEventElm(e).style.backgroundColor = "#fef3ed"; };


/****
  Main call function
****/
function googieSpellCheck(elm, name) {
  TA_SCROLL_TOP = CURRENT_TEXT_AREA.scrollTop;
  googieAppendIndicator(elm);
  
  CURRENT_ELM = elm;
  createEditLayer(CURRENT_TEXT_AREA.offsetWidth, CURRENT_TEXT_AREA.offsetHeight);

  createErrorWindow();
  document.getElementsByTagName("body")[0].appendChild(ERROR_WINDOW);

  try {
    netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
  } 
  catch (e) { 

  }

  CURRENT_ELM.onclick = null;

  createRequest();
  ORGINAL_TEXT = CURRENT_TEXT_AREA.value;
  REQUEST.open("POST", getGoogleUrl(), true);
  REQUEST.onreadystatechange = reqDone;
  var req_text = ORGINAL_TEXT.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  REQUEST.send(createXMLReq(req_text));
}


/****
  Request specific functions
****/
function createXMLReq(text) {
  return '<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>' + text + '</text></spellrequest>';
}

function createRequest() {
  REQUEST = getXMLHttpRequest();
}

//Retunrs an array
//result[item] -> ['attrs']
//                ['suggestions']
function parseResult(r_text) {
  var re_split_attr_c = /\w="\d+"/g;
  var re_split_text = /\t/g;

  var matched_c = r_text.match(/<c[^>]*>[^<]*<\/c>/g);
  var results = new Array();
  
  for(var i=0; i < matched_c.length; i++) {
    var item = new Array();

    //Get attributes
    item['attrs'] = new Array();
    var split_c = matched_c[i].match(re_split_attr_c);
    for(var j=0; j < split_c.length; j++) {
    var c_attr = split_c[j].split(/=/);
    item['attrs'][c_attr[0]] = parseInt(c_attr[1].replace('"', ''));
    }

    //Get suggestions
    item['suggestions'] = new Array();
    var only_text = matched_c[i].replace(/<[^>]*>/g, "");
    var split_t = only_text.split(re_split_text);
    for(var k=0; k < split_t.length; k++) {
    if(split_t[k] != "")
      item['suggestions'].push(split_t[k]);
    }
    results.push(item);
  }
  return results;
}


function reqDone() {
  if (REQUEST.readyState == 4) {
  if(REQUEST.status == 200) {
    var r_text = REQUEST.responseText;
    if(r_text.match(/<c.*>/) != null) {
      var results = parseResult(r_text);
      //Before parsing be sure that errors were found
      CURRENT_RESULTS = results;
      showErrorsInIframe(results);

      hideElement($('googie_change_lang'));
      //Change link text to resume
      CURRENT_ELM.innerHTML = "Resume editing";
      CURRENT_ELM.onclick = resumeEditing;
      CURRENT_ELM.className = "googie_check_spelling_ok";
      EDIT_LAYER.scrollTop = EL_SCROLL_TOP;
    }
    else {
      //No spelling error found
      CURRENT_ELM.innerHTML = "Check spelling";
      CURRENT_ELM.onclick = function(e) { googieSpellCheck(CURRENT_ELM, CURRENT_TEXT_AREA.id);};
      alert("No spelling errors found :)!");
    }
  }
  }
}



/****
 Error window (the drop-down window)
****/
//Set up the error window
function createErrorWindow() {
  ERROR_WINDOW = document.createElement("div");
  ERROR_WINDOW.className = "googie_window";
}

function hideErrorWindow() {
  ERROR_WINDOW.style.visibility = "hidden";
}


function updateOrginalText(offset, old_value, new_value, id) {
  var part_1 = ORGINAL_TEXT.substring(0, offset);
  var part_2 = ORGINAL_TEXT.substring(offset+old_value.length);
  ORGINAL_TEXT = part_1 + new_value + part_2;
  var add_2_offset = new_value.length - old_value.length;
  for(var j=0; j < CURRENT_RESULTS.length; j++) {
    //Don't edit the offset of the current item
    if(j != id && j > id){
      CURRENT_RESULTS[j]['attrs']['o'] += add_2_offset;
    }
  }
}

function saveOldValue(id, old_value) {
  CURRENT_RESULTS[id]['is_changed'] = true;
  CURRENT_RESULTS[id]['old_value'] = old_value;
}

function showErrorWindow(elm, id) {
  var abs_pos = absolutePosition(elm);
  abs_pos.y -= EDIT_LAYER.scrollTop;
  ERROR_WINDOW.style.visibility = "visible";
  ERROR_WINDOW.style.top = (abs_pos.y+20) + "px";
  ERROR_WINDOW.style.left = (abs_pos.x) + "px";
  ERROR_WINDOW.innerHTML = "";

  //Build up the result list
  var table = TABLE({'class': 'googie_list'});
  var list = TBODY();

  var suggestions = CURRENT_RESULTS[id]['suggestions'];
  var offset = CURRENT_RESULTS[id]['attrs']['o'];
  var len = CURRENT_RESULTS[id]['attrs']['l'];

  if(suggestions.length == 0) {
    var row = TR();
    var item = TD();
    var dummy = SPAN();
    item.appendChild(TN("No suggestions :("));
    row.appendChild(item);
    list.appendChild(row);
  }

  for(i=0; i < suggestions.length; i++) {
    var row = TR();
    var item = TD();
    var dummy = SPAN();
    dummy.innerHTML = suggestions[i];
    item.appendChild(TN(dummy.innerHTML));
    
    var correctError = function (l_elm) {
      var old_value = elm.innerHTML;
      var new_value = l_elm.innerHTML;

      elm.style.color = "green";
      elm.innerHTML = l_elm.innerHTML;
      hideErrorWindow();

      updateOrginalText(offset, old_value, new_value, id);

      //Update to the new length
      CURRENT_RESULTS[id]['attrs']['l'] = new_value.length;
      saveOldValue(id, old_value);
    };

    item.onclick = function(e) {correctError(getEventElm(e))};
    item.onmouseover = item_onmouseover;
    item.onmouseout = item_onmouseout;
    row.appendChild(item);
    list.appendChild(row);
  }
  
  //The element is changed, append the revert
  if(CURRENT_RESULTS[id]['is_changed']) {
    //Close button
    var old_value = CURRENT_RESULTS[id]['old_value'];
    var offset = CURRENT_RESULTS[id]['attrs']['o'];
    var revert_row = TR();
    var revert = TD({'class': 'googie_list_revert'});

    revert.onmouseover = item_onmouseover;
    revert.onmouseout = item_onmouseout;
    revert.appendChild(TN("Revert to " + old_value));

    revert.onclick = function(e) { 
      updateOrginalText(offset, elm.innerHTML, old_value, id);
      elm.style.color = "#b91414";
      elm.innerHTML = old_value;
      hideErrorWindow();
    };

    revert_row.appendChild(revert);
    list.appendChild(revert_row);
  }

  //Append the edit box
  var edit_row = TR();
  var edit = TD();

  var edit_input = INPUT({'style': 'width: 110px;'});

  var onsub = function () {
    saveOldValue(id, elm.innerHTML);
    updateOrginalText(offset, elm.innerHTML, edit_input.value, id);
    elm.style.color = "green"
    elm.innerHTML = edit_input.value;
    
    hideErrorWindow();
    return false;
  };
  
  var ok_pic = IMG({'src': GOOGIE_IMAGE_DIR + "ok.gif"});
  var edit_form = FORM({'style': 'margin: 0; padding: 0'}, edit_input, " ", ok_pic);
  ok_pic.onclick = onsub;
  edit_form.onsubmit = onsub;
  
  edit.appendChild(edit_form);
  edit_row.appendChild(edit);
  list.appendChild(edit_row);

  //Close button
  var close_row = TR();
  var close = TD({'class': 'googie_list_close'});
  close.onmouseover = item_onmouseover;
  close.onmouseout = item_onmouseout;
  close.appendChild(TN("Close"));
  close.onclick = function() { hideErrorWindow()};
  close_row.appendChild(close);
  list.appendChild(close_row);

  table.appendChild(list);
  ERROR_WINDOW.appendChild(table);
}


/****
  Edit layer (the layer where the suggestions are stored)
****/
function createEditLayer(width, height) {
  EDIT_LAYER = DIV({'class': 'googie_edit_layer'});
  EDIT_LAYER.style.width = width + "px";
  EDIT_LAYER.style.height = height + "px";
}


function resumeEditing(e) {
  $('googie_change_lang').style.display = "inline";

  EL_SCROLL_TOP = EDIT_LAYER.scrollTop;
  var elm = getEventElm(e);
  elm.innerHTML = "Check spelling";
  elm.onclick = function(e) { googieSpellCheck(elm, CURRENT_TEXT_AREA.id);};
  hideErrorWindow();

  //Remove the EDIT_LAYER
  EDIT_LAYER.parentNode.removeChild(EDIT_LAYER);

  CURRENT_TEXT_AREA.value = ORGINAL_TEXT;
  showElement(CURRENT_TEXT_AREA);
  CURRENT_ELM.className = "googie_check_spelling_link";

  CURRENT_TEXT_AREA.scrollTop = TA_SCROLL_TOP;

  elm.onmouseout = null;
}

function createErrorLink(text, id) {
  var elm = SPAN({'class': 'googie_link'});
  elm.onclick = function () { showErrorWindow(elm, id); };
  elm.innerHTML = text;
  return elm;
}

function showErrorsInIframe(results) {
  var output = DIV();
  output.style.textAlign = "left";
  var is_safari = (navigator.userAgent.toLowerCase().indexOf("safari") != -1);
  var pointer = 0;
  for(var i=0; i < results.length; i++) {
    var offset = results[i]['attrs']['o'];
    var len = results[i]['attrs']['l'];
    
    var part_1_text = ORGINAL_TEXT.substring(pointer, offset).replace(/\n/g, "<BR>");
    var part_1 = SPAN();
    part_1.innerHTML = part_1_text;
    if(part_1_text.substring(0, 1) == " ")
      output.appendChild(TN(" "));
    output.appendChild(part_1);
    if(part_1_text.substr(part_1_text.length-1, 1) == " " && is_safari)
      output.appendChild(TN(" "));
    pointer += offset - pointer;
    
    //If the last child was an error, then insert some space
    output.appendChild(createErrorLink(ORGINAL_TEXT.substr(offset, len), i));
    pointer += len;
  }
  //Insert the rest of the orginal text
  var part_2 = SPAN();
  part_2.innerHTML = ORGINAL_TEXT.substr(pointer, ORGINAL_TEXT.length).replace(/\n/g, "<BR>");
  output.appendChild(part_2);

  EDIT_LAYER.appendChild(output);

  //Hide text area
  hideElement(CURRENT_TEXT_AREA);
  CURRENT_TEXT_AREA.parentNode.insertBefore(EDIT_LAYER, CURRENT_TEXT_AREA.nextSibling);
}


/****
 Misc. functions
****/
function Position(x, y) {
  this.x = x;
  this.y = y;
}	

//Get the absolute position of menu_slide
function absolutePosition(element) {
  //Create a new object that has elements y and x pos...
  var posObj = new Position(element.offsetLeft, element.offsetTop);

  //Check if the element has an offsetParent - if it has .. loop until it has not
  if(element.offsetParent) {
    var temp_pos =	absolutePosition(element.offsetParent);
    posObj.x += temp_pos.x;
    posObj.y += temp_pos.y;
  }

  return posObj;
}

function getEventElm(e)
{
	var targ;
	if (!e) var e = window.event;
	if (e.target) targ = e.target;
	else if (e.srcElement) targ = e.srcElement;
	if (targ.nodeType == 3) // defeat Safari bug
		targ = targ.parentNode;
  return targ;
}

function googieAppendIndicator(elm) {
  var img = document.createElement('img');
  img.src = GOOGIE_IMAGE_DIR + "indicator.gif";
  img.style.textDecoration = "none";
  elm.appendChild(img);
}

/****
 Choose language
****/
var langlist_codes = new Array("da", "nl", "en", "fi", "fr", "de", "it", "pl", "pt", "es", "sv");
var lang_to_word = {"da": "Danish", "nl": "Dutch", "en": "English",
                              "fi": "Finnish", "fr": "French", "de": "German",
                              "it": "Italian", "pl": "Polish", "pt": "Portuguese",
                              "es": "Spanish", "sv": "Swedish"};

function createLangWindow() {
  LANGUAGE_WINDOW = DIV({'id': 'lang_win', 'class': 'googie_window'});

  //Build up the result list
  var table = TABLE({'class': 'googie_list'});
  var list = TBODY();

  for(i=0; i < langlist_codes.length; i++) {
    var row = TR();
    var item = TD({'id': langlist_codes[i]});
    item.appendChild(TN(lang_to_word[langlist_codes[i]]));
    
    var switchLang = function(elm) {
      deHighlightCurSel($(CURRENT_LANG));
      CURRENT_LANG = elm.id;
      CURRENT_LANG_SPAN.innerHTML = lang_to_word[elm.id];

      //Set cookie
      var now = new Date();
      now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000);
      setCookie('language', CURRENT_LANG, now);

      highlightCurSel(elm);
      hideLangWindow();
    };
    
    item.onclick = function(e) {switchLang(getEventElm(e))};
    item.onmouseover = function(e) { 
      var i_it = getEventElm(e);
      if(i_it.className != "googie_list_selected")
        i_it.className = "googie_list_onhover"; 
    };
    item.onmouseout = function(e) { 
      var i_it = getEventElm(e);
      if(i_it.className != "googie_list_selected")
        i_it.className = "googie_list_onout"; 
    };
    row.appendChild(item);
    list.appendChild(row);
  }

  //Close button
  var close_row = TR();
  var close = TD({'class': 'googie_list_close'});
  close.onmouseover = item_onmouseover;
  close.onmouseout = item_onmouseout;
  close.appendChild(TN("Close"));
  close.onclick = function(e) { hideLangWindow(); item_onmouseout(e);};
  close_row.appendChild(close);
  list.appendChild(close_row);

  table.appendChild(list);
  LANGUAGE_WINDOW.appendChild(table);
}
createLangWindow();

function hideLangWindow() {
  LANGUAGE_WINDOW.style.visibility = "hidden";
}

//Highlight the current selected language
function deHighlightCurSel(elm) {
  elm.className = "googie_list_onout";
}
function highlightCurSel(elm) {
  elm.className = "googie_list_selected";
}

function showLangWindow(elm) {
  var abs_pos = absolutePosition(elm);
  LANGUAGE_WINDOW.style.visibility = "visible";
  LANGUAGE_WINDOW.style.top = (abs_pos.y+20) + "px";
  LANGUAGE_WINDOW.style.left = (abs_pos.x+8) + "px";
  highlightCurSel($(CURRENT_LANG));
}


function chooseLanguage(elm) {
  var lang_win = $("lang_win");
  if(lang_win == null) {
  document.getElementsByTagName("body")[0].appendChild(LANGUAGE_WINDOW);
  }
  showLangWindow(elm);
}


/* Decorate function */
function googieDecorateTextarea(id) {
  CURRENT_TEXT_AREA = $(id);
  if(CURRENT_TEXT_AREA != null) {
    var table = TABLE();
    var tbody = TBODY();
    var tr = TR();
    var switch_lan = TD();
    var check_spl = TD();

    table.style.width = CURRENT_TEXT_AREA.style.width;
    switch_lan.style.width = "200px";
    check_spl.style.width = "100%";
    check_spl.style.textAlign = "right";
    
    check_spl.innerHTML = '<img src="' + GOOGIE_IMAGE_DIR + 'spellc.gif" alt="" /> <span onclick="googieSpellCheck(this)" class="googie_check_spelling_link">Check spelling</span>';

   // switch_lan.innerHTML = '<a class="googie_check_spelling_link" onclick="chooseLanguage(this)" id="googie_change_lang" style="width: 20px"><img src="' + GOOGIE_IMAGE_DIR + 'ch_off.gif" alt="Change lang" onmouseover="this.src=\'' + GOOGIE_IMAGE_DIR + 'ch_on.gif\'" onmouseout="this.src=\'' + GOOGIE_IMAGE_DIR +'ch_off.gif\'" /></a>';
   switch_lan.innerHTML = '<a class="googie_check_spelling_link" id="googie_change_lang" style="width: 20px">';

    tr.appendChild(switch_lan);
    tr.appendChild(check_spl);

    tbody.appendChild(tr);
    table.appendChild(tbody);

    insertBefore(table, CURRENT_TEXT_AREA);

    CURRENT_LANG_SPAN = SPAN({'class': 'googie_cur_lang_display'}, lang_to_word[CURRENT_LANG]);

    var div = DIV({'style': 'text-align: right;'});
    div.style.width = CURRENT_TEXT_AREA.style.width;
    //div.appendChild(SPAN({'class': 'googie_cur_lang'}, "Current language: ", CURRENT_LANG_SPAN));
    div.appendChild(SPAN({'class': 'googie_cur_lang'}, ""));
    insertAfter(div, CURRENT_TEXT_AREA);
  }
  else {
    //alert("Text area not found");
  }

}

