/*
 * File: hilite.js
 * Prerequisites: protoype.js
 */
/**
 * Class to highlight specific keywords in a node and its child nodes
 *
 * Synopsis:
 *
 *   var hiliter = new KeywordHiliter("keywords.php", document.body);
 *   hiliter.execute();
 *
 * @version 1.0
 * @author Joris Verbogt <joris@ph8.nl>
 * @copyright &copy; Mangrove 2007
 */
var KeywordHiliter = Class.create();
KeywordHiliter.prototype = {
  /**
   * @param String The Url to connect to to fetch the keywords
   * @param Element The Element and its children to search for keywords
   */
  initialize: function(url,el) {
    this.url = url;
    this.el = el;
    this.options = Object.extend({
      elementTag: 'ABBR',
      elementClass: false,
      useClassName: 'intellilink',
      useTitle: true,
      useItemID: false,
      useGetFunction: 'getKeywords'
    });
  },
  /**
   * Hilite a specific node, i.e., turn it into an abbreviation or anchor
   *
   * @param Node The node to highlight
   * @param RegExp The Expression to search for
   * @return The highlighted node, if matched
   */
  hiliteNode: function(node,matchRegExp) {
      var match = matchRegExp.exec(node.data);
      if (match) {
          // theNode is an element containing the keyword
          var theNode = node.splitText(match.index);
          theNode.splitText(match[0].length);
          var spanNode = node.ownerDocument.createElement(this.options.elementTag);
          if(this.options.useTitle) {
            spanNode.title = this.keywords[match[0].toLowerCase()];
          }
          if (this.options.useClassName != '') {
            //spanNode.addClassName(this.options.useClassName);
            Element.addClassName(spanNode,this.options.useClassName);
          }
          if (this.options.useItemID) {
            Element.addClassName(spanNode,'param-itemID=' + this.keywords[match[0].toLowerCase()]);
//            spanNode.addClassName('param-itemID=' + this.keywords[match[0].toLowerCase()]);
          }
          if (!node.parentNode.parentNode.hasClassName('no_highlight')){
	         node.parentNode.replaceChild(spanNode, theNode);
	         spanNode.appendChild(theNode);
	         return spanNode;
          }
      } else {
          return node;
      }
  },
  /**
   * Fetch the keywords and their descriptions from the Url
   */
  fetchKeywords : function() {
    new Ajax.Request(this.url, {
      method: 'post',
      postBody: 'action=' + this.options.useGetFunction,
      onSuccess: this._handleFetchKeywords.bind(this)
    });
  },
  /**
   * Set the keywords to the result of the Ajax request
   */
  _handleFetchKeywords: function(transport, json) {
    if (json) {
      this.keywords = json;
    } else {
      this.keywords = eval('(' + transport.responseText + ')');
    }
    this.execute();
  },
  /**
   * Find the keywords and highlight the nodes
   */
  execute: function() {
    if (!this.keywords || this.el.childNodes.length == 0) {
      return;
    }
    // Create a RegExp from the keywords
    var keywordsRegExp = new RegExp($H(this.keywords).keys().join("|"), "i");
    var skipElementsRegExp = /^(script|style|textarea|pre|a|h1|h2|h3|h4|h5|h6|select|input)/i;
    var node = this.el.childNodes[0];
    var depth = 1;

    while (node && depth > 0) {
        if (node.nodeType == 1) { // ELEMENT_NODE
            if (!skipElementsRegExp.test(node.tagName) && node.childNodes.length > 0) {
                node = node.childNodes[0];
                depth++;
                continue;
            }
        } else if (node.nodeType == 3) { // TEXT_NODE
            node = this.hiliteNode(node,keywordsRegExp);
        }
        while (!node.nextSibling && depth > 0) {
            node = node.parentNode;
            depth --;
        }
        if (node.nextSibling) {
            node = node.nextSibling;
        }
    }
  }
}