<!--
/////////////////
// TABS OBJECT //
/////////////////

//Creating Tabs object to represent the Tabs in memory
var Tabs = new Object;

//Tab variables
Tabs.Container		= Element_ByID("tabs"); //Container for all the Tabs HTML objects

Tabs.Objects_IDs	= new Array; //List array for the existing Tab objects' IDs (numeric). Contains all existing tabs IDs
Tabs.Objects		= new Array; //Associated array for the existing Tab objects (HTML::DIV)
Tabs.Handlers		= new Array; //Array for the existing Tab handlers (for handling events)

Tabs.Comm		= new Object; //Tab communication handler - Not implemented (fully) yet - Keeps track of tabs Ajax communications
Tabs.Comm.Statuses	= new Array; //Array for the Tab communication channels status flags


//Variables default value
Tabs.ActiveTabID	= null; //Which Tab (by ID) is active
Tabs.EditableTabID	= null; //Which Tab (by ID) is in title edit mode
Tabs.EditTabDefocusInt	= null; //Used for defocusing a tab (uses timeout instead of direct call)

Tabs.DraggedTabAnchor	= null; //The dragged tab anchor object (HTML::DIV) holder

Tabs.EditState		= false; //Indicates if a tab is in edit mode
Tabs.CommandExecState	= false; //Indicates if the system is executing (ajax) command

Tabs.DragToTabID	= null; //Indicates an attempt to drag a box to a Tab

Tabs.EditMode		= true; //Indicates if a tabs are in edit mode




///////////////////
// TAB FUNCTIONS //
///////////////////

Tabs.Init = function ()
{
	//Add Terminator tab
	AppendTab(-1,"");
}


//Tabs visual functions
Tabs.Hide=function() {Tabs.Container.style.display="none"};
Tabs.Show=function() {Tabs.Container.style.display=""};
Tabs.Refresh=function() {Tabs.Hide(); Tabs.Show();};




//A function for generating Event execution funcions
Tabs._GENERATE_ExecuteEvent = function(TabHandler,Action) {return function(){return TabHandler[Action].apply(TabHandler,arguments)};};




//Refresh communication indicator. Not implemented yet
Tabs.Comm.UpdateCommIndicator = function()
{
}





Tabs.GetOffset=function(TabObject,isTop)
{// Returns the offset (X or Y) of a specific Tab object
	return GetElementOffset(TabObject,isTop);
};




Tabs.PluckTab=function(TabHandler)
{//plucks out a tab from the HTML (visually only). Pushes other tabs to the left
 //Needed?
	
	var CurrentHandler;
	var IndexRun;
	
	//Hard sets current offsets of all existing tabs (?)
	for(IndexRun=0;IndexRun<Tabs.Objects_IDs.length;IndexRun++)
	{
		CurrentHandler=Tabs.Handlers[Tabs.Objects_IDs[IndexRun]];
		CurrentHandler.Tab.OffsetTop=Tabs.GetOffset(CurrentHandler.Tab,true)
		CurrentHandler.Tab.OffsetLeft=Tabs.GetOffset(CurrentHandler.Tab,false);
	}
	CurrentHandler = null; //Free up memory
	
	//Runs through the following tabs and changes their offset to push them left
	var NextTab=TabHandler.Tab.nextSibling;
	while(NextTab)
	{
//		if (NextTab.Tab) {NextTab.OffsetTop-=NextTab.Tab.offsetHeight}; //Excludes terminator (?)
		if (NextTab.Tab) {NextTab.OffsetLeft-=NextTab.Tab.offsetWidth}; //Excludes terminator (?)
		NextTab=NextTab.nextSibling; //Moves to the next tab
	}
	
	//Free up memory
	NextTab = null;
	IndexRun = null;
};




Tabs.GetDraggedTabAnchor=function(Set_Tab_innerHTML)
{//Retrieves (OR creates) the Dragged Tab object (HTML::DIV). Can set dragged tab content to that of the original for nicer drag effect
	
	if (!Tabs.DraggedTabAnchor)
	{//If dragged tab object doesn't exist yet create it
		Tabs.DraggedTabAnchor=CreateTabHTML(-2,Set_Tab_innerHTML);

		//Tabs.DraggedTabAnchor.className="tab_dragged";
		
		Tabs.DraggedTabAnchor.style.filter="alpha(opacity=40)";
		Tabs.DraggedTabAnchor.style.opacity=0.4;
	}
	
	if (!Set_Tab_innerHTML) {return Tabs.DraggedTabAnchor;}

	//...else - Reset HTML of dragged tab (update title)
	Tabs.DraggedTabAnchor.Title_Label.innerHTML = Set_Tab_innerHTML; 


	return Tabs.DraggedTabAnchor;
};






Tabs.GetTabsOrder_Str=function()
{//Creates the Tabs order string according to the HTML objects' order
	var TabsOrderStr="";
	var TabObject;
	var IndexRun;
	for(IndexRun=0;IndexRun<Tabs.Container.childNodes.length-1;IndexRun++) //Excluding terminator (which is always last object [childNodes.length-1])
	{
		TabObject=Tabs.Container.childNodes[IndexRun];
		if(TabObject.tagName=="DIV") //Runs only on DIVs. Other object types can not be Tabs
		{
			TabsOrderStr+= (TabsOrderStr!="")?"_":"";
			TabsOrderStr+= TabObject.TabID;
		}
	}
	
	//Free up memory;
	TabObject=null;
	IndexRun = null;

	return(TabsOrderStr);
}
	



Tabs.GetContainingTab=function(HTMLObject)
{//Locates the TabObject containing an HTML element
	var CurrentNode = HTMLObject;
	while(CurrentNode && CurrentNode.ObjectType != "Klostu_Tab") {CurrentNode = CurrentNode.parentNode};

	return(CurrentNode);
}














/////////////////////
// TAB DRAG ENGINE //
/////////////////////


