/*
 * Lipt: List injection for PRE tags
 * Author: Choan C. Galvez <choan(a)alice.0z0ne.com> <http://dizque.lacalabaza.net>
 * Suggested by Ingo Chao <http://www.satzansatz.de/cssd/listinjection.html>
 * Version: 0.2.3
 *
 * License: Whatever you like. Provided as is, no warranty, blah blah. Use at your own risk.
 *
 * Changelog:
 * 2005-07-02 Anonymous function
 * 2005-07-02 Just one '//' comment by line
 * 2005-07-01 Checks the HTML default namespace and creates the elements using it
 */
/*
See Also: lipt.css

<script language="JavaScript" type="text/javascript" src="/common/js/lipt.js"></script>
<style type="text/css">
<!--
@import url(/common/css/lipt.css);
-->
</style>

<h2>Here's a demo</h2>
<pre><code>
function foo() { // Just a demo
	//doSomething();
	doNothing();
}
</code>
</pre>
*/
(function() { // anonymous function, doesn't pollute the global namespace
//============================================
function lipt() {

  /* change to FALSE if you don't want to proccess comments (boogie buggy) */
  var PROCCESS_COMMENTS = false;

  if (!document.getElementsByTagName) { return; }

  var ns = document.getElementsByTagName('html')[0].getAttribute('xmlns');

  // look for pre tags in the doc
  var pres = document.getElementsByTagName('pre');

  if (0 == pres.length) {
    return; // no pre tags, nothing to do
  }

  for (var i = 0; i < pres.length; i++) {
    var pre = pres[i];

    // search for the first code element inside the pre
    var code = pre.getElementsByTagName('code')[0];

    if (null == code) { continue; }// no one here, try with the next pre tag

    // go for the job
    var inMultiLineComment = false;
    var inHtmlComment = false;

      //### BCM ### - change here to preserve any current (X)HTML formatting
    //var content = getText(code);
    var content = getXml(code);

    // normalize new lines
    if (!window.opera)//Opera seems to have a nice bug with global replacements
    {
      content = content.replace(/\n|\r|\r\n/g, '\n');
    }
    else
    {
      content = content.replace(/\n|\r|\r\n/, '\n');
    }
    content = content.replace(/^\n*/, '');//trim empty lines at start
    content = content.replace(/\n*$/, '');//trim empty lines at the end

    content = content.replace(/\&nbsp;/g, '\&amp;nbsp;');//### BCM ### - more replacements
    
    var lines = content.split('\n');
    
    var ol = createElement('ol', ns);
    ol.className = 'code';

    for (var j = 0; j < lines.length; j++)
    {
      var line = lines[j];
      line = line.replace(/\t/g, '    '); // replace tab with four spaces

      var cname = 'tab' + (Math.floor(countSpaces(line) / 4)); // className for this line
      var restSpaces = countSpaces(line) % 4;
      line = line.replace(/^ +/, '');
      if (restSpaces)
      {
        for (var k = 0; k < restSpaces; k++)
        {
          line = '\u00A0' + line; /* &nbsp; equivalent in Unicode */
        }
      }
      var parts = new Array();

      if (inMultiLineComment || inHtmlComment) { parts = ['', line]; }
      else { parts = [line]; }
      
      //=======================
      //comments
      if (PROCCESS_COMMENTS) {
        var slashSlashPos = line.indexOf('//');
        var starSlashPos = line.indexOf('/*');
        var slashStarPos = line.indexOf('*/');
        var htmlCmtStart = line.indexOf('<!--');
        var htmlCmtEnd   = line.indexOf('-->');

        labelSlashSlash: if (slashSlashPos != -1) {
          switch (line.charAt(slashSlashPos -1)) {
            case '"':
            case "'":
            case ':': /* don't process URIs as comments */
              break labelSlashSlash;
          }
          //parts = line.split('//');
          //parts[1] = '//' + parts[1];
          parts[0] = line.substring(0, slashSlashPos);
          parts[1] = line.substring(slashSlashPos)
        } else if (starSlashPos != -1) {
          switch (line.charAt(starSlashPos -1)) {
            case '"':
            case "'":
              break labelSlashSlash;
          }
          if (!inMultiLineComment) {
            parts = line.split('/*');
            parts[1] = '/*' + parts[1];
          }
          inMultiLineComment = true;
        }

        labelHtmlCmt: if (htmlCmtStart != -1) {
          switch (line.charAt(htmlCmtStart -1)) {
            case '"':
            case "'":
              break labelHtmlCmt;
          }
          if (!inHtmlComment) {
            parts = line.split('<!--');
            parts[1] = '<!--' + parts[1];
          }
          inHtmlComment = true;
        }

        if (slashStarPos != -1) {
          inMultiLineComment = false;
        }

        if (htmlCmtEnd != -1) {
          inHtmlComment = false;
        }
      }//end comment stuff
      //=======================

      var li = createElement('li', ns);
      li.className = cname; // tab0, tab1, etc.
      var span = createElement('code', ns);

      //var code = document.createTextNode(parts[0]);
      //span.appendChild(code);
      //### BCM ### - change here to preserve any current (X)HTML formatting
      var code = document.createElement('div');
      parts[0] = parts[0].replace(/\n/g, '');//### BCM ###
      if (parts[0].length == 0) { parts[0] += '\u00A0'; }//### BCM ### to create space for an empty line
      code.innerHTML = parts[0];
      span.appendChild(code);

      if (parts[1])
      {
        var cmt = createElement('span', ns);
        cmt.appendChild(document.createTextNode(parts[1]));
        cmt.className = 'cmt';
        span.appendChild(cmt);
      }

      //span.appendChild(document.createTextNode('\u00A0')); /* Unicode non-breaking space fix for Firefox */

      li.appendChild(span);
      ol.appendChild(li);
    };

    pre.parentNode.replaceChild(ol, pre);
    i--; // IMPORTANT: if we replace the pre, now there are n - 1 pre elements in the collection we are traversing
  };

//============================================
  function countSpaces(s) {
    var spaceCount = 0;
    for (var i = 0; i < s.length; i++) {
      if (' ' == s.substr(i,1)) {
        spaceCount++;
      } else {
        break;
      }
    };
    return spaceCount;
  }

//============================================
  function getText(node) {
    /* from JavaScript The Definitive Guide */
    var s = '';
    var children = node.childNodes;
    for (var i=0; i < children.length; i++) {
      var child = children[i];
      if (child.nodeType == 3 /* Text node */) {
        s += child.data;
      } else {
        s += getText(child);
      }
    }
    return s;
  }

//============================================
  function getXml(node)
  {
    var strXML = "";
    var temp = node.childNodes.length-1;
    for (var i = 0; i <= temp; i++)
    {
      if (node.childNodes[i].nodeType == 3)
      {
        strXML += node.childNodes[i].data;
      }
      else if (node.childNodes[i].nodeType == 1)
      {
        if (node.childNodes[i].tagName == 'SPAN')
        {
          strXML += '<span class=\"' + node.childNodes[i].className + '\">' + getXml(node.childNodes[i]) + '</span>';
        }
      }
    }//end for

    strXML = strXML.replace(/\<span([^>]*)\>/g,'!~~~span$1~~~!');
    strXML = strXML.replace(/\<\/span\>/g,'!~~~/span~~~!');
    strXML = strXML.replace(/</g,'&lt;').replace(/>/g,'&gt;');
    strXML = strXML.replace(/!~~~/g,'<').replace(/~~~!/g,'>');

    return strXML;
  }

//============================================
function inspect(elm)
{
  var str = "";
  for (var i in elm){ str += i + ": " + elm.getAttribute(i) + "\n"; }
//alert(str);
document.write(str);
}
/*EXAMPLE:
table = document.getElementById("tableMain");
inspect(table);
*/

  
//============================================
function createElement(element, ns)
{
    // Adapted from Simon Willinson's code  http://simon.incutio.com/archive/2003/06/15/javascriptWithXML
    if (ns && typeof document.createElementNS != 'undefined')
    {
      return document.createElementNS(ns, element);
    }
    if (typeof document.createElement != 'undefined')
    {
      return document.createElement(element);
    }
    return false;
  }
}

//============================================
// add the handler to the onload event
var oldOnload = window.onload;
if (typeof oldOnload == 'function') {
  window.onload = function() {
    oldOnload();
    lipt();
  }
} else {
  window.onload = lipt;
}
})(); // execute

