
//====================================================================================
//== EEM6Tabsheet.js
//====================================================================================
//== 
//====================================================================================

//====================================================================================
//== TabPageObj object
//====================================================================================
function TabPageObj(ID, sCaption){
	//== TabID											What the calling code wants to refer to this as
	//==													can be an integer or possibly a string
	this.TabID											= ID;
	//== ArrayIndex										integer index in the TabBook.TabPages[] for this button
	this.ArrayIndex										= -1;
	//== Visible										is the tab "open" and visible (not necessarily displayed currently though)
	this.Visible										= false;
	//== Active											is the tab active (selected)
	this.Active											= false;
	//== Displayed										is this displayed?  (do we have room for it?)
	this.Displayed										= false;			
	//== PageFrame										The frame for the actual tab page
	this.PageFrame										= null;
	//== TabCaptionText								The caption on the tab button (in text form without any <BR>
	this.TabCaptionText								= null;
	//== TabCaptionHTML								The HTML for the tab caption
	this.TabCaptionHTML								= null;
	//== elementTD										Points to the <TD> for the tab button
	this.elementTD										= null;
	//== elementA											Points to the <A> for the tab button
	this.elementA											= null;
	//== CanTable										can we create a table for this tab (should we show the "Table" button
	this.CanTable										= false;
	//== eventTable										event to fire when the user selects the "Table" link
	this.eventTable										= null;
	//== CanDownload									can we download this tab (should we show the "Download" button
	this.CanDownload									= false;
	//== eventDownload									event to fire when the user selects the "Download" link 
	this.eventDownload									= null;
	//== CanLaunch										Can we launch this tab into a seperate window?
	this.CanLaunch										= false;
	//== HideOnClose									Do we just hide the tab on close (True)
	//==													or do we really destroy the tab page (False)
	this.HideOnClose									= false;
	//== eventClose										event to fire when the tab is hidden/closed	
	this.eventClose										= null;
	//== Tag											a string to hold general info
	this.Tag											= "";
	//== TabWindow										the window object for the tab page
	this.TabWindow										= function(){
		if (NotNull(this.PageFrame)){
			return this.PageFrame.contentWindow;
		}else{
			return null;
		}
	}
	//== EventHandler									executes (or tries to) some event code
	this.EventHandler									= function(sName, Func){
		if (NotNull(Func)){
			DebugText(sName + ": executing function");
			return Func();
		}
	}
	//== _CalcTabCaption							Calculate the Text and HTML versions of the caption
	this._CalcTabCaption							= function(sCaption){
		//== Step 1: for the pure text, replace any <BR>'s with spaces
		this.TabCaptionText							= sCaption.split("<BR>").join(" ");
		//== Step 2: for the HTML, try to get two lines with a <BR> in the middle
		this.TabCaptionHTML							= sCaption.split("<BR>", 2).join("<BR>");
	}
	this._CalcTabCaption(sCaption);
}