var Tabs_Drag_Engine={
	TabObject:null, //Dragged Tab object container variable - filled when drag is started
	
	init:function(Tab)
	{//Called upon each Tab Handler's creation
		// Prepares the events for the dragged Tab
		Tab.onmousedown=Tabs_Drag_Engine.start;
		//Drag events are not set yet. Will be set on drag initiation
		Tab.onDragStart=new Function;
		Tab.onDragEnd=new Function;
		Tab.onDrag=new Function

		//In case Tab has no position, seys position to 0/0 (for code safety)
		if(isNaN(parseInt(Tab.style.left))) Tab.style.left="0px";
		if(isNaN(parseInt(Tab.style.top))) Tab.style.top="0px";
	},
	
	finalize:function(Tab)
	{//Free up memory - Called on tabs unload (on page closing) (?) OR upon drag_end?
		Tab.onmousedown=null;
		Tab.onDragStart=null;
		Tab.onDragEnd=null;
		Tab.onDrag=null

		Tab.object=null;
	},
	
	start:function(Event)
	{
		//Do not allow drag start if in Tab title edit state
		if (Tabs.EditableTabID != null) {if (Tabs.Handlers[Tabs.EditableTabID].EditState) {return};}
		
		//Otherwise...
		
		Event=Tabs_Drag_Engine.normalize_event(Event); //Normalizes Event object
		if(Event.which!=1) {return true}; //Drag starts only on left mouse button click
		
		//Selectes AND SAVES the passed tab object (this - executes within )
		var SelectedTabObject=Tabs_Drag_Engine.TabObject=this; 
		
		SelectedTabObject.onDragStart(); //Executes drag start event on the dragged Tab (Plucking tab, creating anchor ...)
		
		//Saves the initial position (and in this case also last position) of the object/mouse
		SelectedTabObject.Mouse_X_Latest=Event.clientX+document.body.scrollLeft;
		SelectedTabObject.Mouse_Y_Latest=Event.clientY+document.body.scrollTop;
		SelectedTabObject.Mouse_X_Original=Event.clientX+document.body.scrollLeft;
		SelectedTabObject.Mouse_Y_Original=Event.clientY+document.body.scrollTop;
		
		//Sets the trag engine's mouse up/down events as the documents' events
		document.onmouseup=Tabs_Drag_Engine.end;
		document.onmousemove=Tabs_Drag_Engine.drag;
		
		SelectedTabObject = null; //Free up memory
		
		return false;
	},
	
	drag:function(Event)
	{// Called during the drag
		if (Tabs.EditableTabID != null) if (Tabs.Handlers[Tabs.EditableTabID].EditState) {return}; //Does not take effect during tab title edit mode
		if (!Tabs_Drag_Engine.TabObject) {return}; //Does not take effect if no Tab is selected

		//Otherwise...
		
		Event=Tabs_Drag_Engine.normalize_event(Event); //Normalizes Event object
		if(Event.which==0) {return Tabs_Drag_Engine.end()} //When mouse is released, release drag
		
		var SelectedTabObject=Tabs_Drag_Engine.TabObject; //Retrieves Tab object
		var Mouse_X_Current=Event.clientX+document.body.scrollLeft;
		var Mouse_Y_Current=Event.clientY+document.body.scrollTop;

		//Abort if same position as last
		if(Mouse_X_Current==SelectedTabObject.Mouse_X_Latest && Mouse_Y_Current==SelectedTabObject.Mouse_Y_Latest) {return false};
		 
		//Calculates position of mouse in relation to original position when drag started. Do not allow drag if distance is less than 8 pixels
		var Distance;
		if (SelectedTabObject.Mouse_X_Original != -1000) //Only if not released yet (Mouse_X_Original != -1000)
		{
			Distance = Math.sqrt(Math.pow(Mouse_X_Current-SelectedTabObject.Mouse_X_Original,2)+Math.pow(Mouse_Y_Current-SelectedTabObject.Mouse_Y_Original,2)); //Calculates the position
			if (Distance<8) 
				{return false} //Cancels the drag even - do nothing
			else 
				{SelectedTabObject.Mouse_X_Original = -1000}; //Continue with the drag event - release the original position lock by setting the original mouse-X to -1000
		};

		//Retrieves the Mouse position
		var TabY_Current=parseInt(SelectedTabObject.style.top);
		var TabX_Current=parseInt(SelectedTabObject.style.left);
		
		//calculates the new tab's position based on the mouse offset from the last position
		var New_Y=TabY_Current + Mouse_Y_Current - SelectedTabObject.Mouse_Y_Latest;
		var New_X=TabX_Current + Mouse_X_Current - SelectedTabObject.Mouse_X_Latest;
		
		//Reposition the dragged tab in the new place
		SelectedTabObject.style.top =New_Y+"px";
		SelectedTabObject.style.left=New_X+"px";

		//Updates the tab's last mouse position
		SelectedTabObject.Mouse_Y_Latest=Mouse_Y_Current;
		SelectedTabObject.Mouse_X_Latest=Mouse_X_Current;

		//SelectedTabObject.onDrag(New_X,New_Y); - Less effective/nice than basic drag/drop on the mouse position
		SelectedTabObject.onDrag(Mouse_X_Current,Mouse_Y_Current); //Calling Tabs' onDrag event (commits drag changes in needed)
		
		//Free up memory
		SelectedTabObject = null;
		TabY_Current = null;
		TabX_Current = null;
		New_X = null;
		New_Y = null;
		Distance = null;
		Mouse_X_Current = null;
		Mouse_Y_Current = null;
		
		return false
	},
	
	end:function(Event)
	{//Ends drag session
		if (Tabs.EditableTabID != null) if (Tabs.Handlers[Tabs.EditableTabID].EditState) {return}; //Do not attempt to execute drag-end if in tab title edit state (no drag was started)
		if (!Tabs_Drag_Engine.TabObject) {return}; //Do not attempt to execute drag-end if no TabObject exists (no drag was started)
		
		Event=Tabs_Drag_Engine.normalize_event(Event); //Normalizes Event object
		
		//Free up documents' mouse events (previously taken over by drag engine)
		document.onmousemove=null;
		document.onmouseup=null;
		
		var RetVal=Tabs_Drag_Engine.TabObject.onDragEnd(); //Dropping tab (Execute OnDragEnd)
		Tabs_Drag_Engine.TabObject=null; //Releases the dragged tab from the drag engine
		
		return RetVal;
	},
	
	normalize_event:function(Event)
	{//Returns a modified Event object containing cross-browser properties
		if(typeof Event=="undefined")		{Event		= window.event};
		if(typeof Event.which=="undefined")	{Event.which	= Event.button};
		if(typeof Event.target=="undefined")	{Event.target	= Event.srcElement};
		return Event;
	}
};














//Obsolete - Creates a handler upon insert
/*
var initTabs=function()
{
	for(var IndexRun=0;IndexRun<Tabs.Objects_IDs.length;IndexRun++)
	{
		var TabRun=Tabs.Objects[Tabs.Objects_IDs[IndexRun]];
		{
			Tabs.Handlers[Tabs.Handlers.length]=new TabHandler(TabRun);
		}
	}
	RegisterEvent("unload",unloadTabs); //??????????? Implement
};


function unloadTabs()
{//Should be called centrally in page unload - See var initTabs=function() above or Event registration below. Should not be associated with _unload in Tabs Handler

	//Free up Tabs' Objects and Handlets
	for(var IndexRun=0;IndexRun<Tabs.Objects_IDs.length;IndexRun++)
	{
		Tabs_Drag_Engine.finalize(Tabs.Objects[Tabs.Objects_IDs[IndexRun]]); //Clearing Tabs events
		Tabs.Objects[Tabs.Objects_IDs[IndexRun]] = null; //Clearing Tabs object
		Tabs.Handlers[Tabs.Objects_IDs[IndexRun]] = null; //Clearing Tabs handlers
	}
	
	
	//Free up arrays
	Tabs.Container		= null;
	Tabs.Objects_IDs	= null;
	Tabs.Objects		= null;
	Tabs.Handlers		= null;
	
	//Free up DraggedTabAnchor
	Tabs.DraggedTabAnchor	= null;
}
//??????????? Implement
//RegisterEvent("unload",unloadTabs); 
*/




















///////////////////////
// TAB EVENT HANDLER //
///////////////////////


function TabHandler(TabObject)
{//Creates a Tab Handler - Responsible for handling Tab events
	this.Tab	= TabObject; //Links Handler to the Tab Object (HTML::DIV)

	//Resets state variables
	this.DragState	= false;
	this.EditState	= false;
	this.ActiveState= false;
	this.MouseDown	= false;
	
	Tabs_Drag_Engine.init(this.Tab);

	//Associates Events list
	this._mouseup	= Tab_Mouse_Up;
	this._mousein	= Tab_Mouse_In;
	this._mouseout	= Tab_Mouse_Out;
	
	this._dragStart	= Tab_Drag_Start;
	this._dragEnd	= Tab_Drag_End;
	this._drag	= Tab_Drag;
	this._drop	= Tab_Drop;

	//???
	//this._unload	= unloadTabs;
		
	//Create events into the Tab object (HTML::DIV) - Events are a simple "trigger" mechanism calling the function associated wih the above set Events list
	this.Tab.onmouseup	= Tabs._GENERATE_ExecuteEvent(this,"_mouseup");
	this.Tab.onmouseover	= Tabs._GENERATE_ExecuteEvent(this,"_mousein");
	this.Tab.onmouseout	= Tabs._GENERATE_ExecuteEvent(this,"_mouseout");
	
	this.Tab.onDragStart	= Tabs._GENERATE_ExecuteEvent(this,"_dragStart");
	this.Tab.onDragEnd	= Tabs._GENERATE_ExecuteEvent(this,"_dragEnd");
	this.Tab.onDrag		= Tabs._GENERATE_ExecuteEvent(this,"_drag");
}



////////////////
// TAB EVENTS //
////////////////

