if (window.include) {
    include('/js/classLite.js');
} else if ("undefined"==typeof(addClass)) {
    function classRE (className) {
	// don't worry about escaping special characters, as they're invalid
	// class names
	return new RegExp('(?:^|\\s+)'+className+'(?:\\s+|$)');
    }
    // simplified versions of the functions in class.js
    function addClass(node, className) {
	if (!classRE(className).test(node.className)) {
	    node.className += " "+className;
	}
    }
    function removeClass(node, className) {
	node.className = node.className.replace(classRE(className), ' ');
    } 

}

/*
if (! window.dbgMsg) {
    function dbgMsg(msg) {}
}
*/

function nodeName(node) {
    return "#"+node.id+".{"+node.className+'}';
}

function funcName(func) {
    var matches = func.toString().match(/function[^(]*\([^)]*\)/);
    return matches[0];
}

function objName(obj) {
    if (null == obj) return "null";
    if ("string" == typeof(obj)) return obj;
    if ("function" == typeof(obj))
	return funcName(obj);
    if (1 == obj.nodeType)
	return nodeName(obj);
    return 'unknown';
}

function joinArgs(args, joint) {
    var str = '';
    if (! joint) joint = ', ';
    if (args.length) {
	str = objName(args[0])+'';
	for (var i=1; i < args.length; ++i) {
	    str += joint + objName(args[i]);
	}
    }
    return str;
}

// IE doesn't define HTMLElement::ELEMENT_NODE, so can't use node.ELEMENT_NODE
function isElementNode(node) { return 1 == node.nodeType; }
function nextSibling(node) { return node.nextSibling; }
function previousSibling(node) { return node.previousSibling; }

function Tabset () {
    this.resetCurrent();
}
Tabset.prototype.states = {
  show: {style: {display: 'block', visibility: 'visible'}, 
	 tabClass: 'selected', panelClass:'selected', callback: ''},
  hide: {style: {display: '', visibility: 'hidden'},
	 tabClass:'', panelClass:'hidden', callback: ''}
};
Tabset.prototype.tabSuffix = 'Tab';
Tabset.prototype.panelSuffix = 'Panel';

Tabset.prototype.resetCurrent = function () {
    this.currPanel = {style: this.states.hide.style, className: this.states.hide.panelClass};
    this.currTab = {className: this.states.hide.tabClass};
};

Tabset.prototype.setTabSuffix = function(suff) 
{ this.tabSuffix = suff; }
Tabset.prototype.setPanelSuffix = function(suff) 
{ this.panelSuffix = suff; }

Tabset.prototype.setShowClass = function(className) 
{ this.states.show.panelClass=this.states.show.tabClass = className; };
Tabset.prototype.setShowPanelClass = function(className) 
{ this.states.show.panelClass = className; };
Tabset.prototype.setShowTabClass = function(className) 
{ this.states.show.tabClass = className; };
/* setHide*Class not use (yet) */
Tabset.prototype.setHideClass = function(className) 
{ this.states.hide.panelClass=this.states.hide.tabClass = className; };
Tabset.prototype.setHidePanelClass = function(className) 
{ this.states.hide.panelClass = className; };
Tabset.prototype.setHideTabClass = function(className) 
{ this.states.hide.tabClass = className; };

Tabset.prototype.setCallback = function (callback, state) 
{ 
    if (state) {
	this.states[state].callback = callback; 
    } else {
	for (state in this.states) {
	    this.states[state].callback = callback; 
	}
    }
};
Tabset.prototype.setShowCallback = function (callback) 
{ this.states.show.callback = callback; };
Tabset.prototype.setHideCallback = function (callback) 
{ this.states.hide.callback = callback; };

Tabset.prototype.setState = function(node, state) { addClass(node, state); };
Tabset.prototype.unsetState = function(node, state) { removeClass(node, state); };

Tabset.prototype.setCurrentTab = function (tab) {
    if (this.currTab) {
	this.setUnselectedTab(this.currTab);
    }
    this.setSelectedTab(tab);
    currTab = tab;
};

Tabset.prototype.setSelectedPanel = function(node) 
{ 
    addClass(node, this.states.show.panelClass); 
    if (this.states.hide.panelClass) 
    {removeClass(node, this.states.hide.panelClass);}
};
Tabset.prototype.setUnselectedPanel = function(node) 
{ 
    removeClass(node, this.states.show.panelClass);
    if (this.states.hide.panelClass) 
    {addClass(node, this.states.hide.panelClass);}
};
Tabset.prototype.setSelectedTab = function(node) 
{ 
    addClass(node, this.states.show.tabClass); 
    if (this.states.hide.tabClass) 
    {removeClass(node, this.states.hide.tabClass);}
};
Tabset.prototype.setUnselectedTab = function(node) 
{ 
    removeClass(node, this.states.show.tabClass); 
    if (this.states.hide.tabClass) 
    {addClass(node, this.states.hide.tabClass);}
};

Tabset.prototype.pickNode = function (nodes, isTheNode) {
    for (var i=0; i < nodes.length; ++i) {
	if (isTheNode(nodes[i])) {
	    return nodes[i];
	}
    }
    //return undefined
};

Tabset.prototype.findNode = function (node, isTheNode, nextNode) {
    //dbgMsg('findNode('+joinArgs(arguments)+')', 2);
    while (node && !isTheNode(node)) {
	//dbgMsg("considering "+objName(node), 3);
	node = nextNode(node);
    }
    //dbgMsg("found "+objName(node), 2);
    return node;
};

