// Copyright (c) 1998-2007 Araxis Ltd. All rights reserved.

// This file handles the tab control functionality.
//
// If Javascript is not enabled, the user will only be able to view the first tab's section.
// If cookies are enabled, the state of each tab control is persisted.
//
// There are two mechanisms that can be used to display a particular tab/section. The first is to use a URL anchor (#WorkJournal for example). 
// Where the anchor value is the name of the section/tab you wish to display.
// The second (for use when you can't use the anchor, for example when forwarding in a servlet), is to set the cookie g_sTabToSelectCookieName,
// to the value of the section/tab name you wish to display.

var g_sTabCookieName = "dxTabControls_v1"; // "v1" suffix allows easy versioning in case we need to change format
var g_crumbsTabControls =  new CrumbsCtor(getPageFilenameWithoutExtension(), g_sTabCookieName);

// Handles clicking of a global navigation tab
function onClickNavigationItem(element, event)
{
	if (!window || !element || typeof element.getElementsByTagName == "undefined")
		return true; // we've not handled this, so revert to default behaviour
		
	var elementTarget = null;
	if (typeof event.target != "undefined")
		elementTarget = event.target; // DOM
	else if (typeof event.srcElement != "undefined")
		elementTarget = event.srcElement; // IE
	else
		return true; // we've not handled this, so revert to default behaviour

	if (typeof (elementTarget.nodeName) != "undefined" && elementTarget.nodeName == "A")
		return true; // we recognize the event, but it was for the anchor child element, so just allow default behaviour

	var nodeListA = element.getElementsByTagName('a');
	if (nodeListA.length && typeof nodeListA[0].href != "undefined")
	{
		if (typeof window.location != "undefined")
		{
			window.location = nodeListA[0].href;
			return false; // we've handled this event, so don't use default behaviour			
		}
		else if (typeof window.navigate != "undefined")
		{
			window.navigate(nodeListA[0].href);
			return false; // we've handled this event, so don't use default behaviour			
		}		
	}

	return true; // we've not handled this, so revert to default behaviour
}

// Called by the delayedShowTabWithId method below.
function showTabWithId(sTabId)
{
	var elemTab = getElementUsingId(sTabId);
	if (elemTab)
		tabAction(elemTab);
}

// Called by the links embedded in the Flash image on the home page.
function delayedShowTabWithId(sTabId)
{
	window.setTimeout ("showTabWithId('" + sTabId +"')", 10);
}

// Handles the clicking of a tab to display the appropriate tab section and highlight the 
// appropriate tab. If an anchor element with an href attribute is a child of the li element, it indicates
// the content of the tab should be retrieved using an AJAX request to the given URL.
// See onXMLHTTPRequestEventForTabContent() for more information regarding how the content of the response is processed.
//
// param obj the 'li' element of a 'ul' collection representing the tab strip
// param fDoNotSetFocus, boolean to prevent focus being set to an element of this tab, focus is set if parameter is anything  but true
function tabAction(obj, fDoNotSetFocus)
{
	if (!obj || !obj.parentNode || !obj.parentNode.parentNode || typeof obj.getElementsByTagName == "undefined")
		return;

    if (typeof fDoNotSetFocus == "undefined" || fDoNotSetFocus != true)
        fDoNotSetFocus = false;

	// We need to remove the class name 'current' from the currently active tab.
	// To do this we unset the class name for all the 'li' elements within the 'ul' collection.
	// We also determine the tab index, needed to show the relevant tab section.
	var iTabIndex = 0;
	var nodeListLi = obj.parentNode.getElementsByTagName('li');
	for (var i = 0; i < nodeListLi.length; i++)
	{
		if (nodeListLi.item(i).className != "")
			nodeListLi.item(i).className = "";
		if (obj === nodeListLi.item(i))
			iTabIndex = i;
	}
	if (obj.className != 'current')
		obj.className = 'current';
	
    // look for registered href for the id of the current tab, send AJAX request for tab content if registered href if one exists
    if (typeof g_TabDynamicContentHref[obj.id] != "undefined" && g_TabDynamicContentHref[obj.id] != null)
    {
            var sTabContentServletURL = g_TabDynamicContentHref[obj.id];

            // add new object for tab content to array of XMLHTTPRequest objects
            var sIndex = "TAB_" + obj.id; 
            initXMLHTTPRequestObject(sIndex);
            if (g_aobjXmlHttpRequests[sIndex] != null)
            {
                // sets the event handler function that will be invoked when the request is complete
                g_aobjXmlHttpRequests[sIndex].onreadystatechange = onXMLHTTPRequestEventForTabContent;
                
                // make an asynchronous get request for the XML data
                g_aobjXmlHttpRequests[sIndex].open("GET", sTabContentServletURL, true);
                g_aobjXmlHttpRequests[sIndex].send(null);
            }
    }

	// we need to hide the currently visible tab section and show the tab section related to the clicked tab
	
	// li -> ul -> div(tabstrip) -> div(section wrapper)
	var nodeSectionWrapper = obj.parentNode.parentNode.parentNode;
	var aSectionElements = getElementsByClassName('section', nodeSectionWrapper, 'div');
	showTab(aSectionElements, iTabIndex, !fDoNotSetFocus);

	keepTrackOfActionedTabs(nodeSectionWrapper.id, iTabIndex);		
}