function Tab_Drag_Start()
{//Event for starting Tab drag
	this.MouseDown = true; //Setting Handler to indicate mouse is down

	//Disable controls visivility for the dragged Tab
	this.Tab.Controls_Edit.className = 'tab_controls';
	this.Tab.Controls_Close.className = 'tab_controls';

	Tabs.PluckTab(this); //Plucks the tab out of the HTML (visually)
	
	this.NextTab_Original=this.Tab.nextSibling; //Stores the original "next tab" for later use (revert) - Not needed?
	
	var DraggedTabAnchor=Tabs.GetDraggedTabAnchor(this.Tab.Title_Label.innerHTML); //Retreive (or create) the dragged tab anchor object (HTML::DIV) placed instead of the dragged Tab
	DraggedTabAnchor.style.visibility="hidden"; //Hides the achnor while the tab is not yet dragged
	
	//retreives dragged tab anchor needed height and width
	var DraggedTabAnchor_Height=this.Tab.offsetHeight;
	var DraggedTabAnchor_Width=this.Tab.offsetWidth;
	
	//Browser specific calculations for Dragged Tab Anchor width and height
	if (isGecko || isOpera)
	{//removes the borders width/height
		DraggedTabAnchor_Width-=parseInt(DraggedTabAnchor.style.borderTopWidth);
		DraggedTabAnchor_Width-=parseInt(DraggedTabAnchor.style.borderBottomWidth);
		DraggedTabAnchor_Height-=parseInt(DraggedTabAnchor.style.borderLeftWidth)
		DraggedTabAnchor_Height-=parseInt(DraggedTabAnchor.style.borderRightWidth)
	}; 
	
	//Gets the Tab's current position (where dragging starts from)
	var Tab_NewTop=Tabs.GetOffset(this.Tab,true);
	var Tab_NewLeft=Tabs.GetOffset(this.Tab,false);
	
//	Tabs.Hide(); - Not needed
	
	//Resizing dragged tab anchor
	DraggedTabAnchor.style.width=DraggedTabAnchor_Width+"px";
	DraggedTabAnchor.style.height=DraggedTabAnchor_Height+"px";
	
	this.Tab.parentNode.insertBefore(DraggedTabAnchor,this.Tab.nextSibling); //Places the dragged tab anchor before the next object - where the dragged tab was
	
	//Moving the dragged Tab to absolute position to allow dragging. Placing Tab in correct position (where originally was)
	this.Tab.style.position="absolute";
	this.Tab.style.zIndex=99;
	this.Tab.style.top=Tab_NewTop+"px";
	this.Tab.style.left=Tab_NewLeft+"px";

//	Tabs.Show(); - Not needed

	Tabs.Refresh(); //Refreshes the Tabs to make sure visual effects take place

	this.DragState=false; //Will reset on first call to event Tab_Drag
	
	return false;
}


function Tab_Drag_End()
{//Finalizes the Tab dragging (Happens on OnDragEnd event)

	var WasDragged = this.DragState; //May have been triggered without the Tab realy dragged - storing in variable before _drop() is executed
	
	var Moved = this._drop();
	
	//Dropping the Tab. If Tab was dragged, was moved (as returned from _drop()) and the new order is indeed dirrerent, saves new order to server
	if((Moved) && (WasDragged) && (Tabs.TabsOrder_Current!=Tabs.GetTabsOrder_Str())) {Server_SaveTabsOrder()}
	
	//Free up memory
	Moved = null;
	WasDragged = null;

	var DraggedTabAnchor=Tabs.GetDraggedTabAnchor(); //Retreive (or create) the dragged tab anchor object (HTML::DIV)
	DraggedTabAnchor.style.visibility="hidden"; //Hides the achnor when not in drag more (just in case)
	DraggedTabAnchor = null; //Free up memory
	
	return true;
}



function Tab_Drag(New_X, New_Y)
{//Executes during dragging
	
	if(!this.DragState)
	{//if tab is not yet set into dragged state
		EditTabName_Cancel(); //Cancels title edit (if active)

		//Sets tab to be 40% transparent
		this.Tab.style.filter="alpha(opacity=60)";
		this.Tab.style.opacity=0.6;
		this.DragState=true; //Sets the Tab's dragged state
//		this.Action("dragstart") - DEPRECATED
	}
	
	//Finds the closest tab (to place dragged tab next to it
	var TabObject;
	var Distance;
	var ClosestTab_Object=null;
	var ClosestTab_Distance=999999999;
	var IndexRun;
	
	for(IndexRun=0;IndexRun<Tabs.Objects_IDs.length;IndexRun++) //Runs through all Tab onjects (based in IDs table)
	{
		TabObject=Tabs.Objects[Tabs.Objects_IDs[IndexRun]]; //Retrieves tab handlers
		
		if (TabObject==this) continue; //Ignores same Tab

		//Calculate distance
		Distance = Math.sqrt(
			Math.pow(New_X-(TabObject.OffsetLeft-10),2)+
			Math.pow(New_Y-TabObject.OffsetTop,2)
		);
		
		//Debug(TabObject.TabID+":"+Distance+"["+TabObject.OffsetLeft+","+TabObject.OffsetTop+"]");
		
		if (isNaN(Distance)) continue; //Ignores "non-existing" distance
		
		//Checking if closest so far
		if(Distance < ClosestTab_Distance)
		{
			ClosestTab_Distance=Distance;
			ClosestTab_Object=TabObject;
		}
	}

	var DraggedTabAnchor=Tabs.GetDraggedTabAnchor(); //Retrieves the dragged tab anchor
	DraggedTabAnchor.style.visibility=""; //makes sure the anchor is visible

	if ((ClosestTab_Object != null) && (ClosestTab_Object != DraggedTabAnchor.nextSibling) && (ClosestTab_Object != Tabs_Drag_Engine.TabObject))
	{//If there is a closeby tab and it is not the next tab (negating the need to move the anchor) - moving the anchor
		ClosestTab_Object.parentNode.insertBefore(DraggedTabAnchor,ClosestTab_Object);
//		Debug("noving anchor before: "+ClosestTab_Object.id);
		
		if(isOpera)
		{//Attention!!!: Refreshes Boxes for opera (change code) (?)
			/*document.body.style.display="none";
			document.body.style.display=""*/
		}
	}
	
	//Free up memory
	ClosestTab_Object = null;
	ClosestTab_Distance = null;
	DraggedTabAnchor = null;
	IndexRun = null;
	TabObject = null;
	Distance = null;
}





function Tab_Drop()
{//Executes in Tab_Drag_End (when mouse is released and Tab is dropped)
	
	var Moved=false; //Assuming for now Tab was not moved

//	Tabs.Hide();
	
	//Returns Tab to regular positioning and visualization
	this.Tab.style.position="";
	this.Tab.style.width="";
	this.Tab.style.zIndex="";
	this.Tab.style.filter="";
	this.Tab.style.opacity="";
	
	var DraggedTabAnchor=Tabs.GetDraggedTabAnchor(); //this.Tab.Title_Label.innerHTML - not needed. Dragged tab anchor already exists
	
	if(DraggedTabAnchor.nextSibling != this.NextTab_Original) //Only if anchor is not where the Tab was originally... Tab was moved
	{
		DraggedTabAnchor.parentNode.insertBefore(this.Tab,DraggedTabAnchor.nextSibling); //Reinserts the Tab in it's new position (After the anchor)
		Moved=true; //Flags Moved state
	}
	
	DraggedTabAnchor.parentNode.removeChild(DraggedTabAnchor); //Removes the Dragged Tab Anchor from the HTML document
	
//	Tabs.Show();
	Tabs.Refresh();

	if(isOpera) 
	{//Attention!!!: Refreshes Boxes for opera (change code) (?)
		/*document.body.style.display="none";
		document.body.style.display=""*/
	};
	
	this.DragState=false; //Resets drag sate
	
	DraggedTabAnchor = null; //Free up memory
	
	return Moved;
}


function Tab_Mouse_Up()
{//When mouse button is up, assume tab was clicked - unless in Drag state, Edit state or Command execution
	if ((this.MouseDown)&&(!this.DragState)&&(!this.EditState)&&(!Tabs.CommandExecState)) {ActivateTab(this.Tab.TabID);};
	
	var IndexRun;
	
	for (IndexRun=0;IndexRun<Tabs.Objects_IDs.length;IndexRun++)
	{//Resets ALL Tabs' MouseDown state
		if (Tabs.Objects_IDs[IndexRun]<0) {continue};
		Tabs.Handlers[Tabs.Objects_IDs[IndexRun]].MouseDown = false;
	}

	IndexRun = null; //Free up memory
}


function Tab_Mouse_In()
{//When mouse enters a tab - Show the Tab controls - Unless in edit or drag state
	if ((!this.DragState)&&(!this.EditState))
	{
		//Enabled controls visivility
		this.Tab.Controls_Edit.className = 'tab_table_nospace tab_controls_active';
		this.Tab.Controls_Close.className = 'tab_table_nospace tab_controls_active';
	}
}


