function createElement(element) {
  element = element.toLowerCase();
  if (typeof document.createElementNS != 'undefined')
    return document.createElementNS('http://www.w3.org/1999/xhtml', element);
  if (typeof document.createElement != 'undefined')
    return document.createElement(element);
  return false;
}

function addClass(el,val) {
  if (!el.className) el.className = val;
  else {
    newClassName = el.className + " " + val;
    el.className = newClassName;
  }
}

function insertAfter(newElement,targetElement) {
  var parent = targetElement.parentNode;
  if (parent.lastChild == targetElement) parent.appendChild(newElement);
  else parent.insertBefore(newElement,targetElement.nextSibling);
}

/* --- code view --- */

// set initial view ('pre' or 'ol', defaults to 'pre')
var initialView = 'ol';
var classCodePre = 'code';

function initCodeView() {
  if (!document.getElementsByTagName) return;

  // find all pre elements
  var els = document.getElementsByTagName("pre");
  var numEls = els.length;
  for (var i=0;i<numEls;i++) {
    if (els[i].className && els[i].className.match(classCodePre)) {
      // create, hide and append code list
      var elAlt = createCodeList(els[i]);

      if (initialView === 'ol') els[i].style.display = 'none';
      else elAlt.style.display = 'none';
      insertAfter(elAlt,els[i]);

      // build toggle control
      var elToggle = createElement("a");
      elToggle.appendChild(document.createTextNode("Toggle Code View"));
      elToggle.setAttribute('href',"javascript:;");

      // add toggle event
      elToggle.onclick = function (e) {
        toggleCodeView(this);
      }
      if (elToggle.captureEvents) elToggle.captureEvents(Event.ONCLICK);

      // append control to paragraph and insert before the list
      var elToggleWrap = createElement("p");
      if (initialView === 'ol') addClass(elToggleWrap,"contract");
      else addClass(elToggleWrap,"expand");
      elToggleWrap.appendChild(elToggle);
      els[i].parentNode.insertBefore(elToggleWrap,els[i]);
    }
  }
}

// creates an ordered list as the alternative display for preformatted lines in
// code elements
// note: it is impractical to use line returns to split lines in IE, so use
// a code element for each line in the pre
function createCodeList(elCodePre) {
  var elCodeOl = createElement("ol");
  addClass(elCodeOl,'code');

  // iterate through list to grab lines of code
  var odd = true;
  var elsNodes = elCodePre.childNodes;
  var numNodes = elsNodes.length;
  for (var i=0;i<numNodes;i++) {
    // if we have a line of code, grab it (cheat a little and grab innerHTML)
    if (elsNodes[i].nodeName.toLowerCase() === 'code') {
      var elCode = createElement("code");
	  if (elsNodes[i].className) {
		addClass(elCode, elsNodes[i].className);
	  }
      elCode.innerHTML = elsNodes[i].innerHTML;

      var elCodeLi = createElement("li");
	  elCodeLi.className = elCode.className;
      elCodeLi.appendChild(elCode);

      // alternate the classes
      if (odd) {
        addClass(elCodeLi,'odd');
        odd = false;
      } else odd = true;

      elCodeOl.appendChild(elCodeLi);
    }
  }
  return elCodeOl;
}

function toggleCodeView(control) {
  var elOrig = control.parentNode.nextSibling;
  var elAlt = elOrig.nextSibling;

  if (elAlt.style.display == 'none') {
    elOrig.style.display = 'none';
    elAlt.style.display = 'block';
    control.parentNode.className = "contract";
  } else {
    elAlt.style.display = 'none';
    elOrig.style.display = 'block';
    control.parentNode.className = "expand";
  }
}

function doCodeView(el) {
  var els = el.childNodes;
  var numEls = els.length;

  // find all pre elements
  for (var i=0;i<numEls;i++) {
    if ((els[i].nodeName.toLowerCase() == "pre") &&
        els[i].className && els[i].className.match(classCodePre)) {
      // create, hide and append code list
      var elAlt = createCodeList(els[i]);

      if (initialView === 'ol') els[i].style.display = 'none';
      else elAlt.style.display = 'none';
      insertAfter(elAlt,els[i]);

      // build toggle control
      var elToggle = createElement("a");
      elToggle.appendChild(document.createTextNode("Toggle Code View"));
      elToggle.setAttribute('href',"javascript:;");

      // add toggle event
      elToggle.onclick = function (e) {
        toggleCodeView(this);
      }
      if (elToggle.captureEvents) elToggle.captureEvents(Event.ONCLICK);

      // append control to paragraph and insert before the list
      var elToggleWrap = createElement("p");
      if (initialView === 'ol') addClass(elToggleWrap,"contract");
      else addClass(elToggleWrap,"expand");
      elToggleWrap.appendChild(elToggle);
      els[i].parentNode.insertBefore(elToggleWrap,els[i]);
    }
  }
}

$(document).ready(function() {
  initCodeView();
});