// Keeps track of actioned tabs.
//
// param sTabControlName, the name of the tab control.
// param iTabIndex, the 0 based index of the activated tab
function keepTrackOfActionedTabs(sTabControlName,iTabIndex)
{
	g_crumbsTabControls.setCrumb(sTabControlName, iTabIndex);
}

// saves the tab control state changes.
function saveTabControlStateChanges()
{
	if (!g_fEnableShowHideAndTabControlStatePersistence)
    {
		return;
    }
		
	g_crumbsTabControls.storePageSpecificCrumbsInCookie();
}

// Returns string containing the id of the requested tab, or null if tab was specified in URL.
function getRequestedTab()
{
    if (typeof window != "undefined" && typeof window.location != "undefined" &&
        typeof window.location.hash != "undefined" &&
        window.location.hash != null && window.location.hash.length != 0 && 
        document.getElementById(location.hash.substring(1, window.location.hash.length)) != null)
    {
        return location.hash.substring(1, window.location.hash.length);
    }
    
    return null;
}

function getTableOfSectionIdsAndActiveTabIndices()
{
    if (!areCookiesEnabled())
        return null;

    // get Tab Control state from the cookie for the page
    var aCrumbs = g_crumbsTabControls.toArray();

    // Delete all this page's persisted tabs. As we activate each tab, it's value is added back to the cookie. This means
    // that persisted values for tabs that no longer exist are thrown away.
    g_crumbsTabControls.deletePageSpecificCrumbsFromCookie();

    aTableOfSectionIdsAndActiveTabIndices = new Array(aCrumbs.length)

    for (var i = 0; i < aCrumbs.length; i++)
    // iterate through the cookie values to find the ids of the DIVs (tabs) to make visible in the page
    {
        // put the two values into a row of the table
        aTableOfSectionIdsAndActiveTabIndices[i] = aCrumbs[i].split("@");
    }
    
    return aTableOfSectionIdsAndActiveTabIndices;
}

function findIndexOfActiveTabInSectionGroup(aTableOfSectionIdsAndActiveTabIndices, sSectionId)
{
        if (aTableOfSectionIdsAndActiveTabIndices == null || aTableOfSectionIdsAndActiveTabIndices == "undefined")
        {
            // table of persisted tabs is not in cookie, show first tab
            return 0;
        }
        
        // iterate through the table of cookie values to see if any of the ids match the the current section wrapper id
        for (var m = 0; m < aTableOfSectionIdsAndActiveTabIndices.length; m++ )
        {
            if(aTableOfSectionIdsAndActiveTabIndices[m][0] == "undefined" || aTableOfSectionIdsAndActiveTabIndices[m][0].id == "undefined")
                continue;

            if(aTableOfSectionIdsAndActiveTabIndices[m][0] == sSectionId )
            {
                return aTableOfSectionIdsAndActiveTabIndices[m][1];
            }
        }

        // no tab has been found, default to first tab
        return 0;
}
	