function Tab_Mouse_Out()
{//When mouse is out - hide the Tab controls
	//Disable controls visivility
	this.Tab.Controls_Edit.className = 'tab_controls tab_table_nospace';
	this.Tab.Controls_Close.className = 'tab_controls tab_table_nospace';
}


















/////////////////////
// TAB MANAGEMENT  //
/////////////////////


function EditTab(TabID)
{//Enters Tab title edit
 // DEPRECATED? replaced with EditTabName_Edit (?)
	if (Tabs.EditState) {EditTabName_Cancel(1); return(false)} //Only one tab can be edited. If attempting to enter (another) tab edit, cancels current edit

	//var EditTab_Object = Tabs.Objects[TabID];
	//Attention!!! - Where is the enter to the edit state?
	//(?) - why the need for this function then? why the need for CommandExecState
	Tabs.CommandExecState = true; //Sets command state
}



function EditTabName_Edit(TabID)
{//Enters edit mode for tab title
	var Tab_Object = Tabs.Objects[TabID];

	if (!Tab_Object) {return false}; //Aborts if not a real tab
	
	//Abort if tab is inactive or already being edited
	if ((!Tab_Object.Handler.ActiveState) || (TabID == Tabs.EditableTabID) || (Tabs.CommandExecState))
	{
		Tab_Object = null; //Free up memory
		return;
	};
	
	//If another tab is in edit mode, cancels the other tab's editing and marks new tab as edited.
	if (TabID != Tabs.EditableTabID) {EditTabName_Cancel()};
	Tabs.EditableTabID = TabID;
	
	//Cancels tab's drag if about to enter drag mode
	if (Tabs_Drag_Engine.TabObject)
	{
		document.onmousemove=null;
		document.onmouseup=null;

		Tabs_Drag_Engine.TabObject.onDragEnd();
		Tabs_Drag_Engine.TabObject=null;
	}
	
	//Triggering tab's edit state
	Tab_Object.Handler.EditState=true;
	Tabs.EditState=true;
	
	//Sets the edit box's parameters
	var EditWidth = Tab_Object.Title_Label.offsetWidth+6;
	Tab_Object.Title_Label.className = 'tab_title_label_disabled';
	Tab_Object.Title_Edit.style.width=EditWidth+"px";
	Tab_Object.Title_Edit.className = 'tab_title_edit_enabled';
	Tab_Object.Title_Edit.value = Edit(Tab_Object.Title_Label.innerHTML);

	//Sets edit box's ZIndex
	Tab_Object.zIndex = 100;
	Tab_Object.Title_Label.zIndex = 101;
	Tab_Object.Title_Edit.zIndex = 102;
	
	// Triggers a focus event - needed for browsers that can not yet focus on the HTML::INPUT object since it may be visually inactive at this stage (before refresh?)
	// Attention: Doesn't work right in opera (?)
	
	if (!isOpera)
		{setTimeout('Tabs.Objects['+TabID+'].Title_Edit.focus();',1)}
	else
		{Tabs.Objects[TabID].Title_Edit.focus();}
	
	//Free up memory
	Tab_Object = null;
	EditWidth = null;
}



function EditTabName_Commit()
{//Commits tab title edit
	var Tab_Object = Tabs.Objects[Tabs.EditableTabID];
	if (Trim(Tab_Object.Title_Edit.value).length==0) 
	{//If title is empty - Cancel edit
		EditTabName_Cancel(1);
		Tab_Object = null; //Free up memory
		return(false);
	}

	var NewTitle = Tab_Object.Title_Edit.value; //Retrieves the new title
	var OriginalTitle = Tab_Object.Title_Label.innerHTML; //Retrieves the original title
	Tab_Object.Title_Label.innerHTML = "<span class='tab_title_disabled'>"+HTML(NewTitle)+"<img src='/images/in_progress.gif' width=7 height=1/></span>"; //Sets the new temporary title with 'in-progress' indicator
	Tabs.Refresh(); //Refresh the tabs after new title was set (temporary until server approves change)

	Tab_Object.Handler.ActiveState = false; //Leaves edit mode
	
	Server_RenameTab(Tabs.EditableTabID,Escape(NewTitle),OriginalTitle); //Commits new title to server

	//Free up memory
	Tab_Object = null;
	NewTitle = null;
	OriginalTitle = null;
};




function EditTabName_Cancel(CancelEdit)
{//Cancels the tab's edit
	
	//Cancels defocus event
	if (Tabs.EditTabDefocusInt != null) clearTimeout(Tabs.EditTabDefocusInt);
	Tabs.EditTabDefocusInt = null;
	
	var Tab_Object = Tabs.Objects[Tabs.EditableTabID]; //Selects editable tab object
	
	if (Tab_Object)
	{
		if ((!CancelEdit) && (Edit(Tab_Object.Title_Label.innerHTML) != Tab_Object.Title_Edit.value)) {EditTabName_Commit()}; //Commin name change if cancel called upon blur (for example) and value of title changed
		
		//Leaves edit state
		Tab_Object.Handler.EditState=false;
		Tabs.EditState=false;
		
		//Switches back to Title (disabled Input)
		Tab_Object.Title_Label.className = 'tab_title_label_enabled';
		Tab_Object.Title_Edit.className = 'tab_title_edit_disabled';
		//Tab_Object.Title_Edit.blur();
	}
	
	Tabs.EditableTabID = null; //Free up editable tab indicator
	Tabs.Refresh(); //Refresh tabs
	
	Tab_Object = null; //Free up memory
}





function EnableTab(TabID,NewTabID,NewTabTitle)
{//Activated disabled (new) tab
// TabID is always zero. This is the TabID for a new Tab (which is the only Tab that needs enabling)

//	Tabs.Hide();

	var EnableTab_Object = Tabs.Objects[TabID]; //Retrieves the Tab object
	if (!EnableTab_Object) 
	{//Error - not a valid TabID for enabling
		EnableTab_Object = null; //Free up memory
		return false;
	}

	EnableTab_Object.id = "tab_"+NewTabID; //Sets the new HTML object ID variable (as received from the server)
	EnableTab_Object.TabID = NewTabID; //Sets the TabID parameter

	if (Tabs.ActiveTabID == TabID) {Tabs.ActiveTabID = NewTabID}; //In case enabled tab was set as the active tab, updates the active tab with the new ID

	//Updates the tab's title object and edit object with the new Title (received from the server)
	EnableTab_Object.Title.id = 'tab_' + TabID + '_title';
	EnableTab_Object.Title_Label.innerHTML = NewTabTitle;
	EnableTab_Object.Title_Edit.value = NewTabTitle;

	//Updates the Tab object and handler in the associated arrays
	Tabs.Objects[NewTabID] = EnableTab_Object;
	Tabs.Handlers[NewTabID] = EnableTab_Object.Handler;
	//Free up the old (Tab ID# 0) from the associated array
	Tabs.Objects[TabID] = null;
	Tabs.Handlers[TabID] = null;
	
	//Update the ID in the objects IDs list array
	Tabs.Objects_IDs[Tabs.Objects_IDs.length-1] = NewTabID; //Attention: Assuming last ID in Objects_IDs is the last Tab that is pending creation

	//Sets the tab handler's active state
	EnableTab_Object.Handler.ActiveState=true;
	
//	Tabs.Show();
	Tabs.Refresh();

	//Updates the new tabs order string
	Tabs.TabsOrder_Current = Tabs.GetTabsOrder_Str();
	
	EnableTab_Object = null; //Free up memory
}




function ActivateTab(TabID)
{//Sets a new tab as active

	if (Tabs.EditMode)
	{
		//If second press on the tab, enters editing mode
		if (TabID == Tabs.ActiveTabID) 
		{
			EditTabName_Edit(TabID);
			return false
		};
	}
	
	//...otherwise

	var ActiveTab_New_Object = Tabs.Objects[TabID]; //Retrieves the Tab object
	if (!ActiveTab_New_Object) 
	{//Error - not a valid TabID for activation
		ActiveTab_New_Object = null; //Free up memory
		return false;
	}

	//Else...
	
	if (Tabs.EditMode)
	{
		//Cancels currect tab edit if in such state
		EditTabName_Cancel();
	}
	
	
	//Activates tab
	ActiveTab_New_Object.className = "tab tab_active";

	//Deactivates currectly selected tab
	var ActiveTab_Current_Object = Tabs.Objects[Tabs.ActiveTabID];
	if (ActiveTab_Current_Object) 
	{
		ActiveTab_Current_Object.className = "tab";
	};
	
	//Sets selected Tab indicator
	Tabs.ActiveTabID = TabID;
	
	//Shows the page (of the activated Tab)
	Pages.ActivatePage(TabID);

	//Free up memory
	ActiveTab_New_Object = null;
	ActiveTab_Current_Object = null;
}







