function TabBar(defaultWidth,frameset,hasVerticalSplitter,css,
	captionLeftImage,captionCenterImage,captionRightImage,captionImageHeight,
  captionLeftImageWidth,captionRightImageWidth,firstCaptionImageSuffix)
{
	this.addTab = addTab;
	this.addPanel = addPanel;
	this.addTabLink = addTabLink;
	this.draw = draw;
	this.refresh = refresh;
	this.selectTab = selectTab;
	this.selectTabWithIndex = selectTabWithIndex;
	this.getFramesetRows = getFramesetRows;
	this.getTab = getTab;
	this.getTabWithContentWindow = getTabWithContentWindow;
	this.hideTab = hideTab;
	this.showTab = showTab;
	this.doSlide = doSlide;
	this.slide = slide;
	this.slideVertical = slideVertical;
	this.getContentHeight = getContentHeight;
	this.getTabLink = getTabLink;
	this.getTabLinkWithUrl = getTabLinkWithUrl;
	this.getTabWithTabLink = getTabWithTabLink;
	this.getTabWithTabLinkUrl = getTabWithTabLinkUrl;
	this.getVerticalSplitterFrame = getVerticalSplitterFrame;
	this.getVerticalSplitterWindow = getVerticalSplitterWindow;
	this.open = open;
	this.close = close;
	this.verticalSplitterSlide = verticalSplitterSlide;
	this.positionVerticalSplitter = positionVerticalSplitter;
	this.selectTabLink = selectTabLink;
	this.pointToTabLink = pointToTabLink;
	this.unselectCurrentTabLink = unselectCurrentTabLink;
	this.onSelectTabLink = null;
	this.launchUrl = launchUrl;
	this.enable = enable;
	this.disable = disable;
	this.isTabLinkUrl = isTabLinkUrl;

	this.tabs = new Object;
	this.tabLinks = new Object;
	this.hasVerticalSplitter = hasVerticalSplitter;
	this.currentTab = null;
	this.currentTabLink = null;
	this.tabCount = 0;
	this.tabCaptionCount = 0;
	this.isDrawn = false;
	this.tabsAnimate = true;
	this.timerId = null;
	this.slideTabIndex = 0;
	this.tabCaptionHeightCurrent = 0;
	this.tabCaptionHeight = 0;
	this.slideTimerIncrement = 50;
	this.slideIncrement = 60;
	this.isOpen = false;
	this.defaultWidth = defaultWidth;
	this.openWidth = defaultWidth;
	this.frameset = frameset;
	this.contentWindow = null;
	this.isVerticalSplitterMoved = false;
	this.captionClassName = "tabBarCaption";
	this.selectedCaptionClassName = "tabBarCaption";
	this.hoverCaptionClassName = "tabBarCaption";
	this.openWhenEnabled = false;
	this.css = css;
	this.captionLeftImage = captionLeftImage;
	this.captionCenterImage = captionCenterImage;
	this.captionRightImage = captionRightImage;
	this.captionImageHeight = captionImageHeight;
	this.captionLeftImageWidth = captionLeftImageWidth;
	this.captionRightImageWidth = captionRightImageWidth;
	this.firstCaptionImageSuffix = (typeof(firstCaptionImageSuffix) != "undefined") ? firstCaptionImageSuffix : "";
	this.vsOpenWidth=26;
	this.vsClosedWidth=26;
	this.hideTabImages=hideTabImages;

	inCourse = (typeof(parent.crsTitle) != "undefined");
	isCustom=(typeof(coursewareHandler) != "undefined" && coursewareHandler.isCustom)
	isDummies=(typeof(coursewareHandler) != "undefined" && coursewareHandler.isDummies)
	if (isCustom || !inCourse || isDummies)
	{
		this.tabCaptionHeightCurrent = 32;
		this.tabCaptionHeight = 22;
		this.vsClosedWidth=8;
		this.vsOpenWidth=8;
		this.isOpen=true;
	}

	function addTab(src,caption,description,isVisible,allowScrolling)
	{
		if (this.isDrawn)
		{
			alert("Tabs cannot be added once the TabBar is drawn.");
			return;
		}

		var tabIndex = ++this.tabCount;
		this.tabs[tabIndex] = new Tab(tabIndex,src,caption,description,this,++this.tabCaptionCount,allowScrolling);
		this.tabs[tabIndex].visible = isVisible;
		if (this.currentTab == null)
			this.currentTab = this.tabs[tabIndex];
	}

	function addPanel(src,height,isVisible,allowScrolling)
	{
		if (this.isDrawn)
		{
			alert("Panels cannot be added once the TabBar is drawn.");
			return;
		}

		var tabIndex = ++this.tabCount;
		this.tabs[tabIndex] = new Tab(tabIndex,src,"",null,this,0,allowScrolling);
		this.tabs[tabIndex].visible = isVisible;
	  this.tabs[tabIndex].panelHeight = height;
	}

	function addTabLink(tabLink)
	{
	  this.tabLinks[tabLink.name] = tabLink;
	}

	// Hide a tab given its 1-based index.
	function hideTab(tabIndex)
	{
		this.tabs[tabIndex].visible = false;
		for (var index = 1; index <= this.tabCount; index++)
		{
			if (this.tabs[index].visible)
				break;
		}

		if (index > this.tabCount)
		{
			alert("You cannot hide the last visible tab.");
			this.tabs[tabIndex].visible = true;
			return;
		}

		this.refresh();
	}

	// Show a tab given its 1-based index.
	function showTab(tabIndex)
	{
		this.tabs[tabIndex].visible = true;
		this.refresh();
	}


	// document.write out the html for the frameset of the TabBar.
	function draw()
	{
		if (this.isDrawn)
		{
			alert("TabBar has already been drawn to the page.");
			return;
		}

		var html = "";
		var rows = this.getFramesetRows();

		html += "<frameset id=\"TabBar\" onload=\"onTabBarLoad();\"";
		html +=	" rows=\"" + rows + "\"";
		html +=	" border=0 framespacing=0>";
		for (var tabIndex in this.tabs)
		{
			var tab = this.tabs[tabIndex];
			var scrolling = tab.allowScrolling ? "auto" : "no";

	    if (!tab.isPanel())
	      html += "<frame marginheight=0 marginwidth=0 src=\"" + rootDir + "/shared/tabbies/tabbarcaption.htm\"" +
	        " scrolling=\"no\"" +
	        " name=\"" + tab.name() + "\"" +
	        " id=\"" + tab.name() + "\"" +
	        " noresize frameborder=\"no\">";
		html += "<frame marginheight=0 marginwidth=0 src=\"" + tab.src + "\"" +
				" scrolling=\"" + scrolling + "\"" +
				" name=\"" + tab.contentFrameName() + "\"" +
				" id=\"" + tab.name() + "Content\"" +
				" noresize frameborder=\"no\">";
		}

		html += "</frameset>";

		document.write(html);

	  var index = 0;
		for (var tabIndex in this.tabs)
		{
			var tab = this.tabs[tabIndex];
	    if (!tab.isPanel())
	      index++;
	    tab.contentWindow = window.frames[index];
	    index++;
	  }
	}

	// Select a tab given the Tab object.
	function selectTab(tab,animateYn)
	{
		var tabIndex = tab.tabIndex;

		this.selectTabWithIndex(tabIndex,animateYn);
	}

	// Select a tab given the tab's 1-based index.
	function selectTabWithIndex(tabIndex,animateYn)
	{
		var newTab = this.tabs[tabIndex];
	  if (newTab.isPanel())
	    return;

		if (typeof(animateYn) == "undefined")
			animateYn = false;

		if (animateYn && !this.tabsAnimate)
			animateYn = false;

		if (this.currentTab != null && this.currentTab.tabIndex == tabIndex)
			return;

	  if (this.currentTab != null)
			this.currentTab.select(false);
		newTab.select(true);

		if (!newTab.visible)
			newTab.visible = true;

		if (animateYn)
			this.doSlide(tabIndex);
		else
		{
			this.currentTab = newTab;
			this.refresh();
		}
	}

	function doSlide(slideTabIndex)
	{
		if (this.slideTabIndex != 0 || this.tabs[slideTabIndex].isPanel())
			return;

		if (slideTabIndex == this.currentTab.tabIndex)
			return;
		this.slideIncrement = Math.floor(this.currentTab.contentHeight() / 7);

		var frameset = document.getElementById("TabBar");
//    alert(frameset.rows);
//		alert('sliding slideIncrement:'+this.slideIncrement+' contentHeight:'+this.currentTab.contentHeight());

		this.slideTabIndex = slideTabIndex;
		this.timerId = setInterval(this.slide,this.slideTimerIncrement);
	}

	function slide()
	{
		var frameset = document.getElementById("TabBar");
		var currentTabIndex = tabBar.currentTab.tabIndex;
		var currentTabHeight = tabBar.currentTab.contentHeight();
		var newRows = "";

		if (currentTabHeight <= tabBar.slideIncrement)
		{
			clearInterval(tabBar.timerId);
			tabBar.currentTab = tabBar.tabs[tabBar.slideTabIndex];
			tabBar.slideTabIndex = 0;
			tabBar.refresh();
			return;
		}

		for (var tabIndex=1; tabIndex <= tabBar.tabCount; tabIndex++)
		{
			if (newRows != "")
				newRows += ",";

	    var tab = tabBar.tabs[tabIndex];

	    if (!tab.isPanel())
	    {
	      // Frame for Caption
	      if (tab.visible)
	        newRows += ((tabIndex == tabBar.slideTabIndex || tabIndex == currentTabIndex) ? tabBar.tabCaptionHeightCurrent : tabBar.tabCaptionHeight) + ",";
	      else
	        newRows += "0,";
	    }

			// Frame for Tab Content
			if (tabIndex == currentTabIndex)
				newRows += currentTabHeight - tabBar.slideIncrement;
			else if (tabIndex == tabBar.slideTabIndex)
				newRows += "*";
			else if (tab.isPanel())
	      newRows += tab.contentHeight();
	    else
				newRows += "0";
		}
		frameset.rows = newRows;
	}

	function close()
	{
		if (!this.isOpen)
			return;

		if (this.hasVerticalSplitter)
		{
			this.frameset.cols = "0," + this.vsClosedWidth +",*";
			this.hideTabImages("closed");
		}
		else
			this.frameset.cols = "0,*";

		this.isOpen = false;
		if (typeof(this.contentWindow.onSlideyClose) == "function")
			this.contentWindow.onSlideyClose();
	}

	function open()
	{
		if (this.hasVerticalSplitter)
		{
			this.frameset.cols = this.openWidth + "," + this.vsOpenWidth + ",*";
			this.hideTabImages("open");
		}
		else
			this.frameset.cols = this.openWidth + ",*";

		this.isOpen = true;
		if (typeof(this.contentWindow.onSlideyOpen) == "function")
	    this.contentWindow.onSlideyOpen();
	}

	function hideTabImages(state)
	{
		tabImg=parent.VerticalSplitter.document.getElementById("tabImages");

		if (tabImg==null)
			return;

		if(state=="closed")
		{
			if (this.verticalSplitter.isEnabled) tabImg.style.display="inline";
		}
	}
	function refresh()
	{
		if (!this.currentTab.visible)
		{
	    var startTab = startTabIndex;
	    var found = false;

			if (this.currentTab.tabIndex != this.tabCount)
	      startTabIndex = this.currentTab.tabIndex+1;

	    while (true)
	    {
	      for (var tabIndex=startTabIndex; tabIndex <= this.tabCount; tabIndex++)
	      {
	        if (this.tabs[tabIndex].visible && !this.tabs[tabIndex].isPanel())
	        {
	          this.currentTab = this.tabs[tabIndex];
	          found = true;
	          break;
	        }
	      }
	      if (found || startTabIndex == 1)
	        break;
	    }
	    if (!found)
	    {
	      alert("Application error: All non-panel tabs are hidden.");
	      return "";
	    }
		}

		var rows = this.getFramesetRows();
		if (rows != "")
		{
			var frameset = document.getElementById("TabBar");
			frameset.rows = rows;
		}

		for (var i=0; i < self.frames.length; i++)
		{
			self.frames[i].scrollTo(0,0);
		}
	}

	function getFramesetRows()
	{
		var rows = "";
		var currentTabIndex = 0;

		if (this.currentTab)
	    currentTabIndex = this.currentTab.tabIndex;

	  var isAllPanels = true;
		for (var tabIndex=1; tabIndex <= this.tabCount; tabIndex++)
	  {
	    var tab = this.tabs[tabIndex];
	    if (!tab.isPanel())
	    {
	      isAllPanels = false;
	      break;
	    }
	  }

		for (var tabIndex=1; tabIndex <= this.tabCount; tabIndex++)
		{
	    var tab = this.tabs[tabIndex];

			if (rows != "")
				rows += ",";

	    if (tab.isPanel())
	    {
	      if (isAllPanels && tabIndex == 1)
	        rows += "*"
	      else
	        rows += tab.contentHeight();
	    }
	    else if (tabIndex == currentTabIndex)
	      rows += this.tabCaptionHeightCurrent + ",*";
	    else
	      rows += ((tab.visible) ? this.tabCaptionHeight : "0") + ",0";
		}
		return rows;
	}

	// Get a tab given the window the tab's caption is in.
	function getTab(wnd)
	{
		for (var tabIndex in this.tabs)
		{
			var tab = this.tabs[tabIndex];
			if (wnd.name == tab.name())
			{
				tab.captionWindow = wnd;
				return tab;
			}
		}
		return null;
	}

	// Get a tab given the window the tab's caption is in.
	function getTabWithContentWindow(wnd)
	{
		for (var tabIndex in this.tabs)
		{
			var tab = this.tabs[tabIndex];
			if (wnd.name == tab.contentWindow.name)
				return tab;
		}
		return null;
	}

	function getContentHeight(tabIndex)
	{
	  if (this.tabs[tabIndex].isPanel())
	    return this.tabs[tabIndex].contentHeight();

		// We have to go through this mumbo-jumbo because, if the tab contains a document from another domain, we won't be
		// able to access it's document.body.clientHeight property.

		var rows = document.getElementById("TabBar").rows + ",";
		var rexp = "^";

		for (var idx=1; idx < tabIndex; idx++)
	  {
	    rexp += "[^\\,]+\\,";
	    if (!this.tabs[idx].isPanel())
	      rexp += "[^\\,]+\\,";
	  }
		rexp += "[^\\,]+\\,([^\\,]+)\\,";

		var re = new RegExp(rexp);
		var foundArray = re.exec(rows);

		var height = foundArray[1];
		if (height == "*")
	  {
	    var totalHeight = 0;
	    for (var idx=1; idx <= this.tabCount; idx++)
	    {
	      var tab = this.tabs[idx];
	      if (tab.visible)
	      {
	        if (tab.isPanel())
	          totalHeight += tab.contentHeight();
	        else
	          totalHeight += this.tabCaptionHeight;
	      }
	    }
			height = document.body.clientHeight - totalHeight;
	  }
		else
			height = parseInt(height);

		return height;
	}

	function getVerticalSplitterFrame()
	{
		return this.frameset.children(1);
	}

	function getVerticalSplitterWindow()
	{
		return this.getVerticalSplitterWindow().contentWindow;
	}

	function verticalSplitterSlide()
	{
		if (this.inSkillAssessment)
		{
			alert(resStr.mustCompleteSa);
			return;
		}
		this.timerId = setInterval(slideVertical,10);
	}

	function slideVertical()
	{
		var navBarWidth = document.body.clientWidth;

		var slideIncrement = 60;

		if (tabBar.isOpen)
		{
			// We're closing the navbar.
			if (navBarWidth <= slideIncrement)
			{
				clearInterval(tabBar.timerId);
				tabBar.close();
				return;
			}
			navBarWidth -= slideIncrement;
			vsWidth=this.vsCloseWidth;
		}
		else
		{
			// We're opening the navbar.
			if (navBarWidth >= tabBar.openWidth - slideIncrement)
			{
				clearInterval(tabBar.timerId);
				tabBar.open();
				return;
			}
			navBarWidth += slideIncrement;
			vsWidth=this.vsOpenWidth;
		}
		if (this.hasVerticalSplitter)
			tabBar.frameset.cols = navBarWidth + "," + vsWidth + ",*";
		else
			tabBar.frameset.cols = navBarWidth + ",*";
	}

	function positionVerticalSplitter(x)
	{
		if (this.inSkillAssessment)
		{
			alert(resStr.mustCompleteSa);
			return;
		}

		var navBarWidth = document.body.clientWidth;

		this.isVerticalSplitterMoved = true;
		if (this.hasVerticalSplitter)
			this.frameset.cols = (navBarWidth + x) + "," + this.vsOpenWidth +",*";
		else
			this.frameset.cols = (navBarWidth + x) + ",*";

		if (navBarWidth + x <= 0)
		{
			this.isOpen = false;
			this.openWidth = this.defaultWidth;
		}
		else
		{
			this.isOpen = true;
			this.openWidth = navBarWidth + x;
		}
	}

	function getTabLink(tabLinkName)
	{
	  var tab = this.getTabWithTabLink(tabLinkName);
	  if (tab == null)
	    return null;
	  else
	  {
			var tabLinks = tab.contentWindow.tabLinks;
	    return tabLinks.get(tabLinkName);
	  }
	}

	function getTabLinkWithUrl(url)
	{
	  var tab = this.getTabWithTabLinkUrl(url);
	  if (tab == null)
	    return null;
	  else
	  {
			var tabLinks = tab.contentWindow.tabLinks;
	    return tabLinks.getTabLinkWithUrl(url);
	  }
	}

	function getTabWithTabLink(tabLinkName)
	{
		for (var tabIndex=1; tabIndex <= this.tabCount; tabIndex++)
		{
	    var tab = this.tabs[tabIndex]
			var tabLinks = tab.contentWindow.tabLinks;
	    if (typeof(tabLinks) != "undefined")
	    {
	      var tabLink = tabLinks.get(tabLinkName);
	      if (typeof(tabLink) != "undefined")
	        return tab;
	    }
	  }
	  return null;
	}

	function getTabWithTabLinkUrl(url)
	{
		for (var tabIndex=1; tabIndex <= this.tabCount; tabIndex++)
		{
	    var tab = this.tabs[tabIndex]
			var tabLinks = tab.contentWindow.tabLinks;
	    if (typeof(tabLinks) != "undefined")
	    {
	      var tabLink = tabLinks.getTabLinkWithUrl(url);
	      if (tabLink != null)
	        return tab;
	    }
	  }
	  return null;
	}

	function selectTabLink(tabLink)
	{
		if (tabLink.pointWhenClicked)
			this.pointToTabLink(tabLink);

		var returnVal;	// Indicates whether to process the url or not.
	  if (typeof(this.onSelectTabLink) == "function")
	    returnVal = this.onSelectTabLink(tabLink);
	  else if (typeof(this.onSelectTabLink) == "string")
	    returnVal = eval(this.onSelectTabLink + "(tabLink)");

		if (returnVal)
		{
			var url = tabLink.url;
			this.launchUrl(tabLink.url);
		}
	}

	function launchUrl(url)
	{
		this.contentWindow.location.href=url;
	}

	function pointToTabLink(tabLink)
	{
		this.unselectCurrentTabLink();

		if (tabLink != null)
		{
			tabLink.select();
			this.currentTabLink = tabLink;
		}
	}

	function unselectCurrentTabLink()
	{
	  try
	  {
	    if (this.currentTabLink != null)
			{
	      this.currentTabLink.unselect();
				this.currentTabLink = null;
			}
	  }
	  catch (e)
	  {
	  }
	}

	function disable()
	{
		this.verticalSplitter.enable(false);
		if (this.isOpen)
		{
			this.openWhenEnabled = true;
			this.close();
		}
	}

	function enable()
	{
		this.verticalSplitter.enable(true);
		if (this.openWhenEnabled)
			this.open();
		this.openWhenEnabled = false;
	}

	function isTabLinkUrl(url)
	{
		for (var tabIndex=1; tabIndex <= this.tabCount; tabIndex++)
		{
			var tabLinks = this.tabs[tabIndex].getTabLinks();
	    if (tabLinks != null)
	    {
	      if (tabLinks.hasTabLinkWithUrl(url))
	        return true;
	    }
		}
		return false;
	}
}