// Sets the visible tab in each section group of the page. The id of the visible tab is retrieved from the cookie that stores active 
// tab states.  This the active tab can be overridden by the addition of a tab name in the fragment id of the requested URL. The 
// functionality of the fragment id value will still work even if tab persistance is disabled.
function setTabControlsFromPersistedState()
{
    if (!document || !document.getElementById)
    {
        // no document object, or unsupported method so exit.
        return;
    }

	// get the requested tab if one is specified in the URL
    var sRequestedTabId = getRequestedTab();

    // declare table to store section ids in first column and active tab indices in the second column
    var aTableOfSectionIdsAndActiveTabIndices = null;

	if (typeof g_fEnableShowHideAndTabControlStatePersistence != "undefined" && g_fEnableShowHideAndTabControlStatePersistence)
	{
        // selected tab persistence is enabled, get table of section ids and active tab indices from cookie
        aTableOfSectionIdsAndActiveTabIndices = getTableOfSectionIdsAndActiveTabIndices();
    }			

	// For each section group in the page, check whether the cookie contained a value to indicate the active tab to show. 
	// If not then show the first tab.

	// declare flag to track whether focus has already been set for a form element in the page
	var fFocusHasBeenSet = false;

	// We only want to find DIVs with class 'tabStrips' and 'section' within a DIV with class 'sectionWrapper' so that we don't process
	// the global tabs at the top of the page.
	var aSectionWrappers = getElementsByClassName('sectionWrapper', document, 'div')

    sectionGroupsLoop: 
    for (var k = 0; k < aSectionWrappers.length; k++)
	// iterate through the sections groups
	{
		var nodeTabStrip = getElementsByClassName('tabStrip', aSectionWrappers[k], 'div')[0];
		if (typeof nodeTabStrip == "undefined")
		    continue;

		// get reference to list node of tab strip
		var nodeUL = nodeTabStrip.getElementsByTagName('ul').item(0);
		if (typeof nodeUL == "undefined")
        {
			// if no list container element then there is no list, stop processing this section wrapper and process the next section wrapper
		    continue;
        }

		// get array of references to list entry nodes
		var tabLI = nodeUL.getElementsByTagName('li');
		if (typeof tabLI == "undefined" || tabLI.length == 0)
        {
			// if no list entry elements then there is no list, stop processing this section wrapper and process the next section wrapper
		    continue;
        }
		
        if (sRequestedTabId != null) // a tab has already been selected based on URL frag id
        {
            // a specific tab has been requested, look for it in this section group
            for (var j = 0; j < tabLI.length; j++ )
            {
                if (tabLI[j].id == sRequestedTabId)
                {
                    // the requested tab has been found in this section group, no need to set the persisted state for this section group
                    continue sectionGroupsLoop;
                }
            }
        }

        // declare index of active tab
        var iActiveTab = findIndexOfActiveTabInSectionGroup(aTableOfSectionIdsAndActiveTabIndices, aSectionWrappers[k].id);
		
		// get array of references to DIVs that have a class attribute = "section"; these represent each of the tabs
		var aSectionElements = getElementsByClassName('section', aSectionWrappers[k], 'div');
	
		if (aSectionElements.length == 0)
        {
			// there are no tabs in the section; continue to next section wrapper
			continue;
        }
		
		if (iActiveTab > aSectionElements.length - 1)
        {
			// the persisted tab no longer exists, set active tab to the first
			iActiveTab = 0;
        }
		
        tabAction(tabLI[iActiveTab], fFocusHasBeenSet);
        fFocusHasBeenSet = true;
	}
    
	// if a requested tab is specified via the location.hash, and the tab exists, show it
    if (sRequestedTabId != null)
    {
        tabAction(document.getElementById(sRequestedTabId), false); // false ensure focus is set to requested tab
    }
}

// Sets the visible state of all the sections passed in aSectionElements. Only one tab (per section group) can be visible, 
// specified by the iActiveTabIndex, which indicates the index in the array aSectionElements of the tab to make visible. 
// The fSetFocus parameter instructs this function to set the focus of the first active element of the first visible form. 
// Note: that if this function has previously been called for another array of sections, the focus
// will be lost to the visible section given in the current call to the function.
//
function showTab(aSectionElements, iActiveTabIndex, fSetFocus)
{
	if (aSectionElements == null)
		return;
	
	if (aSectionElements.length == 0)
		return;

	if (typeof aSectionElements[0].style == "undefined")
		return;

	if (typeof aSectionElements[0].style.display == "undefined")
		return;

	// Set all tab sections to the correct state. We do this in a single pass for maximum efficiency, otherwise
	// there might be flicker or unnecessary rendering delay.
	var fFirstVisibleInputElementHasBeenFound = !fSetFocus;

	for (var k = 0; k < aSectionElements.length; k++)
	{	
        var sDesiredState = k == iActiveTabIndex ? 'block' : 'none';
		if (aSectionElements[k].style.display != sDesiredState)
		{
			aSectionElements[k].style.display = sDesiredState;
		}

		if (k == iActiveTabIndex && !fFirstVisibleInputElementHasBeenFound)
			fFirstVisibleInputElementHasBeenFound = setFocusOfFirstActiveFormInput(aSectionElements[k]);
	}							
}