function CreateTabHTML(TabID,TabName)
{//Creates new tab (HTML::DIV) object
	
	var NewTab=document.createElement("DIV");
	NewTab.id="tab_"+TabID; //
	NewTab.className = 'tab_object';
	NewTab.TabID=TabID; //Backup copy of the TabID in the DOM of the tab object
	NewTab.ObjectType="Klostu_Tab";
	
	if (!Tabs.EditMode) {NewTab.onmouseup= function() {ActivateTab(Tabs.GetContainingTab(this).TabID)}};

		var NewTab_Table=document.createElement("TABLE");
		NewTab_Table.className = 'tab_table';
		
		var NewTab_Table_MainRow = NewTab_Table.insertRow(0);
		var NewTab_Table_SepLeft = NewTab_Table_MainRow.insertCell(0);
		var NewTab_Table_TitleCell = NewTab_Table_MainRow.insertCell(1); NewTab_Table_TitleCell.className = 'tab_contentarea';
		var NewTab_Table_Tools = NewTab_Table_MainRow.insertCell(2); NewTab_Table_Tools.className = 'tab_contentarea';
		var NewTab_Table_SepRight = NewTab_Table_MainRow.insertCell(3);
		
			var NewTab_seperator_left=document.createElement("DIV");
			NewTab_seperator_left.className='tab_sep_left';
			NewTab_Table_SepLeft.appendChild(NewTab_seperator_left);

			var NewTab_Title=document.createElement("DIV");
			NewTab_Title.id='tab_'+TabID+'_title';
			NewTab_Title.className='tab_title';		
				
				var NewTab_Title_label=document.createElement("DIV");
				NewTab_Title_label.className='tab_title_label_enabled';
				NewTab_Title_label.innerHTML = TabName;				
				NewTab_Title.appendChild(NewTab_Title_label);
				


				if (Tabs.EditMode)
				{
					var NewTab_Title_edit=document.createElement("INPUT");
					NewTab_Title_edit.maxLength=32;
					NewTab_Title_edit.className='tab_title_edit_disabled';
	
					NewTab_Title_edit.ondblclick = function() {if (Tabs.EditTabDefocusInt != null) {clearTimeout(Tabs.EditTabDefocusInt);} NewTab_Title_edit.focus()}; //Needed for explorer
					NewTab_Title_edit.onblur = function() {Tabs.EditTabDefocusInt=setTimeout('EditTabName_Cancel()',100);}; //Delayed edit-cancel, since explorer blurs upon same object's click
					NewTab_Title_edit.onfocus = function() {if (Tabs.EditTabDefocusInt != null) {clearTimeout(Tabs.EditTabDefocusInt);}}; //Cancel delayed edit-cancel
	
					NewTab_Title_edit.onkeydown = function(Event) //Enables Enter/Esc
					{
						if(typeof Event=="undefined")		{Event		= window.event};
						if(typeof Event.which=="undefined")	{Event.which	= Event.keyCode};
						var CancelEdit = (Event.which==27); 
						if ((Event.which==13) || (Event.which==27)) 
							{Tabs.EditTabDefocusInt=setTimeout('EditTabName_Cancel('+CancelEdit+')',100)}
						else if (Event.which>=35)
						{
							var TestObject = document.createElement("DIV");
							TestObject.style.visibility="hidden";
							TestObject.style.position="absolute";
							TestObject.style.top="-100px";
							TestObject.style.left="-100px";
							TestObject.style.fontSize="10px";
							TestObject.style.fontFamily="Verdana";
							TestObject.style.fontColor="#000000";
							TestObject.style.fontWeight="bold";
							TestObject.innerHTML="["+this.value + "##]";
							document.body.appendChild(TestObject);
							var NewWidth = TestObject.clientWidth;
							//document.body.removeChild(TestObject);
							TestObject = null; //Free up memory
							
							if (parseInt(this.style.width) < NewWidth) 
								{this.style.width = parseInt(NewWidth)}
							else
								{};
						};
						
						//Free up memory
						CancelEdit = null;
						NewWidth = null;
					};
	
					NewTab_Title.appendChild(NewTab_Title_edit);	
				}
				
			NewTab_Table_TitleCell.appendChild(NewTab_Title);

			var NewTab_Table_Tools_Table=document.createElement("TABLE");
			NewTab_Table_Tools_Table.className = 'tab_controls_table';
			
			var NewTab_Table_Tools_Row1 = NewTab_Table_Tools_Table.insertRow(0); NewTab_Table_Tools_Row1.className = 'tab_controls_row';
			var NewTab_Table_Tools_CloseCell = NewTab_Table_Tools_Row1.insertCell(0); NewTab_Table_Tools_CloseCell.className = "tab_controls_cell";
			var NewTab_Table_Tools_Row2 = NewTab_Table_Tools_Table.insertRow(1); NewTab_Table_Tools_Row2.className = 'tab_controls_row';
			var NewTab_Table_Tools_EditCell = NewTab_Table_Tools_Row2.insertCell(0); NewTab_Table_Tools_EditCell.className = "tab_controls_cell";

				var NewTab_Title_controls_Edit=document.createElement("DIV");
				NewTab_Title_controls_Edit.className='tab_controls tab_controls_edit';
				
				NewTab_Title_controls_Edit.innerHTML = "<img align=absbottom class='tab_controls_edit' src='/images/tabs/tab_tool_edit.gif' height=10px; width=10px; onmousedown='CancelBubble(event); EditTab(this.parentNode.TabReference.TabID); return(false);'/>";
				NewTab_Title_controls_Edit.TabReference = NewTab;
				NewTab_Table_Tools_EditCell.appendChild(NewTab_Title_controls_Edit);
				
				var NewTab_Title_controls_Close=document.createElement("DIV");
				NewTab_Title_controls_Close.className='tab_controls tab_controls_close';
				NewTab_Title_controls_Close.innerHTML = "<img align=absbottom class='tab_controls_close' src='/images/tabs/tab_tool_delete.gif' height=10px; width=10px; onmousedown='CancelBubble(event); DeleteTab(this.parentNode.TabReference.TabID); return(false);'/>";
		
				
				NewTab_Title_controls_Close.TabReference = NewTab;
				NewTab_Table_Tools_CloseCell.appendChild(NewTab_Title_controls_Close);
		
			NewTab_Table_Tools.appendChild(NewTab_Table_Tools_Table);
			
			var NewTab_seperator_right=document.createElement("DIV");
			NewTab_seperator_right.className='tab_sep_right';
			NewTab_Table_SepRight.appendChild(NewTab_seperator_right);

		NewTab.appendChild(NewTab_Table);




	//Set Tab Objects' additional properties
	NewTab.Title = NewTab_Title; //NewTab_Title (HTML::DIV) object reference
	NewTab.Title_Label = NewTab_Title_label; //NewTab_Title_label (HTML::DIV) object reference
	NewTab.Title_Edit = NewTab_Title_edit; //NewTab_Title_edit (HTML::INPUT) object reference
	NewTab.Controls_Close = NewTab_Title_controls_Close; //NewTab_Title_controls_Close (HTML::DIV) object reference
	NewTab.Controls_Edit = NewTab_Title_controls_Edit; //NewTab_Title_controls_Edit (HTML::DIV) object reference
	
	NewTab.style.cursor="pointer"; //Sets basic CSS properties
	
	NewTab.className=(TabID==-1)?"tab_terminator":"tab"; //Sets the classname of the tab to either "tab_terminator" or "tab" according to TabID (ID# = -1 : Terminator)


	//Free up memory
	NewTab_Table=null;
	NewTab_Table_MainRow=null;
	NewTab_Table_SepLeft=null;
	NewTab_Table_TitleCell=null;
	NewTab_Table_Tools=null;
	NewTab_Table_SepRight=null;
	NewTab_seperator_left=null;
	NewTab_Title=null;
	NewTab_Title_label=null;
	NewTab_Title_edit=null;
	CancelEdit=null;
	CurrentWidth=null;
	NewWidth=null;
	NewTab_Table_Tools_Table=null;
	NewTab_Table_Tools_Row1=null;
	NewTab_Table_Tools_CloseCell=null;
	NewTab_Table_Tools_Row2=null;
	NewTab_Table_Tools_EditCell=null;
	NewTab_Title_controls_Edit=null;
	NewTab_Title_controls_Close=null;
	NewTab_seperator_right=null;

	return(NewTab);
}



