/*
 * Simple tool for wrapping instances of specified text in a tag.
 *
 * (c) Copyright 2006 Future Medium Ptd Ltd - http://www.futuremedium.com.au/
 *
 * @author scampbell
 */

/**
 * Wraps all occurances of the specified text with the specified tag.
 *
 * @param txt     text to wrap.
 * @param tagName name of tag to wrap text with
 * @param root    (optional) root node for the search
 */
function wrap_text(txt, tagName, root) {
  if (!root) {
    root = document;
  }
  
  for (var ii = 0; ii < root.childNodes.length; ii++) {
    var el = root.childNodes[ii];

    switch (el.nodeType) {
      case 1: // ELEMENT_NODE
        wrap_text(txt, tagName, el);
        break;
        
      case 3: // TEXT_NODE
        do_wrap(txt, tagName, el);
        break;
        
      default:
        break;
    }
  }
        
  /**
   * Parses a text node, searching for all instances of the specified text, and
   * wrapping each one in the specified tag.
   *
   * @param txt  text to wrap
   * @param tag  name of tag to wrap text with
   * @param node text node to inspect
   */
  function do_wrap(txt, tagName, node) {
    var nodeTxt = node.nodeValue;
    var idx = nodeTxt.indexOf(txt);

    if (idx == -1) {
      return;
    }
    if (node.parentNode.nodeName == tagName.toUpperCase()) {
      // don't double-up if text is already wrapped
      return;
    }

    /* We only deal with the text if it occurs right at the start of the text
       node. If it occurs after the start of the node, we split the node in two
       so that the text occurs at the start of the next text node, and deal with
       it next time around. */
    
    if (idx == 0) {
      // Divide node in two so that this one only consists of the search text
      node.splitText(txt.length);

      // Create wrapper element
      var wrapperNode = document.createElement(tagName);
      wrapperNode.appendChild(document.createTextNode(node.nodeValue));

      // Replace the text node with the new wrapper element
      node.parentNode.replaceChild(wrapperNode, node);
    } else {
      /* Split the node in two so that the search text is at the start of the 
         next node processed by do_wrap */
      node.splitText(idx);
    }
  }
}