// Response handler for AJAX request to get tab content. Looks for outstanding XMLHTTPRequest objects to process that
// have an id beginning with "TAB_". When one is found and the the request has completed, responseText is searched. The content 
// of each DIV in the  responseText that has an id begining with "kttc" is inserted into the document within the first DIV 
// that has the same id but without the "kttc" prefix.
//
// Once the content has been inserted, further AJAX requests from the same page impression are prevented by removing the href 
// tag on the anchor element of the tab. The tab is identifed by the id used to index the XMLHTTPRequest object in  
// g_aobjXmlHttpRequests; the id after the "TAB_" prefix is the name of the tab.
function onXMLHTTPRequestEventForTabContent()
{
    // pass through AJAX requests processing any that are for tab content
    for (sKey in g_aobjXmlHttpRequests)
    {
        if (sKey.substring(0, "TAB_".length) == "TAB_")
        {
            // get the section element
            var iSectionLiElementId = sKey.substring("TAB_".length);
            var elementSectionLi = getElementUsingId(iSectionLiElementId);
            if (typeof elementSectionLi == "undefined" || elementSectionLi == null)
            {
                // something has gone wrong - the section should be in the page, continue to the next request
                continue;
            }
            
            var xmlHttpRequest = g_aobjXmlHttpRequests[sKey];

	        // check that the object is in the correct ready state and its status is complete before inserting HTML
            if (xmlHttpRequest.readyState == 4)
            {
                // if there was a problem with the request, continue to next request object without doing anything
                if (xmlHttpRequest.status != 200)
                    continue;

                var sResponseText = xmlHttpRequest.responseText;
                
                // look for all DIVs that are children (and not any other decendents) of the content DIV
                // i.e. inside HTML -> BODY -> "DIV (wrapper)" -> "DIV (content)"
                var iIndexOfBodyTag = sResponseText.indexOf("<body");
                if (iIndexOfBodyTag == -1)
                {
                    continue;
                }
                
                var iIndexOfContentDivTag = sResponseText.indexOf("<div id=\"content\"", iIndexOfBodyTag);
                if (iIndexOfContentDivTag == -1)
                {
                    continue;
                }
                
                var asTabContentDivs = sResponseText.split("kttc");
                if (asTabContentDivs.length < 2)
                {
                    // no TABCONTENT DIVs have been found, 
                    continue;
                }
                
                // for each TABCONTENT, attempt to add it to the current page
                for (var i = 1 ; i < asTabContentDivs.length; i++)
                {
                    var sTabContentDiv = asTabContentDivs[i];
                    
                    // first, get the rest of the DIV's id, it is the id of the DIV we need to look for in the page into which to insert
                    var sTargetElementId = sTabContentDiv.substring(0, sTabContentDiv.indexOf("\""));

                    // we now need to strip charaters of the DIV element that wraps the content
                    var iEndOfContentIndex = null;
                    if (i +1 == asTabContentDivs.length)
                    {
                        // this is the last DIV in the array, so it will be terminated with: "</div></div></div></body>"
                        iEndOfContentIndex = sTabContentDiv.lastIndexOf("</div></div></div></body>");
                    }
                    else
                    {
                        // this is not the last DIV, so it will be terminated with: </div><div id="
                        iEndOfContentIndex = sTabContentDiv.lastIndexOf("</div><div id=\"");
                    }
                    
                    var iStartOfContentIndex = sTabContentDiv.indexOf(">") + 1;
                    
                    var sContent = sTabContentDiv.substring(iStartOfContentIndex, iEndOfContentIndex);

                    // look for a span or div with the id
                    var elementTarget = getElementUsingId(sTargetElementId);
                    
                    if (typeof elementTarget != "undefined" &&  elementTarget != null )
                    {
                        // delete all the children of the target element
                        removeChildrenFromNode(elementTarget);

                        // update the innerHTML of the target element
                        elementTarget.innerHTML = sContent;
                        
                        // if target element has a registered callback statement, execute it
                        if (typeof g_TabDynamicContentCallback[sTargetElementId] != "undefined" && g_TabDynamicContentCallback[sTargetElementId] != null)
                        {
                            eval(g_TabDynamicContentCallback[sTargetElementId]);
                        }

                    }
                }

                // Now we should delete the registered href from the g_TabDynamicContentHref, this will prevent further submissions to
                // the servlet serving tab content.
                delete g_TabDynamicContentHref[iSectionLiElementId];

                // we are done with request object, so we delete it from the store
                delete g_aobjXmlHttpRequests[sKey];
                
                // need to set page state here
                onDynamicContentLoad()
            }
        }
    }
}