function AppendTab(TabID,TabName)
{//Appends a new tab
 //	TabID= 0 : New Tab ;
 //	TabID=-1 : Terminator Tab ;
 //	TabID=-2 : Anchor Tab ;

	//Checks if this Tab ID exists already
	if (Element_ByID("tab_"+TabID)) 
	{//Tab with this ID already exists. Abort AppendTab.
		if (TabID == 0)
			{window.alert("Please wait till the creation of the first tab is completed, before trying to create another tab.");}
		else
			{window.alert("Unexpected error: Tab by this ID already exists");}
		return (false);
	}
	else
	{//Purges existing tab object if still exists for some reason
		Tabs.Objects[TabID]==null;
	};
	
	
	var NewTab=CreateTabHTML(TabID,TabName);

	if (Tabs.EditMode)
	{
		var NewHandler = new TabHandler(NewTab); //Creates a new Handler for the new Tab
		NewTab.Handler = NewHandler; //Sets Tab Objects' Handler property
		Tabs.Handlers[TabID] = NewHandler; //Adds Tab Handler to Tabs.Handlers associated array
	}
	
	if (Tabs.Terminator) {Tabs.Container.insertBefore(NewTab,Tabs.Terminator)} else {Tabs.Container.appendChild(NewTab)}; //Adds Tab (HTML::DIV) Object to HTML document (Always before Terminator if not the Terminator itself [which MUST be added first])
	Tabs.Objects[TabID] = NewTab; //Adds Tab (HTML::DIV) Object to Tabs.Objects associated array
	Tabs.Objects_IDs[Tabs.Objects_IDs.length] = TabID; //Adds Tab ID# (numeric) to Tabs.Objects_IDs ordered list array


	if (TabID>0) 
	{//If tab is an existing tab (ID# > 0), creates the tab as Active already
		if (Tabs.EditMode) {NewTab.Handler.ActiveState = true};
		Pages.AddPage(TabID); //Adding a page object for the new tab
	}
	else if (TabID==0) 
	{//If the tab is a new tab (ID# = 0) - Calling server with Append command. Sets tab state as inactive (until server approves addition)
		if (Tabs.EditMode)
		{
			NewTab.Handler.ActiveState = false;
			Server_AppendTab();
		}
	}
	else if (TabID==-1) {Tabs.Terminator = NewTab} //Terminator tab


	Tabs.TabsOrder_Current = Tabs.GetTabsOrder_Str(); //Updates the TabOrder string


	//Free up memory
	NewTab=null;
	NewHandler=null;

}





function NewTab()
{//Calls Append tab
	AppendTab(0,"<span class='tab_title_disabled'>New Tab<img src='/images/in_progress.gif' width=7 height=1/></span>");
}






function DeleteTab(TabID,ForceDelete,SkipServer)
{//Deletes a tab
	
	if (Tabs.EditState) {EditTabName_Cancel(1); return(false)} //Can not delete a tab it Edit title mode. Disable edit first

	Tabs.CommandExecState = true; //Sets command execution mode (To avoid drag?)

	if (Tabs.Objects_IDs.length==2) {window.alert("You can not delete the only tab."); return(false)}; //Do not allow the deletion of the last tab (+Terminator=2)

	var DeleteIndex;
	var IndexRun;
	var OriginalTitle;
	
	var DeleteTab_Object = Tabs.Objects[TabID]; //Retreive the deleted tab object

	// First time delete call requires verification (window message)
	if (ForceDelete)
	{//Force delete - execute to server
		if (SkipServer)
		{//Delete without notfying server - Used for deletion during revert on add new tab or when server gives an ok on delete
			Tabs.Container.removeChild(DeleteTab_Object); //Removes the Tab object from the HTML document
			Tabs.Objects[TabID] = null; //Free up object in associated array
			Tabs.Handlers[TabID] = null; //Free up handler in associated array
			
			//Locates the objectID location to delete in the List array
			DeleteIndex=-1;
			for (IndexRun=0;IndexRun<Tabs.Objects_IDs.length;IndexRun++) {if (Tabs.Objects_IDs[IndexRun]==TabID) {DeleteIndex=IndexRun}};
			if (DeleteIndex != -1) {Tabs.Objects_IDs.splice(DeleteIndex,1)}; //Removes cell from array
			
			if (Tabs.ActiveTabID == TabID) {ActivateTab(Tabs.Objects_IDs[1]);} //Activates the first if the deleted tab was the active one
			
			Tabs.Refresh(); //Refreshes tabs
			
			Tabs.TabsOrder_Current = Tabs.GetTabsOrder_Str(); //Updates tabs order string
			Tabs.CommandExecState = false; //Leaves command state (allow drag?)
		}
		else
		{//Execute delete on server
			//Calls server tab deletion
			DeleteTab_Object.Handler.ActiveState = false; //Disables the tab's active state (allow drag?)
			//Updates the title to indecate a deletion process is running
			OriginalTitle = DeleteTab_Object.Title_Label.innerHTML;
			DeleteTab_Object.Title_Label.innerHTML = "<span class='tab_title_disabled'>"+DeleteTab_Object.Title_Label.innerHTML+"<img src='/images/in_progress.gif' width=7 height=1/></span>";
			Server_DeleteTab(TabID,OriginalTitle); //Calls server side delete
		}
	}
	else
	{//Prompting user for deletion verification

		if (Boxes.CountBoxes(TabID)>0)
		{
			window.alert("You can not delete a tab containing boxes. Please delete/move the boxes first."); 
			Tabs.CommandExecState = false; //Leaves command state if was active (allow drag?)
		}
		else if (confirm("Are you sure you want to delete the tab - "+Edit(DeleteTab_Object.Title_Label.innerHTML))) //Asks for deletion confirmation 
		{
			DeleteTab(TabID,1); //Delete the tab 
			Tabs.CommandExecState = false; //Leaves command state if was active (allow drag?)
		}
		else
		{
			EditTabName_Cancel(1); //Cancels Tab deletion
			Tabs.CommandExecState = false; //Leaves command state if was active (allow drag?)
		}
	}
	
	//Free up memory
	DeleteTab_Object = null; 
	DeleteIndex = null;
	IndexRun = null;
	OriginalTitle = null;
}




function RenameTab(TabID,NewTabTitle)
{//Renames a tab (visually)

//	Tabs.Hide();
	
	var RenamedTab_Object = Tabs.Objects[TabID]; //Retrieves Tab onject
	RenamedTab_Object.Title_Label.innerHTML = NewTabTitle; //Set new tab Title
	RenamedTab_Object.Title_Edit.value = Edit(NewTabTitle); //Set title in INPUT box
	RenamedTab_Object.Handler.ActiveState = true; //Makes sure the tab is active

//	Tabs.Show();
	Tabs.Refresh();

	RenamedTab_Object = null; //Free up memory
}




























/////////////////////
// AJAX OPERATIONS //
/////////////////////



//////// TABS REORDER /////////


var TabsReorder_Handler = new XMLHTTPEngine("TabsReorder",""); //Creates TabsReorder Ajax Handler