Tabset.prototype.setHiddenStyle = function(node) {
    node.style.display=this.states.hide.style.display;
    node.style.visibility=this.states.hide.style.visibility;
}
Tabset.prototype.setShownStyle = function (node) {
    node.style.display=this.states.show.style.display;
    node.style.visibility=this.show.style.visibility;
}

Tabset.prototype.hideNode = function (node, callback, tab) {
    //dbgMsg("hideNode("+joinArgs(arguments, ', ')+")", 2);

    if (node) {
	//this.setHiddenStyle(node);
	this.setUnselectedPanel(node);
	if (tab) this.setUnselectedTab(tab);
	if (node == this.currPanel) {
	    this.resetCurrent();
	}
	if (callback) {
	    callback(node, tab, 'hide');
	}
    }
};

Tabset.prototype.showNode = function (node, callback, tab) {
    //dbgMsg("showNode("+joinArgs(arguments, ', ')+")");

    if (node) {
	//this.setShownStyle(node);
	this.setSelectedPanel(node);
	this.currPanel = node;
	if (tab) {
	    node.tab = tab;
	    this.setSelectedTab(tab);
	    this.currTab = tab;
	}

	if (callback) {
	    callback(node, tab, 'show');
	}
    }
};

Tabset.prototype.switchToNodeAndCall = function (node, callback, tab) {
    //dbgMsg("switchToNodeAndCall("+joinArgs(arguments, ', ')+")", 2);
    if (node) {
	if (this.currPanel) {
	    this.hideNode(this.currPanel, callback, this.currTab);
	}
	this.showNode(node, callback, tab);
    }
}

Tabset.prototype.switchToNode = function (node, tab) {
    //dbgMsg("switchToNode("+joinArgs(arguments, ', ')+")", 1);

    if (node) {
	if (this.currPanel) {
	    this.hideNode(this.currPanel, this.states.hide.callback, this.currTab);
	}
	this.showNode(node, this.states.show.callback, tab);
    }
}

/*
Tabset.prototype.searchAndVisNode = function (visFunc, tab, callback, isTheNode, nextNode) {
    var node = this.findNode(tab, isTheNode, nextNode );
    this.visFunc(node, callback, tab);
};
*/

Tabset.prototype.searchAndShowNode = function (tab, callback, isTheNode, nextNode) {
    var node = this.findNode(tab, isTheNode, nextNode );
    this.showNode(node, callback, tab);
};
Tabset.prototype.searchAndHideNode = function (visFunc, tab, callback, isTheNode, nextNode) {
    var node = this.findNode(tab, isTheNode, nextNode );
    this.hideNode(node, callback, tab);
};

Tabset.prototype.showNextNodeAndCall = function (tab, callback, isTheNode) {
    if (! isTheNode) {
	isTheNode = isElementNode;
    }
    var node = this.findNode(tab.nextSibling, isTheNode, nextSibling);
    this.showNode(node, callback, tab);
};

Tabset.prototype.showNextNode = function (tab, isTheNode) {
    this.showNextNodeAndCall(tab, this.states.show.callback, isTheNode);
}

Tabset.prototype.switchToNextNodeAndCall = function (tab, callback, isTheNode) {
    if (! isTheNode) {
	isTheNode = isElementNode;
    }
    var node = this.findNode(tab.nextSibling, isTheNode, nextSibling);
    this.switchToNodeAndCall(node, callback, tab);
};
Tabset.prototype.switchToNextNode = function (tab, isTheNode) {
    if (! isTheNode) {
	isTheNode = isElementNode;
    }
    var node = this.findNode(tab.nextSibling, isTheNode, nextSibling);
    this.switchToNode(node, tab);
}

Tabset.prototype.hideNextNode = function (tab, callback, isTheNode) {
    if (! isTheNode) {
	isTheNode = isElementNode;
    }
    var node = this.findNode(tab.nextSibling, isTheNode, nextSibling);
    this.hideNode(node, callback, tab);
};
Tabset.prototype.hideNextNode = function (tab, isTheNode) {
    this.hideNextNodeAndCall(tab, this.states.hide.callback, isTheNode);
}

Tabset.prototype.showById = function (tab) {
    //dbgMsg("showById("+objName(tab)+")");
    var node = this.resolveID(tab);
    this.showNode(node, this.states.show.callback, tab);
};

Tabset.prototype.switchByIdAndCall = function (tab, callback) {
    var node = this.resolveID(tab);
    this.switchToNodeAndCall(node, callback, tab);
};

Tabset.prototype.switchById = function (tab) {
    var node = this.resolveID(tab);
    this.switchToNode(node, tab);
};

Tabset.prototype.hideById = function (tab, callback) {
    var node = this.resolveID(tab);
    this.hideNode(node, callback, tab);
};


Tabset.prototype.resolveID = function(obj) {
    var nodeID = this.extractID(typeof(obj) == "string" ? obj : obj.id);
    return document.getElementById(nodeID + this.panelSuffix) 
	    || document.getElementById(nodeID+"Panel")
	    || document.getElementById(nodeID);
}

Tabset.prototype.extractID = function (tabID) {
    var endPos = tabID.length - this.tabSuffix.length;
    //dbgMsg("extractID("+tabID+"): "+tabID.substring(endPos));
    if (this.tabSuffix == tabID.substring(endPos)) {
		return tabID.substring(0,endPos);
    }
    return tabID;
};