// Called directly after a successful insertion of dynamic tab content. 
function onDynamicContentLoad()
{
    if (typeof(setPageState) != "undefined" && typeof(clearModifiedMessageTimeout) != "undefined")
    {
        if (g_pageStateTimerId != null)
            window.clearTimeout(g_pageStateTimerId);
    
        // do this asynchronously
        g_pageStateTimerId = window.setTimeout("setPageState();", 100);
    }
    
    if (typeof(highlightCheckedTableRows) != "undefined")
    {
	   highlightCheckedTableRows();
    }
    
    if (typeof(syncEnabledStatesForAllBoolFields) != "undefined")
    {
		syncEnabledStatesForAllBoolFields();
	}
}

// Given a pointer to a "section" DIV element of the DOM, this method sets the keyboard focus to the first active 
// form field of all the forms in the section (read tab)
function setFocusOfFirstActiveFormInput(nodeSectionElement)
{
	if (nodeSectionElement == "undefined")
		return false;

	var nodeForms  = nodeSectionElement.getElementsByTagName("FORM");
	if (typeof nodeForms == "undefined")
		return false;

	for (var m = 0; m < nodeForms.length; m++)
	{
		// iterate through the forms of a section
		if (typeof nodeForms[m] == "undefined")
			continue;
			
		var aFormElements =  nodeForms[m].elements;
		for(var n=0; n< aFormElements.length; n++)
		// iterate through elements of a form
		{
			var element = aFormElements[n];

			if (element.tagName == "INPUT" && (element.type == "hidden" || element.type == "image"))
				continue;

			if (element.disabled)
				continue;
				
			if (element.tagName == "INPUT" && (element.type == "text" || element.type == "password") && element.readonly)
				continue;

			if (element.tagName == "TEXTAREA" && element.readonly)
				continue;

			// found the first active element that can receive focus
			element.focus();
			return true;
		}
	}
	return false;
}

// clears the modified message timeout
function clearModifiedMessageTimeout()
{
	if (!window || !window.clearTimeout)
		return;
	
	if (g_iTimerIdForChangesAppliedMessage)
		window.clearTimeout (g_iTimerIdForChangesAppliedMessage);
	g_iTimerIdForChangesAppliedMessage = null;
}

// sets the modified message for the given form
function setModifiedMessage(tabId)
{
	var elTransientMessage = getElementUsingId(g_sElementTransientMessagePrefix + tabId);
    if (elTransientMessage)
    {
        if (g_iTimerIdForChangesAppliedMessage) 
            window.clearTimeout (g_iTimerIdForChangesAppliedMessage);
            
        g_iTimerIdForChangesAppliedMessage = window.setTimeout ("removeModifiedMessage('" + tabId +"')", 4*1000);
        g_elementChangesAppliedMessage = elTransientMessage;
		elTransientMessage.className = "shown";
    }
}

// removes the modified message on a form (see function setModifiedMessage)
function removeModifiedMessage(tabId)
{
    if (g_elementChangesAppliedMessage != null)
    	g_elementChangesAppliedMessage.className = "alwaysHidden";
	g_elementChangesAppliedMessage = null;
}

// register the given URL for the given tab
function registerTabDynamicContentHref(sTabId, sUrl)
{
    if (sTabId == null || sUrl == null)
        return;

    if (typeof g_TabDynamicContentHref =="undefined" || g_TabDynamicContentHref == null)
        return;

    g_TabDynamicContentHref[sTabId] = sUrl;

}

// register the given callback statement for the given Dynamic Include id
function registerTabDynamicContentCallback(sDynamicContentIncludeId, sCallbackText)
{
    if (sDynamicContentIncludeId == null || sCallbackText == null)
        return;

    if (typeof g_TabDynamicContentCallback =="undefined" || g_TabDynamicContentCallback == null)
        return;

    g_TabDynamicContentCallback[sDynamicContentIncludeId] = sCallbackText;
}