TabsReorder_Handler.onLoad = function(Handler) 
{//Function executed upon response from server
	
	function TabsReorder_Revert(Reason)
	{//In case of failure to reorder tab - Revert/Alert about tab reorder failure
		window.alert(Reason); //Alerting the failure reason
		//Attention!!!: Revert tabs order? - or notify to reload tabs (?)
		Tabs.Comm.Statuses['TabsReorder']=0; //Free up TabsReorder communication channel
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator
	}


	var Response = Handler.getXML();
	if (!Response) 
	{//Invalid result returned
		TabsReorder_Revert("No server response"); 
		Response = null; //Free up memory
		return(false);
	}
	
	var XMLroot = Response.getElementsByTagName('root').item(0);
	Response = null; //Free up memory
	
	if (!XMLroot) 
	{//Invalid result returned
		TabsReorder_Revert("Invalid server XML response"); 
		XMLroot = null; //Free up memory
		return(false);
	}
	
	var Status = XMLroot.getElementsByTagName('status').item(0);
	if (!Status)
	{//Invalid result returned
		TabsReorder_Revert("No status reported"); 
		Status = null; XMLroot = null; //Free up memory
		return(false);
	}

	var StatusID = Status.getElementsByTagName('status_id').item(0); 
	StatusID = StatusID?StatusID.childNodes.item(0).data:0;
	
	var StatusMessage = Status.getElementsByTagName('status_message').item(0); 
	StatusMessage = StatusMessage?StatusMessage.childNodes.item(0).data:'Unknown';
	
	if (StatusID != 1)
	{//Returrned Status indicated Tab reorder failure - Reverting reorder
		TabsReorder_Revert(StatusMessage);
		StatusID = null; Status = null; XMLroot = null; //Free up memory
		return(false);
	}

	
	//Else - All done
	Tabs.TabsOrder_Current = Tabs.GetTabsOrder_Str();
	Tabs.Comm.Statuses['TabsReorder']=0;//Free up TabsReorder communication channel
	Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator

	//Free up memory
	StatusMessage = null;
	StatusID = null;
	Status = null;
	XMLroot = null;
};


function Server_SaveTabsOrder()
{//Call server to with Tab Order command via Ajax
	if (Tabs.Comm.Statuses['TabsReorder']) {window.alert('Error - Still busy with previous tabs reordeing.')}; //Attention!!!: Can override previous reorder since full new tabs order is submitted

	//Otherwise...
	
	var TabsOrderStr=Tabs.GetTabsOrder_Str(); //Fetches the tags order string
	
	try 
	{
		Tabs.Comm.Statuses['TabsReorder']=1; //Flags TabsReorder communication channel
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator

		TabsReorder_Handler.URL='/cgi-bin/profile/tabs.pl?usk='+USK+'&act=ord&order='+TabsOrderStr;
		Debug("Calling reorder tabs @ "+TabsReorder_Handler.URL);
		TabsReorder_Handler.Execute(); //Execute server call
	}
	catch (e)
	{//Error - Could not call server
		Tabs.Comm.Statuses['TabsReorder']=0; //Free up TabsReorder communication channel
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator
	};
	
	//Free up memory
	TabsOrderStr = null;
};











//////// APPEND TAB /////////


var AppendTab_Handler = new XMLHTTPEngine("AppendTab",""); //Create AppendTab Ajax handler


AppendTab_Handler.onLoad = function(Handler) 
{//Function executed upon response from server
	
	function AppendTab_Revert(Reason)
	{//In case of failure to add a new tab - Revert and delete new tab (ID# = 0)
		window.alert(Reason); //Alerting the failure reason
		DeleteTab(0,true,true); //Deleting the temporary(new) tab Object
		Tabs.Comm.Statuses['AppendTab']=0; //Free up AppendTab communication channel
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator
	}


	Debug ("[AppendTab] Message received from server");
	var Response = Handler.getXML();
	if (!Response)
	{//Invalid result returned
		AppendTab_Revert("No server response");
		Response = null; //Free up memory
		return(false);
	}
	
	var XMLroot = Response.getElementsByTagName('root').item(0);
	Response = null; //Free up memory

	if (!XMLroot)
	{//Invalid result returned
		AppendTab_Revert("Invalid server XML response");
		XMLroot = null; //Free up memory
		return(false);
	}
	
	var Status = XMLroot.getElementsByTagName('status').item(0);
	if (!Status)
	{//Invalid result returned
		AppendTab_Revert("No status reported");
		Status = null; XMLroot = null; //Free up memory
		return(false);
	}

	var StatusID = Status.getElementsByTagName('status_id').item(0); 
	StatusID = StatusID?StatusID.childNodes.item(0).data:0;
	
	var StatusMessage = Status.getElementsByTagName('status_message').item(0); 
	StatusMessage = StatusMessage?StatusMessage.childNodes.item(0).data:'Unknown';

	Debug ("[AppendTab] Status: "+StatusID+" :"+StatusMessage);
	
	if (StatusID != 1)
	{//Returrned Status indicated Tab addition failure - Reverting addition
		AppendTab_Revert(StatusMessage);
		StatusMessage = null; StatusID = null; Status = null; XMLroot = null; //Free up memory
		return(false);
	}
	

	//Free up memory
	StatusMessage = null;
	StatusID = null;
	Status = null;

	//Else

	var DataSet = XMLroot.getElementsByTagName('data').item(0);
	if (!DataSet)
	{//Failed to receive data from server regarding the added tab - Unexpected error - Reverting addition
		AppendTab_Revert("Unexpected error - No data reported");
		DataSet = null; XMLroot = null; //Free up memory
		return(false);
	}
	
	var NewTabID = DataSet.getElementsByTagName('tab_id').item(0);
	NewTabID = (NewTabID.childNodes)?parseInt(NewTabID.childNodes.item(0).data):false;

	var NewTabTitle = DataSet.getElementsByTagName('tab_title').item(0);
	NewTabTitle = (NewTabTitle.childNodes)?NewTabTitle.childNodes.item(0).data:false;

	Debug ("[AppendTab] TabID: "+NewTabID+" :"+NewTabTitle);

	if (!NewTabTitle || !NewTabID) 
	{//Missing new TabID or Title in response from the server - Unexpected error - Reverting addition
		AppendTab_Revert("Unexpected error - Missing new Tab details");
		NewTabID = null; NewTabTitle = null; DataSet = null; XMLroot = null; //Free up memory
		return(false);
	}
	else
	{//Tab addition information is complete - Finalizing tab addition
		EnableTab(0,NewTabID,Unescape(NewTabTitle));  //Enabling Tab and setting title received from server
		Pages.AddPage(NewTabID); //Adding a page object for the new tab
		ActivateTab(NewTabID); //Setting Tab as the active Tab
		EditTabName_Edit(NewTabID); //Triggering Tab title edit
	};
	
	Tabs.Comm.Statuses['AppendTab']=0; //Free up AppendTab communication channel
	Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator
	
	//Free up memory
	NewTabID = null;
	NewTabTitle = null;
	DataSet = null;
	XMLroot = null;
};


function Server_AppendTab()
{//Calling server with AppendTab command via Ajax
	if (Tabs.Comm.Statuses['AppendTab']) {window.alert('Error - only one tab creation should run at a given time. Aborting tab creation call.')}; //AppendTab communication channel already busy (previous addition not finalized [or not finalized properly])
	
	//Otherwise...
	
	try 
	{
		Tabs.Comm.Statuses['AppendTab']=1; //Flags AppendTab communication channel as busy
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator

		AppendTab_Handler.URL='/cgi-bin/profile/tabs.pl?usk='+USK+'&act=new';
//		Debug("Calling append tab @ "+AppendTab_Handler.URL);
		AppendTab_Handler.Execute(); //Executing server call
	}
	catch (e)
	{//Failed to call server
		Tabs.Comm.Statuses['AppendTab']=0; //Free up AppendTab communication channel
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator
	};
};












//////// DELETE TAB /////////


var DeleteTab_Handler = new XMLHTTPEngine("DeleteTab",""); //Creates DeleteTab Ajax handler