//====================================================================================
//== TabBookObj object
//====================================================================================
function TabBookObj(name, win){
	DebugText("Creating tabsheet '" + name + "'");
	//== ObjectName										The name for this object that other JavaScript can refer to it as
	this.ObjectName 									= name;
	//== HostWindow										The host window for the frameset and frames
	this.HostWindow										= win;
	//== Frameset										The frameset that contains the tab button frame as well as 
	//==													all of the tab page frames
	//==												Assume there is only one frameset in this.HostWindow
	this.Frameset										= this.HostWindow.document.getElementsByTagName("frameset")[0];
	//== FrameButtons									The frame that the tab page buttons go in
	//==												For now, assume this is the 2nd frame
	//==													the 1st frame (.frames[0]) is the frame to show when no tabs are shown
	this.FrameButtons									= this.HostWindow.frames["fraTabButtons"];
	//== FramePrefix									The prefix for the "id" for the frames we add
	this.FramePrefix									= "fraTabButton";
	//== TabActiveID									The active tab's array index
	this.TabActiveID									= null;
	//== TabsDIV										The <DIV> element where the tab buttons live
	this.TabsDIV										= null;
	//== TabsTR											The Table Row where we add cells for new tab page buttons
	this.TabsTR											= null;
	//== LaunchAnchor									The <A> element for the "Launch this tab"
	this.LaunchAnchor									= null;
	this.TableAnchor									= null;
	this.DownloadAnchor									= null;
	this.ScrollLeftA									= null;
	this.ScrollRightA									= null;
	this.OldTabDIVWidth									= -1;
	this.OldTabDIVHeight								= -1;
	this.LockResize										= false;
	this.LockUpdate										= false;

	//== TabPages										storage for the TabPageObj objects
	this.TabPages 										= [];
	//== NextDynamicID									the next tab ID to hand out
	this.NextDynamicID									= TAB_DYNAMIC_BEGIN;
	//== elementID										unique ID for the elements we add
	this.elementID										= 0;
	this.DrawingButtons									= false;
	this.FirstDisplayed									= null;
	this.LastDisplayed									= null;
	this.NextToDisplay									= null;
	this.PrevToDisplay									= null;
	this.FirstVisible									= null;
	this.LastVisible									= null;
	this.CountVisible									= 0;
	this.CountDisplayed									= 0;
	//== TabIDCheck										Checks to see if it is a valid ID (do we have a tab with that TabID?)
	this.TabIDCheck										= function(TabID){
		return NotNull(this.TabFromID(TabID));
	}
	//== TabIndexCheck									Checks to see if TabIndex is a valid array index for this.TabPages array
	this.TabIndexCheck									= function(TabIndex){
		var bRet 										= false;
		if (IsDefined(TabIndex)){
			bRet 										= IsBetween(TabIndex, 0, this.TabPages.length);
		}
		return bRet;
	}
	//== TabFromID										Given what the calling code calls a tab (ID=integer or string)
	//==													return the actual tabpage object 
	this.TabFromID 										= function(TabID){
		for (var iLoop = 0; iLoop < this.TabPages.length; iLoop++){
			if (this.TabPages[iLoop].TabID == TabID){
				return (this.TabPages[iLoop]);
			}
		}
		DebugText("Could not find tab for TabID=" + TabID);
		return null;
	}
	this.TabFromDocument								= function(d){
		var oTab										= null;
		var oFrame;
		try{
			oFrame										= d.parentWindow.frameElement;
		}catch(err){
			oFrame										= null;
		}
		if (NotNull(oFrame)){
			for (var iLoop=0; iLoop < this.TabPages.length; iLoop++){
				if (this.TabPages[iLoop].PageFrame == oFrame){
					oTab								= this.TabPages[iLoop];
					break;
				}
			}
		}
		return oTab;
	}
	this.TabExists										= function(TabID){
		return (this.TabFromID(TabID) != null);
	}
	this.TabFromIndex									= function(ArrayIndex){
		if (this.TabIndexCheck(ArrayIndex)){
			return this.TabPages[ArrayIndex];
		}else{
			return null;
		}
	}
	this.TabFromTag										= function(Tag){
		for (var iLoop=0; iLoop < this.TabPages.length; iLoop++){
			if (this.TabPages[iLoop].Tag == Tag){
				return this.TabPages[iLoop];
			}
		}
		return null;
	}
	//== TabID											Returns the .TabID for a TabPage object, or null if oTab is null
	this.TabID											= function(oTab){
		if (IsDefined(oTab)){
			return oTab.TabID;
		}else{
			return null;
		}
	}
	//== TabIndex										Returns the .ArrayIndex for a TabPage object, or null if oTab is null
	this.TabIndex 										= function(oTab){
		if (IsDefined(oTab)){
			return oTab.ArrayIndex;
		}else{
			return null;
		}
	}
	//== TabFrame										Returns the FRAME object for a particular TabID
	this.TabFrame										= function(TabID){
		var oFrame										= null;
		if (this.TabIDCheck(TabID)){
			oFrame										= this.TabFromID(TabID).PageFrame;
			DebugText("TabFrame for TabID " + TabID + " is " + oFrame.id);
		}else{
			DebugText("Error accessing Frame for TabID=" + TabID);
		}
		return oFrame;
	}
	//== TabWindow										returns the WINDOW object for a particular TabID
	this.TabWindow										= function(TabID){
		var oWin										= null;
		var oFrame										= this.TabFrame(TabID);
		if (NotNull(oFrame)){
			oWin										= oFrame.contentWindow;
			DebugText("TabWindow for TabID " + TabID + " is " + oWin);
		}
		return oWin;
	}
	//== TabDocument									returns the DOCUMENT object for a particular TabID
	this.TabDocument									= function(TabID){
		var oDoc										= null;
		try{
			oDoc										= this.TabWindow(TabID).document;
			DebugText("TabDocument (window) for TabID " + TabID + " is " + oDoc.URL);
		}catch(err){
			DebugError("Error accessing TabDocument for Tab #" + TabID, err);
//			try{
//				oDoc									= this.TabFrame(TabID).document;
//				DebugText("TabDocument (frame) for TabID " + TabID + " is " + oDoc.URL);
//			}catch(err){
//				//
//			}
		}
		return oDoc;
	}
	this.NextTabID										= function(){
		return this.NextDynamicID++;
	}
	this.TabSetSource									= function(TabID, src){
		var oTab										= this.TabFromID(TabID);
		if (NotNull(oTab)){
			oTab.PageFrame.src							= src;
			DebugText("Changed source for tab '" + oTab.TabCaptionText + "' to " + oTab.PageFrame.src);
		}
	}
	this.TabSetCaption									= function(TabID, sCaption){
		var oTab										= this.TabFromID(TabID);
		if (NotNull(oTab)){
			oTab._CalcTabCaption(sCaption);
			oTab.elementA.innerHTML 			= oTab.TabCaptionHTML;
		}
	}
	//== TabActive										returns the active tab, or null if there is not one
	this.TabActive 										= function(){
		return this.TabFromID(this.TabActiveID);
	}
	//== UpdateStatus									update the tab's display based on its status
	this.UpdateStatus									= function(oTab){
		switch (true){
			case (oTab.Active && oTab.Displayed):
				//== Tab is active and displayed on screen
				oTab.elementTD.className 			= "TabSelected";
				oTab.elementTD.style.visibility 	= "inherit";
				break;
			case (oTab.Visible && oTab.Displayed):
				//== Tab is visible and displayed on screen
				oTab.elementTD.className 			= "TabUnselected";
				oTab.elementTD.style.visibility 	= "inherit";
				break;
			case (!oTab.Visible):
				//== Tab is "closed", so hide both the tab and the page
				oTab.elementTD.className			= "TabClosed";
				oTab.elementTD.style.visibility 	= "hidden";
				break;
			default:
				//== Tab is visible (and maybe active), but not displayed on screen
				oTab.elementTD.className			= "TabHidden";
				oTab.elementTD.style.visibility		= "hidden";
				break;
		}
		if (oTab.Active){
			if (oTab.TabID != this.TabActiveID){
				var oTabOld								= this.TabActive();
				if (NotNull(oTabOld)){
					oTabOld.Active						= false;
					this.UpdateStatus(oTabOld);
				}
				this.TabActiveID						= oTab.TabID;
				if (oTab.CanLaunch){
					this.LaunchAnchor.style.display		= "inline";
				}else{
					this.LaunchAnchor.style.display		= "none";
				}
				if (oTab.CanTable){
					this.TableAnchor.style.display		= "inline";
				}else{
					this.TableAnchor.style.display		= "none";
				}
				if (oTab.CanDownload){
					this.DownloadAnchor.style.display	= "inline";
				}else{
					this.DownloadAnchor.style.display	= "none";
				}
				DebugText("Set active tab to " + oTab.TabCaptionText);
			}
		}
	}
	this._DoCalcs										= function(){
		var oTab										= null;
		this.FirstVisible								= null;
		this.LastVisible								= null;
		this.FirstDisplayed								= null;
		this.LastDisplayed								= null;
		this.NextToDisplay								= null;
		this.PrevToDisplay								= null;
		this.CountDisplayed								= 0;
		this.CountVisible								= 0;
		for (var iLoop=0; iLoop < this.TabPages.length; iLoop++){
			oTab										= this.TabPages[iLoop];
			if (oTab.Visible && !oTab.Displayed){
				if (this.FirstDisplayed == null){
					//== we have not come across a displayed on yet
					//==	we are to the left of the displayed tabs
					this.PrevToDisplay					= iLoop;
				}else{
					//== we have come across a displayed one
					//==	we must now be to the right of the displayed tabs
					if (this.NextToDisplay == null){
						//== This is the first one to the right of the displayed tabs
						this.NextToDisplay					= iLoop;
					}
				}
			}
			if (oTab.Visible){
				this.CountVisible++;
				if (this.FirstVisible == null){
					this.FirstVisible					= iLoop;
				}
				this.LastVisible						= iLoop;
			}
			if (oTab.Displayed){
				this.CountDisplayed++;
				if (this.FirstDisplayed == null){
					this.FirstDisplayed					= iLoop;
				}
				this.LastDisplayed						= iLoop;
			}
			if (oTab.Active){
				this.TabActiveID						= this.TabPages[iLoop].TabID;
			}
		}
		if (this.TabActiveID == null){
			this.TabActiveID							= this.TabPages[this.FirstVisible];
		}
	}
	this._TabsTooBig									= function(){
		return (this.TabsTR.clientWidth > this.FrameButtons.frameElement.width);
	}
	this._RemoveTabs									= function(iStart, iInc, iStop){
		DebugText("RemoveTabs: " + iStart + ", " + iInc + ", " + iStop);
		var oTab;
		for (var iLoop=iStart; iLoop != iStop; iLoop += iInc){
			oTab										= this.TabPages[iLoop];
			if (NotNull(oTab)){
				if (oTab.Displayed){
					oTab.Displayed						= false;
					this.UpdateStatus(oTab);
					if (! this._TabsTooBig()){
						break;
					}
				}
			}else{
				break;
			}
		}
		return (! this._TabsTooBig());
	}
	this._FixTabButtons									= function(){	
		var oTab;
		var iIndex;
		var iLoop;
		this._DoCalcs();
		if (this._TabsTooBig()){
			//== We are displaying too many buttons, need to remove a few
			oTab										= this.TabFromID(this.TabActiveID);
			if (oTab == null){
				iIndex									= null;
			}else{
				iIndex									= oTab.ArrayIndex;
			}
			if (this._RemoveTabs(this.TabPages.length-1, -1, iIndex)){
				return true;
			}
			if (this._RemoveTabs(0, 1, iIndex)){
				return true;
			}
			return false;
		}else{
			//== Maybe we could fit a few more buttons on the screen?
			for (iLoop=this.LastDisplayed+1; iLoop<=this.LastVisible; iLoop++){
				oTab									= this.TabPages[iLoop];
				if (oTab.Visible){
					oTab.Displayed						= true;
					this.UpdateStatus(oTab);
					if (this._TabsTooBig()){
						oTab.Displayed					= false;
						this.UpdateStatus(oTab);
						break;
					}
				}
			}
			for (iLoop=this.FirstDisplayed-1; iLoop>=this.FirstVisible; iLoop--){
				oTab									= this.TabPages[iLoop];
				if (oTab.Visible){
					oTab.Displayed						= true;
					this.UpdateStatus(oTab);
					if (this._TabsTooBig()){
						oTab.Displayed					= false;
						this.UpdateStatus(oTab);
						break;
					}
				}
			}
			return true;
		}
	}
	this._FixScrollButtons								= function(){
		this._DoCalcs();
		var sText										= "Tabsheet Scrollbars:";
		if (this.PrevToDisplay != null){
			this.ScrollLeftA.disabled					= false;
			this.ScrollLeftA.childNodes[0].src			= GIF("tabScrollLeft");
			sText										= sText + " left: ON";
		}else{
			this.ScrollLeftA.disabled					= true;
			this.ScrollLeftA.childNodes[0].src			= GIF("tabScrollLeftDisabled");
			sText										= sText + " left: off";
		}
		if (this.NextToDisplay != null){
			this.ScrollRightA.disabled					= false;
			this.ScrollRightA.childNodes[0].src			= GIF("tabScrollRight");
			sText										= sText + ", right: ON";
		}else{
			this.ScrollRightA.disabled					= true;
			this.ScrollRightA.childNodes[0].src			= GIF("tabScrollRightDisabled");
			sText										= sText + ", right: off";
		}
		DebugText(sText);
	}
	this._DrawTabButtons								= function(){
		if (this.DrawingButtons){
			//== Keep from recursively calling ourselves
		}else{
			//== Both of the following functions should do their own _DoCalcs() within them
			//==	to make sure they have an accurate reading of what tabs are in what state
			DebugText("Determine which buttons should be shown, tab scrollbuttons");
			this.DrawingButtons								= true;
			try{
				this._FixTabButtons();
				this._FixScrollButtons();
			}catch(err){
				DebugError("DrawTabButtons", err);
			}
			this.DrawingButtons								= false;
		}
	}
	//== TabScroll										scrolls through tabs when there are too many to display
	this.TabScroll										= function(iDirection){
		var oTab;
		this._DoCalcs();
		this.LockResize									= true;
		if (iDirection >= 0){
			//== Scroll to the right
			DebugText("Scroll tab to the right");
			if (this.NextToDisplay != null){
				DebugText("NextToDisplay=" + this.NextToDisplay);
				//== We think there is one to the right we can show
				oTab									= this.TabPages[this.NextToDisplay];
				oTab.Displayed							= true;
				this.UpdateStatus(oTab);
				if (this._TabsTooBig()){
					//== by scrolling to the right, we are now too crowded
					//== remove tabs starting at the leftmost displayed
					this._RemoveTabs(this.FirstDisplayed, 1, this.NextToDisplay);
				}
			}
		}else{
			//== Scroll to the left
			DebugText("Scroll tab to the left");
			if (this.PrevToDisplay != null){
				DebugText("PrevToDisplay=" + this.PrevToDisplay);
				//== We think there is one to the left we can show
				oTab									= this.TabPages[this.PrevToDisplay];
				oTab.Displayed							= true;
				this.UpdateStatus(oTab);
				if (this._TabsTooBig()){
					//== by scrolling to the left, we are now too crowded
					//== remove tabs starting at the rightmost displayed
					this._RemoveTabs(this.LastDisplayed, -1, this.PrevToDisplay);
				}
			}
		}
		this._FixScrollButtons();
		this.LockResize									= false;
	}
	//== TabSelect										selects the tab referred to by TabID
	this.TabSelect										= function(TabID){
		var oTab										= this.TabFromID(TabID);
		if (NotNull(oTab)){
			DebugText("Showing tab '" + oTab.TabCaptionText + "'");
			oTab.Active									= true;
			oTab.Displayed								= true;
			oTab.Visible								= true;
			this.UpdateStatus(oTab);
		}
		this.Draw();
	}
	//== TabShow										display a tab referred to by a TabID
	this.TabShow										= function(TabID){
		var oTab										= this.TabFromID(TabID);
		if (NotNull(oTab)){
			//== Select the tab, which kicks off drawing it
			this.TabSelect(oTab.TabID);
		}else{
			alert("No current tabs to show");
		}
	}
	//== TabShowAll										makes all tabs visible
	this.TabShowAll										= function(){
		var oTab;
		for (var iLoop = 0; iLoop < this.TabPages.length; iLoop++){
			oTab										= this.TabPages[iLoop];
			oTab.Displayed								= true;
			oTab.Visible								= true;
			this.UpdateStatus(oTab);
		}
		this.Draw();
	}
	//== TabCloseReplacement							finds the most logical tab to display when closing a tab
	this.TabCloseReplacement							= function(oTab){
		var oRet										= null;
		var iLoop;
		for (iLoop=oTab.ArrayIndex+1; iLoop < this.TabPages.length; iLoop++){
			if (this.TabPages[iLoop].Visible){
				return this.TabPages[iLoop];
			}
		}
		for (iLoop=oTab.ArrayIndex-1; iLoop >= 0; iLoop--){
			if (this.TabPages[iLoop].Visible){
				return this.TabPages[iLoop];
			}
		}
		return null;
	}
	//== TabClose										close (hide) the tab referred to by TabID
	this.TabClose 										= function(TabID){
		var oTab;
		if (TabID == -1){
			oTab										= this.TabActive();
		}else{
			oTab										= this.TabFromID(TabID);
		}
		if (NotNull(oTab)){
			//== Before we close/hide the tab, figure out where 
			//==	we are going afterwards (what tab to activate)
			var TabIDNew								= this.TabID(this.TabCloseReplacement(oTab));
			if (oTab.HideOnClose){
				this._TabHide(oTab);
			}else{
				this._TabDestroy(oTab);
			}
			//== Fire off any event handler for the tab
			oTab.EventHandler("eventClose", oTab.eventClose);
			//== Select the new tab
			if (NotNull(TabIDNew)){
				this.TabSelect(TabIDNew);
			}else{
				this.Draw();
			}
		}else{
			alert("No current tab to close");
		}
	}
	//== _TabHide										just hides the tab page
	this._TabHide										= function(oTab){
		DebugText("Hiding tab " + oTab.TabCaptionText);
		//== Mark this tab as invisible
		oTab.Visible								= false;
		oTab.Displayed								= false;
		oTab.Active									= false;
		this.UpdateStatus(oTab);
	}
	//== _TabDestroy									destroys the tab page
	this._TabDestroy									= function(oTab){
		DebugText("Destroying tab " + oTab.TabCaptionText);
		//== First, get rid of the <TD> element in the tab buttons <TR>
		try{
			//== Sometimes this causes an error, namely if the tab has never been shown
			this.TabsTR.deleteCell(oTab.elementTD.cellIndex);
		}catch(err){
			//
		}
		//== Now get rid of the frame
		oTest											= this.Frameset.removeChild(oTab.PageFrame);
		DebugText("...removed " + oTest.name);
		//== Remove the TabPageObj from the array
		this.TabPages.splice(oTab.ArrayIndex, 1);
		//== Recalculate array indexes so everyone knows where they are in the array
		this._RecalcIndexes(); 
	}
	this._RecalcIndexes									= function(){
		var oTab;
		for (var iLoop=0; iLoop < this.TabPages.length; iLoop++){
			oTab										= this.TabPages[iLoop];
			oTab.ArrayIndex								= iLoop;
		}
	}
	//== TabTable										creates a table out of the tab data
	this.TabTable										= function(TabID){
		var oTab										= this.TabFromID(TabID);
		oTab											= DefaultValue(oTab, this.TabActive());
		oTab.EventHandler("eventTable", oTab.eventTable);
	}
	//== TabDownload									downloads the tab's data
	this.TabDownload									= function(TabID){
		var oTab										= this.TabFromID(TabID);
		oTab											= DefaultValue(oTab, this.TabActive());
		oTab.EventHandler("eventDownload", oTab.eventDownload);
	}
	//== TabLaunch										launches the current tab into a separate browser window
	this.TabLaunch										= function(TabID){
		var oTab										= this.TabFromID(TabID);
		oTab											= DefaultValue(oTab, this.TabActive());
		if (NotNull(oTab)){
			DebugText("Launching tab " + oTab.TabCaptionText);
			try{
				var sParams								= "directories=no, top=20, left=20, height=400, width=650, menubar=no, toolbar=no, location=no, status=yes, resizable=yes";
				var oFrame								= this.TabFrame(oTab.TabID);
				EEM6().TabToLaunch						= oTab;
				var oWin								= EEM6().open("fsetTabLaunch.html", "_blank", sParams);
			}catch(err){
				DebugError("TabLaunch Error", err);
			}
		}else{
			alert("No current tab to launch");
		}
	}
	//== AddTab											Add a "TabPage" object to this "TabBook"
	this.AddTab 										= function(oTabPage){
		DebugText("Adding tab " + oTabPage.TabCaptionText);
		//== The document for the "Tab Button" frame
		var oDocButtons									= this.FrameButtons.document;
		//== Get the "internal ID", which is used as the array index
		var id											= this.TabPages.length;
		//== Add the "TabPage" object to our array
		this.TabPages[id]								= oTabPage;
		//== Now, take the "TabPage" and tell it where it is stored in the Tabsheet array
		oTabPage.ArrayIndex								= id;
		//== Add a tab to allow access to the tab page
		//==	this is really just a TD since the overall tab across the top
		//==	is nothing more than a single TR of a table
		//== FrameButtons.document.DIV_Tabs.TABLE_Tabs.TR_Tabs.TD_Button_<index>
		var oTD											= this.TabsTR.insertCell(this.TabsTR.cells.length-1);
		this.elementID++;
		oTD.id											= "TD_TabButton_" + this.elementID;
		oTD.className									= "Unselected";
		//== FrameButtons.document.DIV_Tabs.TABLE_Tabs.TR_Tabs.TD_Button_<index>.NOBR
		//==	Add a "No Break" to make sure the text displayed as the tab button stays on one line
		var oNOBR											= oTD.appendChild(oDocButtons.createElement("nobr"));
		//== FrameButtons.document.DIV_Tabs.TABLE_Tabs.TR_Tabs.TD_Button_<index>.NOBR.A
		//==	<A> to click on to select the tab page that goes with the tab button
		var oA											= oNOBR.appendChild(oDocButtons.createElement("a"));
		AnchorSetAction(oA, this.ObjectName + ".TabSelect(" + oTabPage.TabID + ")", "Select this tab");
		oTD.onclick												= oA.onclick;
		//== Store a pointer to the <TD> in the TabPage object
		oTabPage.elementTD								= oTD;
		oTabPage.elementA									= oA;
		//== FrameButtons.document.DIV_Tabs.TABLE_Tabs.TR_Tabs.TD_Button_<index>.NOBR.A.Text
		oA.innerHTML = oTabPage.TabCaptionHTML;
		//== Now, for the actual frame for the tab contents to be displayed in
		var oFrame										= this.HostWindow.document.createElement("<frame APPLICATION=yes>");
		oFrame.id										= this.FramePrefix + this.elementID;
		oFrame.name										= oFrame.id;
		//== Add the new tab page frame to the overall frameset
		oFrame											= this.Frameset.appendChild(oFrame);
		oTabPage.PageFrame 								= oFrame;
		//== Set the initial status to closed
		oTabPage.Active									= false;
		oTabPage.Visible								= false;
		oTabPage.Displayed								= false;
		this.UpdateStatus(oTabPage);
		//== Return the new tab page that they sent in for convenience
		//==	oTab = TabSheet.AddTab(new TabPage...);
		return oTabPage;
	}	
	//== eventTabsResized								fired when the DIV container for the tabs changes size
	this.eventTabsResized								= function(){
		if (!this.LockResize){
			DebugText("Tab button area resized: " + this.TabsDIV.clientWidth + ", " + this.TabsDIV.clientHeight);
			if (this.TabsDIV.clientWidth == this.OldTabDIVWidth){
				if (this.TabsDIV.clientHeight == this.OldTabDIVHeight){
					//== Nothing has really changed here
					DebugText("No resize needed");
					return true;
				}
			}
			this._DrawTabButtons();
			//== Now, keep track of what width/height we are at now so we can ignore the next
			//==	resize we get if we really don't change size
			this.OldTabDIVWidth								= this.TabsDIV.clientWidth;
			this.OldTabDIVHeight							= this.TabsDIV.clientHeight;
		}
		return true;
	}
	//== Draw											Draw this tabsheet and its pages
	this.Draw 											= function(){
		if (this.LockUpdate) {
			//== Do nothing
		}else{
			var sRows										= "";
			this._DoCalcs();
			for (var iLoop = 0; iLoop < this.TabPages.length; iLoop++){
				oTab										= this.TabPages[iLoop];
				if (oTab.Active){
					//== This is the tab we need to show the page for
					sRows									= sRows + ",*";
				}else{
					//== not the tab we are looking for
					sRows									= sRows + ",0";
				}
			}
			if (this.CountVisible > 0){
				//== Show the frame that has the tab buttons, as well as the tab page header
				this.FrameButtons.document.body.style.display	= "block";
				sRows										= "0,50" + sRows;
			}else{
				//== Hide the frame that has the tab buttons, there are no buttons visible
				//==	this effectively hides the entire tabsheet
				this.FrameButtons.document.body.style.display	= "none";
				sRows										= "*,0" + sRows;
			}
			this.Frameset.rows								= sRows;
			//== Figure out which buttons we can display
			//== 	do this after the buttons are displayed so we get an accurate reading
			//==	of how many buttons can fit
			this._DrawTabButtons();
		}
	}
	//== CreateMe										called initially to setup the tabsheet object (draw it)
	this.CreateMe 										= function(){
		this.elementID									= 0;
		//== FrameButtons.document
		var oDocButtons									= this.FrameButtons.document;
		//== FrameButtons.document.DIV_Tabs
		//== 	The DIV that contains the tabs (not the pages, just the tabs you click on)
		var oDIV										= oDocButtons.createElement("div");
		oDIV.id											= "DIV_Tabs";
		oDIV.className									= "TabsContainer";
		//== Make sure we refigure tabs to display when we resize
		oDIV.onresize									= new Function(this.ObjectName + ".eventTabsResized()");
		this.TabsDIV									= oDIV;
		oDocButtons.body.appendChild(oDIV);
		//== FrameButtons.document.DIV_Tabs.TABLE_Tabs
		//== 	The <TABLE> that contains the tab buttons
		//==		table will only be a single <TR>
		var oTable										= oDIV.appendChild(oDocButtons.createElement("table"));
		oTable.id										= "TABLE_Tabs";
		oTable.className								= "Tabs";
		oTable.cellPadding								= 0;
		oTable.cellSpacing								= 0;
		oTable.align									= "left";
		//== FrameButtons.document.DIV_Tabs.TABLE_Tabs.TR_Tabs
		//==	The <TR> that contains the tab buttons
		//==		TR will contain a <TD> for each tab button
		var oTR											= oTable.insertRow();
		oTR.id											= "TR_Tabs";
		oTR.className									= "Tabs";
		this.TabsTR										= oTR;
		
		var oTDScroll									= oTR.insertCell();
		oTDScroll.id									= "TD_Scroll";
		oTDScroll.className								= "TabScroller";
		oTDScroll.align									= "right";
		var oAScroll									= oTDScroll.appendChild(oDocButtons.createElement("a"));
		oAScroll.id										= "A_Scroll_Left";
		AnchorSetAction(oAScroll, this.ObjectName + ".TabScroll(-1)", "Scroll to the left");
		this.ScrollLeftA								= oAScroll;
		var oIMGScroll									= oAScroll.appendChild(oDocButtons.createElement("img"));
		oIMGScroll.src									= GIF("tabScrollLeft");
		oIMGScroll.border								= 0;
		oIMGScroll.style.float							= "right";
		oAScroll										= oTDScroll.appendChild(oDocButtons.createElement("a"));
		oAScroll.id										= "A_Scroll_Right";
		AnchorSetAction(oAScroll, this.ObjectName + ".TabScroll(1)", "Scroll to the right");
		this.ScrollRightA								= oAScroll;
		oIMGScroll										= oAScroll.appendChild(oDocButtons.createElement("img"));
		oIMGScroll.src									= GIF("tabScrollRight");
		oIMGScroll.border								= 0;
		oIMGScroll.style.float							= "right";
		//== FrameButtons.buttons.DIV_Header
		//==	DIV for containing the header that goes above each tab page, allowing
		//==		the user to close the tab page (goes between the tab buttons and the tab pages)
		var oDIVHeader									= oDocButtons.body.appendChild(oDocButtons.createElement("div"));
		oDIVHeader.id									= "DIV_Header";
		oDIVHeader.className							= "TabPageHeader";
		//== FrameButtons.DIV_Header.Table_Header
		var oTableHeader								= oDIVHeader.appendChild(oDocButtons.createElement("table"));
		oTableHeader.id									= "TABLE_Header";
		oTableHeader.cellPadding						= 0;
		oTableHeader.cellSpacing						= 0;
		oTableHeader.align								= "left";
		oTableHeader.width								= "100%";
		//== FrameButtons.DIV_Header.Table_Header.TR_Header
		var oTRHeader									= oTableHeader.insertRow();
		oTRHeader.className								= "TabPageHeader";
		//== FrameButtons.DIV_Header.Table_Header.TR_Header.TD_PageControl
		//==	Provides standard "controls" for the tab page displayed (Close, Launch in new window)
		var oTD											= oTRHeader.insertCell();
		oTD.id											= "TD_PageControl";
		oTD.align										= "right";
		//== Create a bunch of anchors/images for common tab functions
		var oA;
		var oIMG;
		//== Table
		//========
		oA												= oTD.appendChild(oDocButtons.createElement("a"));
		oA.id											= "A_Table";
		AnchorSetAction(oA, this.ObjectName + ".TabTable()", "View table for this data");
		this.TableAnchor								= oA;
		oIMG											= oA.appendChild(oDocButtons.createElement("img"));
		oIMG.id											= "IMG_Table";
		imgMouseovers(oIMG, "graph_table", "graph_table_over");
		oIMG.style.float								= "right";
		oIMG.border										= 0;
		//== Download
		//===========
		oA												= oTD.appendChild(oDocButtons.createElement("a"));
		oA.id											= "A_Download";
		AnchorSetAction(oA, this.ObjectName + ".TabDownload()", "Download this data view");
		this.DownloadAnchor								= oA;
		oIMG											= oA.appendChild(oDocButtons.createElement("img"));
		oIMG.id											= "IMG_Download";
		imgMouseovers(oIMG, "graph_download", "graph_download_over");
		oIMG.style.float								= "right";
		oIMG.border										= 0;
		//== Launch in New Window
		//=======================
		//== FrameButtons.DIV_Header.Table_Header.TR_Header.TD_PageControl.A_PageLaunch
		//==	<A> for launching the currently selected tab in a separate window
		oA												= oTD.appendChild(oDocButtons.createElement("a"));
		oA.id											= "A_PageLaunch";
		AnchorSetAction(oA, this.ObjectName + ".TabLaunch()", "Launch this tab in a new browser window");
		this.LaunchAnchor								= oA;
		//== FrameButtons.DIV_Header.Table_Header.TR_Header.TD_PageControl.A_PageLaunch.IMG_PageLaunch
		//==	<IMG> for the <A> that the user clicks on to launch a new window
		oIMG											= oA.appendChild(oDocButtons.createElement("img"));
		oIMG.id											= "IMG_PageLaunch";
		imgMouseovers(oIMG, "tabLaunch", "tabLaunch_over");
		oIMG.style.float								= "right";
		oIMG.border										= 0;
		//== Container.DIV_Header.Table_Header.TR_Header.TD_PageControl.A_PageClose
		//==	<A> for closing the currently selected tab
		oA												= oTD.appendChild(oDocButtons.createElement("a"));
		AnchorSetAction(oA, this.ObjectName + ".TabClose(-1)", "Click to close this tab");
		//== FrameButtons.DIV_Header.Table_Header.TR_Header.TD_PageControl.A_PageClose.IMG_PageClose
		//==	<IMG> for the <A> that the user clicks on to launch a new window
		oIMG											= oA.appendChild(oDocButtons.createElement("img"));
		oIMG.id											= "IMG_PageClose";
		imgMouseovers(oIMG, "tabClose", "tabClose_over");
		oIMG.style.float								= "right";
		oIMG.border										= 0;
	}
	//== Create the document elements for the overall tabsheet
	this.CreateMe();
}


