
function addOnloadEvent(fun) {    
  var old = window.onload;
  if (old) {  
    window.onload = function () { old(); fun(); }}
  else {
    window.onload = fun; }}

function addEventCatcher(element, event, fun) {
  element["on" + event] = 
    function (event) { 
      fun(); 
      return false; }}

// DOM utils

function innerText(element) {
  if (element.innerText != undefined) {
    return element.innerText }
  else {    
    var text = ""; 
    mapArray(element.childNodes, 
      function (e) { 
        switch (e.nodeType) { 
          case 1: text += innerText(e); break;
          case 3: text += e.nodeValue; break; }});
    return text }}

function elementInsertFirst(element, newChild) {
  if (element.firstChild) {
    element.insertBefore(newChild, element.firstChild); }
  else {
    element.appendChild(newChild); }}
   
        
function elementInsertAfter(element, newChild, refChild) {
  var before = refChild.nextSibling;
  if (before) {
    element.insertBefore(newChild, before); } 
  else {
    element.appendChild(newChild); }}     
        
function elementHasClass(element, className) {
  if (!element.className) { return false }
  var re = new RegExp("(^|\\s+)" + className + "($|\\s+)");
  return re.exec(element.className); }

function elementSetClass(element, className) {
  if (!element.className) { 
    return element.className = className }
  else if (!elementHasClass(element, className)) {
    return element.className += " " + className }}
    
// FIXME: \b does not work when hypens are used in class    

function elementRemoveClass(element, className) {
  if (!element.className) { return false }
  var removed = false;
  var re = new RegExp("\\s*\\b" + className + "\\b\\s*");
  element.className = element.className.replace(re, 
    function (str, offset, s) {
      removed = true;
      return offset==0 || str.length+offset==s.length ? "" : " " })
  return removed }  
    
function elementsWithClass(elements, className) {
  return filterArray(elements, elementHasClass.rcurry(className)); }

function getElementsByClass(element, className, tagName) { 
  return elementsWithClass(element.getElementsByTagName(tagName || "*"),
                           className); }

function getElementsByName(name) {
  return filterArray(document.getElementsByTagName("*"), 
    function (e) { return e.name == name; })}

// General utils


// Return a function bound to an object
function delegate(object, methodName) {
  return function () {
    return object[methodName].apply(object, arguments); }}    
                                                                        
function doArray(array, fun) {
  for (var i=0; i<array.length; i++) {
    fun(array[i]); }}

function mapArray(array, fun) {
  var collect = new Array();
  for (var i=0; i<array.length; i++) {
    collect.push(fun(array[i])); }
  return collect; }
  
function filterArray(array, fun) {
  var a = [];
  doArray(array, function (i) { if (fun(i)) { a.push(i); }});
  return a; }

Array.prototype.contains = function (value) {
  for (var i=0; i<this.length; i++) {
    if (this[i]==value) { 
      return true; }}
  return false; }

function makeArray(fakeArray) {
  var array = [];
  for (var i=0; i<fakeArray.length; i++) {
    array.push(fakeArray[i]); }
  return array; }

Function.prototype.curry = function () { 
  var args = makeArray(arguments), self = this;
  return function () { 
    return self.apply(self, args.concat(makeArray(arguments))); }}
  
Function.prototype.rcurry = function () { 
  var args = makeArray(arguments), self = this;
  return function () { 
    return self.apply(self, makeArray(arguments).concat(args)); }}
     
               


function initTabbedPanes() {
  mapArray(getElementsByClass(document, "become-tabbed-pane"),
           initTabbedPane); } 

function initTabbedPane(paneElement) {
  var menus = getElementsByClass(paneElement, "become-tabbed-menu");
  if (menus.length==1) {
    initTabbedPaneWithMenu(paneElement, menus[0]); } 
  else {
    initTabbedPaneWithoutMenu(paneElement) }
  
  elementRemoveClass(paneElement, "become-tabbed-pane");
  elementSetClass(paneElement, "tabbed-pane"); }

function initTabbedPaneWithMenu(paneElement, menu) {
  var tabs = new Array(); 
  var activeSheetId = (window.location + "#").split("#")[1].split("?")[0];
  var activeSheet;
  
  mapArray(menu.getElementsByTagName("a"), function (a) {
    var tab = new PredefinedTab(a, tabs);
    if (tab.sheet.id==activeSheetId) { activeSheet = tab; }
    elementSetClass(tab.sheet, "tabbed-pane-sheet"); });
  
  elementRemoveClass(menu, "become-tabbed-menu");
  elementSetClass(menu, "tabbed-menu");
  if (activeSheet) 
    { activeSheet.activate(); }
  else if (tabs[0]) { tabs[0].activate(); }}
  
function initTabbedPaneWithoutMenu(paneElement) {
  var menu = document.createElement("ul"),
      tabs = new Array();
  elementSetClass(menu, "tabbed-menu");  
  
  mapArray(paneElement.childNodes, function (sheet) {
    if (sheet.nodeType != 1) return;
               
    var label = sheet.title;
    if (!label) {
      var labelElement = sheet.firstChild;        
      while (labelElement.nodeType != 1) { 
        labelElement = labelElement.nextSibling; }
      label = innerText(labelElement);
      /* sheet.removeChild(labelElement); */ }
                  
    elementSetClass(sheet, "tabbed-pane-sheet");    
            
    var tab = new Tab(label, sheet, tabs);    
    var li = document.createElement("li");    
    li.appendChild(tab.anchor);    
    menu.appendChild(li); });
  
  paneElement.insertBefore(menu, paneElement.firstChild);
  if (tabs[0]) { tabs[0].activate(); }}

function tabOnClick(tab) {
  return function (event) { tab.activate(); return false; }}

function Tab (label, sheet, siblings) {  
  var a = document.createElement("a");
  a.href = "#";
  a.appendChild(document.createTextNode(label));    
  a.onclick = tabOnClick(this);
  
  this.anchor = a;
  this.sheet = sheet;  
  this.siblings = siblings;
  siblings.push(this); }  
  
function PredefinedTab (a, siblings) {  
  a.onclick = tabOnClick(this);  
  this.anchor = a;
  this.sheet= document.getElementById(a.href.split('#')[1]);
  this.siblings = siblings;
  siblings.push(this); }    

Tab.prototype.activate = function () {  
  mapArray(this.siblings, function (tab) {
    tab.sheet.style.display = "none"; 
    elementRemoveClass(tab.anchor.parentNode, "current");
    tab.anchor.href = "#" + tab.sheet.id; });
  this.anchor.removeAttribute("href");
  elementSetClass(this.anchor.parentNode, "current");
  this.sheet.style.display = "block"; }

PredefinedTab.prototype.activate = Tab.prototype.activate;
        
addOnloadEvent(initTabbedPanes); 
               