DeleteTab_Handler.onLoad = function(Handler) 
{//Function executed upon response from server
	
	function DeleteTab_Revert(Reason)
	{//In case of failure to delete tab - Revert tab deletion
		window.alert(Reason); //Alerting the failure reason
		DeleteTab_Handler.CurrectTabObject.Title_Label.innerHTML = DeleteTab_Handler.TabTitle_Original; //Sets back tab title
		DeleteTab_Handler.CurrectTabHandler.ActiveState = true; //Reactivating tab
		Tabs.Comm.Statuses['DeleteTab']=0; //Free up DeleteTab communication channel
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator
		Tabs.Refresh(); //Refresh Tabs
	}


	var Response = Handler.getXML();
	if (!Response) 
	{//Invalid result retuned
		DeleteTab_Revert("No server response");
		Response = null; //Free up memory
		return(false);
	} 
	
	var XMLroot = Response.getElementsByTagName('root').item(0);
	if (!XMLroot)
	{//Invalid result retuned
		DeleteTab_Revert("Invalid server XML response");
		XMLroot = null; //Free up memory		
		return(false);
	} 
	
	Response = null; //Free up memory
	
	var Status = XMLroot.getElementsByTagName('status').item(0);
	if (!Status)
	{//Invalid result retuned
		DeleteTab_Revert("No status reported");
		Status = null; XMLroot = null; //Free up memory		
		return(false);
	} 

	var StatusID = Status.getElementsByTagName('status_id').item(0); 
	StatusID = StatusID?StatusID.childNodes.item(0).data:0;
	
	var StatusMessage = Status.getElementsByTagName('status_message').item(0); 
	StatusMessage = StatusMessage?StatusMessage.childNodes.item(0).data:'Unknown';
	
	if (StatusID != 1)
	{//Returrned Status indicated Tab deletion failure - Reverting deletion
		DeleteTab_Revert(StatusMessage);
		StatusID = null; StatusMessage = null; Status = null; XMLroot = null; //Free up memory
		return(false);
	}
	
	//Free up memory
	StatusMessage = null;
	StatusID = null;
	Status = null;

	//Else
	
	var DataSet = XMLroot.getElementsByTagName('data').item(0);
	if (!DataSet)
	{//Failed to receive data from server regarding the deletion tab - Unexpected error - Reverting deletion
		DeleteTab_Revert("No data reported");
		DataSet = null; XMLroot = null; //Free up memory
		return(false);
	}
	
	var TabID = DataSet.getElementsByTagName('tab_id').item(0);
	TabID = (TabID.childNodes)?parseInt(TabID.childNodes.item(0).data):false;

	if (!TabID) 
	{//Bad TabID - Unexpected error - reverts deletion
		DeleteTab_Revert("Unexpected error - Missing Tab details in response");
		TabID = null; DataSet = null; XMLroot = null; //Free up memory
		return(false);
	}
	else
		{DeleteTab(TabID,1,1); Tabs.Comm.Statuses['DeleteTab']=0;}; //Finalizes Tab deletion
		
	Tabs.Comm.Statuses['DeleteTab']=0; //Free up DeleteTab communication channel
	Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator

	//Free up memory
	TabID = null;
	DataSet = null;
	XMLroot = null;
};


function Server_DeleteTab(TabID,OriginalTabTitle)
{//Calling server with DeleteTab command via Ajax
	if (Tabs.Comm.Statuses['DeleteTab']) {window.alert('Error - Please delete one tab at a time. Aborting..')}; //Can not execute multiple deletes simultaniously
	
	try 
	{
		Tabs.Comm.Statuses['DeleteTab']=1; //Flags DeleteTab communication channel as busy
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator

		DeleteTab_Handler.URL='/cgi-bin/profile/tabs.pl?usk='+USK+'&act=del&id='+TabID;
		Debug("Calling delete tag @ "+DeleteTab_Handler.URL);
		//Storing delete info backup
		DeleteTab_Handler.CurrectTabHandler = Tabs.Handlers[TabID];
		DeleteTab_Handler.CurrectTabObject = Tabs.Objects[TabID];
		DeleteTab_Handler.TabTitle_Original = OriginalTabTitle;
		DeleteTab_Handler.Execute(); //Executing server call
	}
	catch (e)
	{//Failed to call server
		Tabs.Comm.Statuses['DeleteTab']=0; //Free up DeleteTab communication channel
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator
	};
};














//////// RENAME TAB /////////



var RenameTab_Handler = new XMLHTTPEngine("RenameTab",""); //Creates RenameTab Ajax Handler


RenameTab_Handler.onLoad = function(Handler) 
{//Function executed upon response from server
	
	function RenameTab_Revert(Reason)
	{//In case of failure to rename tab - Revert tab rename
		window.alert(Reason); //Alerting the failure reason
		RenameTab_Handler.CurrectTabObject.Title_Label.innerHTML = RenameTab_Handler.TabTitle_Original; //Sets back tab title
		RenameTab_Handler.CurrectTabHandler.ActiveState = true; //Reactivating Tab
		Tabs.Comm.Statuses['RenameTab']=0; //Free up RebnameTab communication channel
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator
		Tabs.Refresh(); //Refresh Tabs
	}
	
	var Response = Handler.getXML();
	if (!Response)
	{//Invalid result retuned
		RenameTab_Revert("No server response");
		Response = null; //Free up memory
		return(false);
	}
	
	var XMLroot = Response.getElementsByTagName('root').item(0);
	Response = null; //Free up memory

	if (!XMLroot)
	{//Invalid result retuned
		RenameTab_Revert("Invalid server XML response");
		XMLroot = null; //Free up memory
		return(false);
	} 
	
	var Status = XMLroot.getElementsByTagName('status').item(0);
	if (!Status)
	{//Invalid result retuned
		RenameTab_Revert("No status reported");
		Status = null; XMLroot = null; //Free up memory
		return(false);
	} 

	var StatusID = Status.getElementsByTagName('status_id').item(0); 
	StatusID = StatusID?StatusID.childNodes.item(0).data:0;
	
	var StatusMessage = Status.getElementsByTagName('status_message').item(0); 
	StatusMessage = StatusMessage?StatusMessage.childNodes.item(0).data:'Unknown';
	
	if (StatusID != 1)
	{
		RenameTab_Revert(StatusMessage);
		StatusID = null; StatusMessage = null; Status = null; XMLroot = null; //Free up memory
		return(false);
	}
	
	//Free up memory
	StatusID = null;
	StatusMessage = null;
	Status = null;

	//Else
	
	var DataSet = XMLroot.getElementsByTagName('data').item(0);
	if (!DataSet)
	{//Failed to receive data from server regarding the renaming tab - Unexpected error - Reverting rename
		RenameTab_Revert("No data reported");
		DataSet = null; Response = null; //Free up memory
		return(false);
	}
	
	var TabID = DataSet.getElementsByTagName('tab_id').item(0);
	TabID = (TabID.childNodes)?parseInt(TabID.childNodes.item(0).data):false;

	var TabTitle = DataSet.getElementsByTagName('tab_title').item(0);
	TabTitle = (TabTitle.childNodes)?TabTitle.childNodes.item(0).data:false;

	if (!TabTitle || !TabID)
	{//Bad/missing TabID or title - Unexpected error - reverts rename
		RenameTab_Revert("Missing Tab details in response");
		TabID = null; NewTabTitle = null; DataSet = null; XMLroot = null; //Free up memory
		return(false);
	}
	else
		{RenameTab(TabID,TabTitle); Tabs.Comm.Statuses['RenameTab']=0;};
		
	Tabs.Comm.Statuses['RenameTab']=0;
	Tabs.Comm.UpdateCommIndicator();
	
	//Free up memory
	TabID = null;
	NewTabTitle = null;
	DataSet = null;
	XMLroot = null;
};


function Server_RenameTab(TabID,TabTitle,OriginalTabTitle)
{//Calling server with RenameTab command via Ajax
	if (Tabs.Comm.Statuses['RenameTab']) {window.alert('Error - only one tab rename should run at a given time. Aborting tab rename call.')}; //Can only rename a tab at a time
	
	try 
	{
		Tabs.Comm.Statuses['RenameTab']=1; //Flags RenameTab communication channel as busy
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator

		RenameTab_Handler.URL='/cgi-bin/profile/tabs.pl?usk='+USK+'&act=ren&id='+TabID+'&title='+TabTitle;
//		Debug("Calling rename tab @ "+RenameTab_Handler.URL);
		//Storing delete info backup
		RenameTab_Handler.CurrectTabHandler = Tabs.Handlers[TabID];
		RenameTab_Handler.CurrectTabObject = Tabs.Objects[TabID];
		RenameTab_Handler.TabTitle_Original = OriginalTabTitle;
		RenameTab_Handler.Execute(); //Executes rename on server
	}
	catch (e)
	{
		Tabs.Comm.Statuses['RenameTab']=0; //Free up RenameTab communication channel
		Tabs.Comm.UpdateCommIndicator(); //Updates communication indicator
	};
};


-->
