/* Copyright (C) 1996-2002 MicroStrategy Incorporated, All rights resrved. Confidential. */
//<SCRIPT>

var useXHR = true;
var javaScriptPath = "";
var mstrLogImplScript = false;
var mstrToolbarImplScript = false;
var mstrRwToolbarImplScript = false;
var mstrGraphToolbarImplScript = false;
var mstrPageSetupTabImplScript = false;
var mstrTreeImplScript = false;
var mstrAllObjectBrowserTreeImplScript = false;
var mstrRWObjSelectionsImplScript = false;
var mstrReportObjSelectionsImplScript = false;
var mstrObjectBrowserImplScript = false;
var mstrRWObjectsImplScript = false;
var mstrReportObjectsImplScript = false;
var mstrReportWSObjectsImplScript = false;
var mstrFormulaBarImplScript = false;
var mstrResizeEditorImplScript = false;
var mstrFormatImplScript = false;
var mstrAccordionTabManagerImplScript = false;
var mstrDocPropTabManagerImplScript = false;
var mstrPageLayoutTabImplScript = false;
var mstrPageMarginsTabImplScript = false;
var mstrGeneralPropTabImplScript = false;
var mstrGridPropTabImplScript = false;
var mstrPicturePropTabImplScript = false;
var mstrWatermarkPropTabImplScript = false;
var mstrLayoutPropTabImplScript = false;
var mstrLinePropTabImplScript = false;
var GradientUtilScript = false;
var mstrTabImplScript = false;
var mstrNumberTabImplScript = false;
var mstrNumberFormatTabImplScript = false;
var mstrColorTabImplScript = false;
var mstrAlignTabImplScript = false;
var mstrFontTabImplScript = false;
var mstrEffectsTabImplScript = false;
var mstrGraphAxesTabImplScript = false;
var mstrGraphTitlesTabImplScript = false;
var mstrGraphGeneralTabImplScript = false;
var mstrGraphAdvancedTabImplScript = false;
var mstrNotesTabImplScript = false;
var mstrGraphOptionTabImplScript = false;
var mstrEditorImplScript = false;
var mstrContactsEditorImplScript = false;
var mstrSortEditorImplScript = false;
var mstrGroupbyPropsImplScript = false;
var mstrTreeAttributeFormsQualificaionImplScript = false;
var mstrMetricQualLevelEditorImplScript = false;
var mstrMsgBoxImplScript = false;
var AttFormsScript = false;
var cartScript = false;
var mstrCartImplScript = false;
var ncScript = false;
var mstrSubscriptionsFolderImplScript = false;
var objectBrowserScript = false;
var calendarScript = false;
var incrementalFetchScript = false;
var advancedDrillScript = false;
var adminOptionsScript = false;
var columnWidthsGGScript = false;
var colHandlesSetScript = false;
var outlineModeGGScript = false;
var lockSetScript = false;
var formatEditorScript = false;
var filterScript = false;
var promptFunctionsScript = false;
var menuScript = false;
var contextMenuManagerScript = false;
var contextMenuScript = false;
var incrementalFetchCheckBoxesScript = false;
var mstrColResizeImplScript = false;
var mstrColorPickerEditorImplScript = false;
var mstrColorGradientEditorImplScript = false;
var mstrRWColorGradientEditorImplScript = false;
var mstrPageByReportImplScript = false;
var mstrPageByMapperImplScript = false;
var mstrPageByImplScript = false;
var mstrFilterEditorImplScript = false;
var mstrOutlineModeImplScript = false;
var mstrExportOptionsImplScript = false;
var mstrAdvancedPropTabImplScript = false;
var mstrOtherPropTabImplScript = false;
var mstrDocPropsExportTabImplScript = false;
var mstrTocPropTabImplScript = false;
var mstrObjSelectionsImplScript = false;
var mstrAttFormsImplScript = false;
var ObjectManipulationScript = false;
var mstrProjectBrowserImplScript = false;
var mstrReportAllObjectsImplScript = false;
//var mstrReportAllObjSelectionsImplScript = false;
var mstrDataExplorerImplScript = false;
var mstrProjectBrowserSelectionsImplScript = false;
var mstrElementPickerImplScript = false;
var mstrFilterObjectsImplScript = false;
var mstrUserEntityEditorImplScript = false;
var mstrAdminGenericTabImplScript = false;
var mstrTreeControlScript = false;
var mstrTreeViewImplScript = false;
var mstrOutlineViewImplScript = false;
var mstrFolderActionsScript = false;
var mstrFolderTreeViewImplScript = false;
var mstrFolderFrameTreeViewImplScript = false;
var mstrTreeCartImplScript = false;
var mstrUserEntitiesTreeCartImplScript = false;
var mstrEntitySelectorImplScript = false;
var mstrSingleObjectSelectorImplScript = false;
var mstrObjSelProjectBrowserImplScript = false;
var mstrPromptDefTabImplScript = false;
var mstrPromptQuestionsTabImplScript = false;
var mstrPromptDisplayTabImplScript = false;
var mstrPromptAdvancedTabImplScript = false;
var mstrPromptQualificationTabImplScript = false;
var mstrPromptDefImplScript = false;
var mstrTabStripImplScript = false;
var mstrTabStripMapperImplScript = false;
var mstrLayoutTabImplScript = false;
var mstrSectionsTabImplScript = false;
var mstrPortalImplScript = false;
var mstrPromptDefTabManImplScript = false;

var mstrUnselectableObjectExplorerImplScript = false;
var mstrSaveAsEditorImplScript = false;
var mstrSaveAsReportImplScript = false;
var mstrSaveAsObjectImplScript = false;
var mstrCreateFolderImplScript = false;
var mstrAdvancedOptionsImplScript = false;
var mstrHyperLinkEditorImplScript = false;
var mstrHyperLinkObjectExplorerImplScript = false;
var mstrAlertsObjectExplorerImplScript = false;
var mstrFilterDetailsFormattingEditorImplScript = false;
var mstrSubtotalSimpleTabScript = false;
var mstrSubtotalAdvancedTabScript = false;
var mstrSubtotalDisplayTabScript = false;
var mstrSubtotalsObjImplScript = false;

var mstrAdminBrowserImplScript = false;
var mstrSecurityFilterFrameImplScript = false;
var mstrFunctionWizardEditorImplScript = false;

var mstrSecurityRoleEditorImplScript = false;

var mstrThresholdFormatEditorImplScript = false;

var mstrSortRowTabImplScript = false;
var mstrSortColTabImplScript = false;

var mstrObjectListImplScript = false;
var mstrUserEntitiesImplScript = false;
var mstrContactsBrowserImplScript = false;
var mstrUserAddressListImplScript = false;
var mstrReportFrameImplScript = false;
var mstrDerivedElementsBrowserImplScript = false;
var mstrDerivedElementsEditorImplScript = false;
var mstrDerivedElmtToolbarImplScript = false;
var mstrDECalculationImplScript = false;

//var mstrDerivedElementsListImplScript = false;
var mstrPathImplScript = false;
var mstrPickerImplScript = false;
var mstrEditorToolbarScript = false;
var mstrDMToolbarImplScript = false;

var mstrThresholdEditorScript = false;
var mstrThresholdSliderImplScript = false;
var mstrSimpleThresholdEditorImplScript = false;
var mstrAdvancedThresholdEditorScript = false;
var mstrAlertsEditorScript = false;
var mstrThresholdExpressionEditorScript = false;
var mstrDivBasedCartImplScript = false;
var mstrFolderImplScript = false;
var mstrInlineRenameImplScript = false;
var mstrGraphDropZonesEditorScript = false;

var mstrInboxImplScript = false;
var mstrDerivedElementFormatEditorImplScript = false;
var mstrDerivedElementToolbarScript = false;
var mstrFormatHelper = false;
var importDerivedElementsEditorImplScript = false;

var mstrRelatedReportsImplScript = false;
var mstrTreeTabManagerImplScript = false;
var mstrTabManagerTreeViewImplScript = false;
var mstrFormatTreeTabManagerImplScript = false;


var mstrObjectExplorerImplScript = false;
var mstrReportXdaObjectsImplScript = false;
var mstrXDAObjectExplorerImplScript = false;
var mstrXDAEditorImplScript = false;
var mstrVisualizationsEditorImplScript = false;
var mstrRWControlImplScript = false;
var mstrHTMLContainerImplScript = false;
var mstrReportGraphImplScript = false;
var mstrReportGraphCMImplScript = false;
var mstrDatasetExplorerEditorImplScript = false;

var mstrPanelStackScript = false;
var mstrRWActionControlImplScript = false;
var mstrScrollerImplScript = false;
var mstrSelectorPropTabImplScript = false;
var mstrFlashPropTabImplScript = false;
var mstrRoundedRectangleScript = false;
var mstrRWUnitBoneImplScript = false;
var mstrFlashViewerImplScript = false;
var mstrFlashDashboardImplScript = false;
var mstrSecondaryDataSourcesImplScript = false;
var mstrWebHyperLinkEditorImplScript = false;
var mstrOtherGridPropTabImplScript = false;
var mstrAlertsExpressionEditorScript = false;
var mstrFilterToolbarScript = false;

var mstrGridStaticScript = false;
var mstrGridReportScript = false;
var mstrGridRWScript = false;
var mstrIPhoneGridVisPropsEditorImplScript = false;
var mstrIPhoneMarkerMashupVisPropsEditorImplScript = false;
var mstrESRIVisPropsEditorImplScript = false;

var bFirstMetric = false;
var sURL = '';
var bDesignMode = false;
var lIndex = 0;
var sMsgID = '';
var sView = '';
var bAdvancedEdit = false;
var flg_RTitle = 1;
var flg_QLinks = 2;
var flg_FTBar = 4;
var flg_Filt = 8;
var flg_PAxis = 16;
var flg_RTBar = 32;
var flg_SRTEditor = 64;
var flg_DRLEditor = 128;
var flg_FSELEditor = 256;
var flg_FRMEditor = 512;
var flg_FMATEditor = 1024;
var flg_SUBEditor = 2058;
var flg_Email = 4096;
var flg_Send = 8192;
var flg_ObjBr = 16384;
var flg_Grid = 32768;
var flg_IncFetch = 65536;
var SCROLLBAR_SIZE = 17;

var aEditorButton = new Array();
aEditorButton[1] = '';
aEditorButton[2] = 0;

var aTemplateElements = new Array();
var lPropertyAlias = 0;
var lPropertyKey = 0;
var lPropertyType = 0;
var lPropertyDerivedMetricType = 3;
var lPropertyDerivedMetric = 0;
var lPropertyFormula = 0;
var lPropertyPosition = 0;
var sNewMetric = '';
var DssXmlTemplateMetrics = '';
var logClientStopTimer = false;
var logClient = false;
var sTreeName = 'tree1';

//prompt anchor
var currentPin = '-1';

//**DHTMLJSPAPI

var initializeCalls = "";

//**DHTMLAPI

var bIsIE4 = (document.all) ? true : false;     // IE 4+
var bIsIE6 = false;
var bIsIE7 = false;
var bIsIE8 = false;
if(bIsIE4){
    var agt=navigator.userAgent.toLowerCase();
    var ie = agt.substring(agt.indexOf("msie")+4, agt.indexOf("msie")+8);
    bIsIE6 = (parseFloat(ie)>=6.0)? true: false; //IE6.0+
    bIsIE7 = (parseFloat(ie)>=7.0)? true: false; //IE7.0+
    bIsIE8 = (parseFloat(ie)>=8.0 && document.documentMode == 8)? true: false; //IE8.0+ standards mode
}
var bIsIEQuirks = bIsIE7 && (document.documentMode == 5 || document.compatMode == "BackCompat");//IE7.0+ but quirks 

var bIsW3C = (document.getElementById && (!bIsIE4 || bIsIE8)) ? true : false;       //W3C
var bIsFirefox = (bIsW3C && navigator.userAgent.toLowerCase().indexOf("firefox") > -1);

var isMac = navigator.userAgent.indexOf('Macintosh') > -1;

// Mouse screen coordinates.
var lMouseX = 0;
var lMouseY = 0;

// bIsDHTML capable browser for degradability
var bIsDHTML = (bIsIE4 || bIsW3C) ? true : false;

//CSS Analyzer
var ENABLE="MSTRCSSANALYSER_Enable";

//This is done to support the insertAdjacentElement, insertAdjacentHTML and insertAdjacentText calls in non IE browsers.
/**
 * Adds methods to HTMLElement to support the insertAdjacentElement, insertAdjacentHTML and insertAdjacentText calls in non IE browsers.  We should remove this
 * add use methods defined in the DOM Standards. 
 * @class HTMLElement
 */
if(typeof HTMLElement!="undefined" && !HTMLElement.prototype.insertAdjacentElement){

    /**
     * Adds insertAdjacentElement for non IE browsers.  We should remove this and use methods defined in the DOM Standards.
     * @param {String} where The position to insert at [beforeBegin, afterBegin, beforeEnd or afterEnd].
     * @param {Node} parsedNode The node to insert.
     */
    HTMLElement.prototype.insertAdjacentElement = function(where, parsedNode)
    {
        switch (where){
        case 'beforeBegin':
            this.parentNode.insertBefore(parsedNode,this)
            break;
        case 'afterBegin':
            this.insertBefore(parsedNode,this.firstChild);
            break;
        case 'beforeEnd':
            this.appendChild(parsedNode);
            break;
        case 'afterEnd':
            if (this.nextSibling)
              this.parentNode.insertBefore(parsedNode,this.nextSibling);
            else this.parentNode.appendChild(parsedNode);
              break;
        }
    };

    /**
     * Add insertAdjacentHTML for non IE browsers.  We should remove this and use methods defined in the DOM Standards.
     * @param {String} where The position to insert at [beforeBegin, afterBegin, beforeEnd or afterEnd].
     * @param {String} htmlStr The html fragment to insert.
     */
    HTMLElement.prototype.insertAdjacentHTML = function(where, htmlStr)
    {
        var r = this.ownerDocument.createRange();
        r.setStartBefore(this);
        var parsedHTML = r.createContextualFragment(htmlStr);
        this.insertAdjacentElement(where,parsedHTML)
    };


    /**
     * Add insertAdjacentText for non IE browsers.  We should remove this and use methods defined in the DOM Standards.
     * @param {String} where The position to insert at [beforeBegin, afterBegin, beforeEnd or afterEnd].
     * @param {String} txtStr The text fragment to insert.
     */
    HTMLElement.prototype.insertAdjacentText = function(where, txtStr)
    {
        var parsedText = document.createTextNode(txtStr)
        this.insertAdjacentElement(where,parsedText)
    };

}


/**
* Allows users to search for an instance of one string within another string.  Should be refactored to use RegExp.  Used in 9 places -- good candidate for removal.
* @memberOf String
* @param {String} element The string to search for.
* @param {String} delimiter An optional parameter for searching delimited strings.
* @type Boolean
* @return True if the element string is found within the container string, otherwise false.
*/
String.prototype.contains = function(element, delimiter) {
    try {
        if (!element) return false;

        if (!delimiter) {
            return (this.indexOf(element) > -1);
        }

        var testString = delimiter + this + delimiter;
        return (testString.indexOf(delimiter + element + delimiter) > -1);
    } catch (err) {
        alert(err);
        return false;
    }
}

/**
 * Listens to all keydown events on the window.document element.  In Report Services the event is redirected to the instance of mstrDocImpl.  In Report mode
 *      this method handles ctrl-z, ctrl-y and F12.
 * @param {Event} e The event object (W3C compliant browsers only).
 * @return true
 */
function keyDownHandler(e) {
    if (typeof(microstrategy) == "undefined" || microstrategy.eventManager == null 
    		|| (iframe && iframe.onWaitState != false)) { // during partial update
        return true;
    }

    // Get the event target element.
    if (!e) e = window.event;

    var src = getEventTarget(e);
    

    
    if(src) {
        var name = src.tagName.toLowerCase();
    
        if (name == 'input' || name == 'select' || name == 'textarea') return true;
    
        if (microstrategy.EXECUTION_SCOPE == microstrategy.REPORT_EXECUTION) {
            switch (e.keyCode) {
                case 89:
                    if (e.ctrlKey) {
                        microstrategy.eventManager.notifyOrphanBones('processRedo');
                        return false;
                    }
                    break;
                case 90:
                    if (e.ctrlKey) {
                        microstrategy.eventManager.notifyOrphanBones('processUndo');
                        return false;
                    }
                    break;
                case 123:
                    if (microstrategy.DISPLAY_MODE == microstrategy.VIEW_MODE) {
                        toggleScreenMode();
                        return false;
                    }
                    break;
                default:
                    return true;
                    break;
            }
        } else {
            var bone = microstrategy.bone("rwb_viewer");
            if (bone != null && bone.doc != null && currentModalEditor.length == 0) {
                return bone.doc.onkeydown(e);
            }
        }
    }
    return true;

}

/**
 * Listens to all keypress events on the window.document element and redirects the event to the instance of mstrDocImpl in Report Services.
 * @param {Event} e The event object (W3C compliant browsers only).
 * @return true
 */
function keyPressHandler(e) {
    
    switch ((e || window.event).keyCode) {
		case 27:
		if (iframe && iframe.onWaitState) {
			iframe.hideWaitPage();
		}
		return true;
	}
	
    if (typeof(microstrategy) == "undefined" || microstrategy.eventManager == null
    		|| (iframe && iframe.onWaitState != false)) {// during partial update
        return true;
    }

    var src = getEventTarget(e);
    
    if(src) {
        var name = src.tagName.toLowerCase();
        if (name == "input" || name == "select" || name == "textarea") return true;
    
        if (microstrategy.EXECUTION_SCOPE != microstrategy.REPORT_EXECUTION) {
            var bone = microstrategy.bone("rwb_viewer");
            if (bone != null && bone.doc != null && currentModalEditor.length == 0) {
                return bone.doc.onkeypress(e);
            }
        }
    }
    return true;

}

/**
 * Listens to all contextmenu events on the window.document element.  If the event target has a CX attribute it will be passed to the 
 *      displayContextMenu function.
 * @param {Event} e The event object (W3C compliant browsers only).
 * @return true
 */
function rightClick(e) {
  // Get the event target element.
  var clickedElement = getEventTarget(e);
  var oTarget = clickedElement;
  oTarget = findTarget(oTarget, 'CX');
  //alert(oTarget.outerHTML);
  // If the target object supports context menus then call the
  // context menu formula.
  if (oTarget) {
    oTarget.clickedElement = clickedElement;
    // Attach the upClick event to the mouse up event to cancel
    // the next mouse up event.
    // document.onmouseup = upClick;
    // Call the display context menu function.
    return displayContextMenu(oTarget, e);
  }
  // Otherwise, return true.
  return true;
}


/**
 * This function shall be called when onKeyDown is triggered on a text box on a form. It will detect if the user pressed &lt;enter&gt; and if so it will
 *      set the focus to the specified object (for example, a button or input image), as if the user requested to submit the form by pressing HTML this element.
 *      This function is currently only used in mstrDatasetExplorerEditorImpl -- good candidate for moving.
 * @param {HTMLElement} obj The input field that received the keydown event.
 * @param {HTMLElement} targetButton The button that should receive focus when the user presses the &lt;enter&gt; key.
 */
function checkForFormSubmit(obj, targetButton){
    var e = window.event;
    if (e != null && e.keyCode == 13){
        var objTargetButton = targetButton;
        if (typeof(objTargetButton) == 'string') {
            objTargetButton = document.getElementById(targetButton);
        }
        if (objTargetButton != null && objTargetButton.focus) {
            objTargetButton.focus();
        }
    }
}

/**
 * This function captures the window.document contextmenu, keydown and keypress events to global event handler functions.  It also has code for the old 
 *      client rendering timer infrastructure.
 */
function Init() {
//*********************************************************************************************
//Purpose: This function gets called by the document onload event
//        and associates the appropriate event handlers.
//Inputs:   None.
//Outputs: None.
//*********************************************************************************************/
  document.oncontextmenu = rightClick;
  document.onkeydown = keyDownHandler;
  document.onkeypress = keyPressHandler;

  if(logClientStopTimer) {
    stopTimer(logClientName);
  }

  if(logClient) {
    logClientTimes(currentUrlObjectID, currentFullURL);
  }
}

/**
 * Updates partial grid CSS in Report Services.  Called once from {@link iframe.updateComponent} -- good candidate for moving.
 * @param {HTMLElement} elem The HTMLElement that contains the STYLE elements.
 * @param {String} cssText The current cssText property for all the grids.
 */
function consolidateStyleSheets(elem, cssText, styleId) {
    var inlineStyles = elem.getElementsByTagName("STYLE");

    //First call from Iframe will be with empty text.
    if (cssText.length == 0) {
        var consolidatedStyle = document.getElementById(styleId + "IFrame");
        if (!consolidatedStyle) {
            consolidatedStyle = document.getElementById(styleId);
        }
        if (consolidatedStyle) {
            cssText = consolidatedStyle.innerHTML;
        }
    }

    if (inlineStyles.length == 0) return cssText;

    for (var i = 0; i < inlineStyles.length; i++) {
        var title = inlineStyles[i].getAttribute("title");
        var componentId = inlineStyles[i].getAttribute("componentid");

        //if it has a title do not consolidate
        if ((!title || title.length == 0) && (componentId && componentId.length > 0)) {
            cssText = replaceStyle(inlineStyles[i], cssText, styleId != 'docObjectStyle');
        }
    }

    return cssText;
}


/**
 * Resets the css in the consolidatedGridStyleSheet using the supplied cssText parameter.  Called once from {@link iframe.replaceComponents} --  good candidate for moving.
 * @param {String} cssText The new cssText for all grids.
 */
function updateStyleContainer(cssText, styleId){
    // called to actually reset the css for the grids
    if (cssText.length == 0) return;

    stylesContainer = document.getElementById(styleId + "Container");
    if (stylesContainer != null){
        var styleObjs = stylesContainer.getElementsByTagName("STYLE");
        if (styleObjs == null || styleObjs.length == 0) {
            // In firefox 2.0, the style tag is part of the head.
            // We need to remove the existing tag.
            var consolidatedStyle = document.getElementById(styleId);
            if(consolidatedStyle){
                consolidatedStyle.parentNode.removeChild(consolidatedStyle);
            }
        }
    } else {
        stylesContainer = document.createElement("div");
        stylesContainer.setAttribute("id", styleId + "Container");
        document.body.appendChild(stylesContainer);
    }
    // Remove the consolidatedGridStyleSheetIFrame before creating the styles again.
    var consolidatedStyleIFrame = document.getElementById(styleId + "IFrame");
    if (consolidatedStyleIFrame){
       consolidatedStyleIFrame.parentNode.removeChild(consolidatedStyleIFrame);
    }

    stylesContainer.innerHTML = "<div>&nbsp;</div><style id=\"" + styleId + "\">" + cssText + "</style>";
}

/**
 * Replaces existing styles with new styles, by component.  Called within a loop from {@link consolidateStyleSheets}.
 * @param {HTMLElement} currentStyle The style tag containing the new style information. 
 * @param {String} cssText The old style information from the consolidated grid stylesheet.
 * @type String
 * @return The newly modified consolidated grid stylesheet style information.
 */
function replaceStyle(currentStyle, cssText, addMarker){
    var componentId = currentStyle.getAttribute("componentid");
        //if it's a component insert the markers
    if (componentId && componentId.length > 0) {
        var marker = "." + componentId + " {";
        if (cssText.indexOf(marker) > -1) {//component already exists, replace style definition
            cssText = cssText.substring(0, cssText.indexOf(marker)) +  marker + "}" + currentStyle.innerHTML + cssText.substring(cssText.lastIndexOf(marker));
        } else {
            if (addMarker) {
                cssText += marker + "}" + currentStyle.innerHTML + marker + "}";
            } else {
                cssText += currentStyle.innerHTML;
            }
        }
    } else {
        cssText += currentStyle.innerHTML;
    }

   return cssText;
}

/**
 * Called from the documents beforeunload event to show client performance logging as well as disconnect from Flash objects in IE6.
 */
function Unload() {
//*********************************************************************************************
//Purpose: This function gets called by the document onbeforeunload event
//Inputs:   None.
//Outputs: None.
//*********************************************************************************************
    // Store a flag for the iframe code so we don't hide the wait page.
    window.isUnloading = true;

    if (typeof(microstrategy) != 'undefined' && typeof(microstrategy.log) != "undefined") {
         // Client performance times, if any
         microstrategy.log.show();
    }

    // For IE6, disconnect FLASH objects...
    if (this.bIsIE6)
    {
        // Disconnect all OBJECT tags...
        this.DisconnectElement("object");
    }
}

/**
 * This function "disconnects" an element (presumed to be either an OBJECT or EMBED) from the JavaScript environment. It does so by iterating over the element, inspecting
 * all function properties and resetting them to empty function bodies.  Called from within {@link Unload} so it could probably be moved there.
 * @param {String} tagName The tag name of the HTMLElements to search for.
 */
function DisconnectElement(tagName) {
    // If we don't have getElementsByTagName, return now...
    if (!document.getElementsByTagName) return;

    // Try to find all elements...
    var elements = document.getElementsByTagName(tagName);

    // Compute the length of the array...
    var len = (elements != null) ? elements.length : 0;

    // Loop through all elements...
    for (var i=0; i < len; i++) {
        // Loop through the properties of the element...
        for (var x in elements[i]) {
            // If it is a function property...
            if (typeof elements[i][x] == 'function') {
                // Reset the function to disconnect it from any JS functions...
                elements[i][x] = function(){};
            }
        }
    }
}

/**
 * Steps through the elements of a form looking for one with the name or id that matches the sField parameter.  Seems like we should be able to do this without looping.
 * Regardless, This method is called once from {@link submitFormSpecial}.  It should be moved to there rather than pollute the global namespace.  
 * @param {HTMLElement} oForm The form to search.
 * @param {String} sField The id or name of the element to search for.
 * @type HTMLElement
 * @return The field if found, otherwise null.
 */
function returnFormField(oForm, sField){
    var col = oForm.elements;
    for (var i = 0, cnt = col.length; i < cnt; i++) {
        var elem = col[i];
        if ((elem.id == sField) || (elem.name == sField)) {
            return elem;
        }
    }
    return null; // not found
}


/**
 * Creates a dynamic FORM element and inserts it into the body of the document.
 * @param {String} sAction The url of the form which may contain parameters.
 * @type HTMLElement
 * @return The newly created and inserted form.
 * @deprecated please use {@link UpdateHelper.createParamsFromURL} instead.
 */
function createDynamicForm(sAction) {
    var oNewForm ;
    var hasParameters = sAction.indexOf('?') > 0;
    var hasRelativeLink = sAction.indexOf('#') > 0;
    var hasSessionId = (microstrategy.sessionId && microstrategy.sessionId != null && microstrategy.sessionId !="");

    //Add a new form
    oNewForm = document.createElement("FORM");
    oNewForm.name = "dynamic_form";
    oNewForm.method = "POST";

    var formAction =  ((hasParameters) ? sAction.substring(0, sAction.indexOf('?')) : sAction);

    if (hasRelativeLink){
       var relativeLink = '';
       sAction = moveAnchor(sAction);
       relativeLink = sAction.substring(sAction.indexOf('#'));
       formAction = formAction.replace(relativeLink,'') + relativeLink;
       sAction = sAction.substring(0,sAction.indexOf('#'));
    }

    //Append session Id. TQMS 267726.
    if(hasSessionId && formAction.indexOf("jsessionid") == -1){
        formAction += ";jsessionid=" + microstrategy.sessionId;
    }

    //Remove request parameters if any and add them as hidden inputs:
    oNewForm.action = formAction;

    if (hasParameters) addURLAsHiddenInputsToForm(oNewForm, sAction);

    //insert the new form after the last form in the list of forms on the document
    document.body.insertAdjacentElement("beforeEnd", oNewForm);

    return oNewForm;

}

/**
 * Creates a new hidden input, populates it's value and inserts it into the supplied form. 
 * @param {HTMLElement} oForm The form that should contain the new input.
 * @param {String} name The name of the new input.
 * @param {String} value The value of the new input.
 * @type HTMLElement
 * @return The new hidden input.
 */
function createHiddenInput(oForm, name, value) {
    var oNewItem = document.createElement("INPUT");
    oNewItem.type="HIDDEN";
    oNewItem.name = name;
    oNewItem.value = value;

    oForm.insertAdjacentElement("beforeEnd", oNewItem);
    return oNewItem;
}

/**
 * Updates a hidden Input in a form. If the input doesn't exist it creates a new one otherwise, it just updates it.
 * @param {HTMLElement} oForm The form that should contain the input to be updated.
 * @param {String} name The name of the input.
 * @param {String} value The value of the input.
 * @param {HTMLElements[]} [oInputs] An array of input fields to search.  If omitted, the form elements will be used.
 * @type Boolean
 */
function updateDynamicInput(oForm, name, value, oInputs) {
    var found = false;
    var i;

    if (!oInputs) oInputs = oForm.getElementsByTagName("input");

    for(i = 0; i < oInputs.length; i++) {
        found = (oInputs[i].name == name);
        if (found) break;
    }

    if(found) {
        oInputs[i].value = value;
    } else {
        createHiddenInput(oForm, name, value);
    }

    return true;
}

/**
 * Submits a form with indicated field values changed.  Seems very similar to submitFormValues.  Seems to be only called in ObjectBrowserBeanImpl so we could probably
 * move it to a better location.
 * @param {String} sFormName The ID of the format to edit and submit.
 * @param {String[]} aFields An array of field names for value modification.
 * @param {String[]} aFieldValues An array of new field values. 
 */
function submitFormSpecial(sFormName, aFields, aFieldValues) {
    //@class=dhtmlAPI;@method=submitFormSpecial;
    var oField = null;
    var bFailed = false;

    var oForm = getObj(sFormName);

    for (i=0; i<aFields.length; i++) {
      // For each one of the fields, look for it on the form
      oField = returnFormField(oForm, aFields[i]);
      if (oField) {
        //alert(aFields[i] + " = " + aFieldValues[i]);
        oField.value = aFieldValues[i];
      }
      else
        bFailed = true;
    }

    if (!bFailed) {
      submitForm(oForm);
    }
}

/**
 * Submits a form with indicated field values changed.  
 * @param {String} sFormName The ID of the format to edit and submit.
 * @param {String[]} aFields An array of field names for value modification.
 * @param {String[]} aFieldValues An array of new field values. 
 */
function submitFormValues(sFormName, aFields, aFieldValues) {
    //@class=dhtmlAPI;@method=submitFormValues;
  var oField = null;
  var bFailed = false;

  var oForm = getObj(sFormName);

  synchForm(oForm);
  for (i = 0, cnt = aFields.length; i < cnt; i++) {
    oField = getObj(aFields[i]);
    if (oField) {
      oField.value = aFieldValues[i];
    }
    else
      bFailed = true;
  }

  if (!bFailed) {
    submitForm(oForm);
  }
}

/**
 * Updates field values on the formula editor form.  Called from FormulaBarTransform -- should be moved to a more appropriate location.
 */
function updatefbNameFormula() {
//*********************************************************************************************
//Purpose: Updates the definition text box in formula editor
//Inputs:   None.
//Outputs: None.
//*********************************************************************************************
  var oTemplateElement = getObj('fbTemplateElement');
  var oName = getObj('fbName');
  var oFormula = getObj('fbFormula');
  var oFormulaSpn = getObj('spnfbFormula');
  var oAvailable = getObj('fbAvailable');
  var oFuncWizard = getObj('tbFunctionWizard');  
  var addButton = document.getElementById("tb_dmAdd");
  oFormula.value = aTemplateElements[parseInt(oTemplateElement.value)][lPropertyFormula];
  if ((parseInt(oTemplateElement.value) == 0) && (aTemplateElements[parseInt(oTemplateElement.value)][lPropertyKey] == '')) {
    oName.value = sNewMetric;
  } else {
    var alias = aTemplateElements[parseInt(oTemplateElement.value)][lPropertyAlias];
    oName.value = alias;
  }

  if (addButton) {
    addButton.className = addButton.className.replace("Disabled", "");
  }


  if ((aTemplateElements[parseInt(oTemplateElement.value)][lPropertyDerivedMetric] == 'false') ||
      (aTemplateElements[parseInt(oTemplateElement.value)][lPropertyDerivedMetricType] == '101')) {
    oFormula.readOnly = true;
    oFormula.className = "disabled";
    oFormulaSpn.setAttribute('TG', 'FALSE');
    oAvailable.disabled = true;
    oAvailable.selectedIndex = -1;
    // TQMS 358621: Function Wizard should be disabled when an attribute in the 'Insert New Metric...' window is selected.
    if( oFuncWizard ){
        oFuncWizard.style.display = "none";
    }
    if (addButton) {
        addButton.className += "Disabled";
    }
  }
  else {
    oFormula.readOnly = false;
    oFormula.className = "";
    oFormulaSpn.setAttribute('TG', 'TRUE');
    oAvailable.disabled = false;
    if (oFuncWizard) oFuncWizard.style.display = "block";
  }
}

/**
 * Updates field values on the formula editor form.  Called from FormulaBarTransform -- should be moved to a more appropriate location.
 */
function addToFormula() {
     var oFormula = getObj('fbFormula');
     var oAvailable = getObj('fbAvailable');
     if (oAvailable) {
        if (!oAvailable.disabled  && oAvailable.selectedIndex>=0 && oAvailable.options[oAvailable.selectedIndex]) {
            if (oFormula) {
                oFormula.focus();
                if(document.selection && document.selection.createRange){
                    var sel = document.selection.createRange();
                    sel.text = oAvailable.options[oAvailable.selectedIndex].value;
                }else{
                oFormula.value += oAvailable.options[oAvailable.selectedIndex].value;
            }
        }
     }
}
}

/**
 * Changes the state of a tristate simulated checkbox.  Not sure we use this anymore as it seems to only be called from GridFormatEditorBeanImpl.
 * @param {HTMLElement} oCheck The simulated checkbox to change.
 * @param {Boolean} [useDefault] Indicates whether to show the conflict state or default to off.  Doesn't seem to be used anywhere.
 */
function toggleCheck(oCheck, useDefault) {
  var chkState = oCheck.getAttribute("CV");
  var oHidden = getObj(oCheck.getAttribute("CL"));
  
  chkState--;
  if (chkState < -2) chkState = 0;
  
  switch (chkState) {
    case -1:
      oCheck.src = microstrategy.FOLDER_IMAGES + 'check_on.gif';
      break;
    case 0:
      oCheck.src = microstrategy.FOLDER_IMAGES + 'check_off.gif';
      break;
    case -2:
      if (useDefault) {
          oCheck.src = microstrategy.FOLDER_IMAGES + 'Check_conflict.gif';
      } else {
          // There's no default, so from On it will change to Off
          chkState = 0;
          oCheck.src = microstrategy.FOLDER_IMAGES + 'check_off.gif';
      }
      break;
  }
  oCheck.setAttribute("CV", chkState);
  oHidden.value = chkState;
}

/**
 * Synchronizes the values of the MicroStrategy State ID, Message ID and View fields for the supplied form.  Only called from {@link submitFormValues} so we should 
 * probably move it into that function to reduce global scope.
 * @param {HTMLElement} oForm The form to synchronize. 
 */
function synchForm(oForm) {
  var sField = '';
  var ocHidden = oForm.getElementsByTagName('INPUT');
  for (i = 0, cnt = ocHidden.length; i < cnt; i++) {
    sField = ocHidden[i].name;
    sField = sField.toUpperCase();
    switch (sField) {
      case 'INDEX':
        ocHidden[i].value = lStateID;
        break;
      case 'MSGID':
        ocHidden[i].value = sMsgID;
        break;
      case 'VIEW':
        ocHidden[i].value = sView;
        break;
    }
  }
  return true;
}

/**
 * Returns a reference to an HTMLElement specified by the vObject parameter.
 *   - There are now 852 references, will not replace references with document.getElementById.
 * 
 * @param {String|HTMLElement} vObject The ID of the requested HTMLElement or a reference to the actual element.
 * @return The requested HTMLElement.
 * @deprecated Please use document.getElementById.
 */
function getObj(vObject) {
    return (typeof vObject == 'string') ? document.getElementById(vObject) : vObject;
}

/**
 * Replaces the document.getElementById method for IE because the native implementation can return a collection.  
 * @param {String} id The ID of the requested HTMLElement
 * @return HTMLElement
 * @refactoring It should be optimized to use the native implementation for W3C compliant browsers.  We should also verify that it is still an issue. 115 references.
 */
function getElementById(id) {
    var obj = document.getElementById(id);
    if (mstr.utils.ISW3C || obj == null) return obj;

    // SELECT and other tags might have length property - test for tagName
    if (!obj.length || typeof(obj.tagName) != 'undefined') obj = [obj];

    for (var i = 0, cnt = obj.length; i < cnt; i++) {
        if (obj[i].id.length > 0) return obj[i];
    }

    return null;
}

/**
 * Calculates the width of the browser window's document area, excluding vertical scrollbar if any.
 * @type Integer
 * @return The width of the browser window's document area.
 * @deprecated Please use {@link mstr.utils.BoxModel.getBrowserWindowWidth}. 
 */
function getClientWidth() {
    var dim = mstr.utils.BoxModel.getBrowserWindowWidth(document);
    return (bIsIE7) ? (dim - SCROLLBAR_SIZE + 5) : dim;
}

/**
 * Calculates the height of the browser window's document area, excluding horizontal scrollbar, if any.
 * @type Integer
 * @return The inner height of the browser window's document area.
 * @deprecated Please use {@link mstr.utils.BoxModel.getBrowserWindowHeight}. 
 */
function getClientHeight() {
    return mstr.utils.BoxModel.getBrowserWindowHeight(document);
}

/**
 * Returns the documents scrollTop value.
 * @type Integer
 * @return The scrollTop.
 */
function getDocumentScrollTop() {
    var de = document.documentElement;
    return (de && de.scrollTop) ? de.scrollTop : document.body.scrollTop;
}

/**
 * Returns the documents scrollLeft value.
 * @type Integer
 * @return The scrollLeft.
 */
function getDocumentScrollLeft() {
    var de = document.documentElement;
    return (de && de.scrollLeft) ? de.scrollLeft : document.body.scrollLeft;
}

/**
 * Calculates the width of an HTMLElement without including it's borders.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The inner width of the HTMLElement.
 * @deprecated Please use {@link mstr.utils.BoxModel.getElementInnerWidth}. 
 */
function getObjInnerWidth(vObject) {
    return mstr.utils.BoxModel.getElementInnerWidth(getObj(vObject));
}

/**
 * Calculates the width of an HTMLElement including it's borders.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The outer width of the HTMLElement.
 * @deprecated Please use {@link mstr.utils.BoxModel.getElementOuterWidth}. 
 */
function getObjOuterWidth(vObject) {
    return mstr.utils.BoxModel.getElementOuterWidth(getObj(vObject));
}

/**
 * Calculates the width of an HTMLElement.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The width of the HTMLElement.
 * @deprecated I think this is the same as {@link mstr.utils.BoxModel.getElementOuterWidth}.
 */
function getObjWidth(vObject) {
    return  mstr.utils.BoxModel.getElementOuterWidth(getObj(vObject));
}


/**
 * Calculates the height of an HTMLElement without including it's borders.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The inner height of the HTMLElement.
 * @deprecated Please use {@link mstr.utils.BoxModel.getElementInnerHeight}. 
 */
function getObjInnerHeight(vObject) {
    return mstr.utils.BoxModel.getElementInnerHeight(getObj(vObject));
}

/**
 * Calculates the height of an HTMLElement including it's borders.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The outer height of the HTMLElement.
 * @deprecated Please use {@link mstr.utils.BoxModel.getElementOuterHeight}. 
 */
function getObjOuterHeight(vObject) {
    return mstr.utils.BoxModel.getElementOuterHeight(getObj(vObject));
}

/**
 * Calculates the height of an HTMLElement.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The height of the HTMLElement.
 * @deprecated I think this is the same as {@link mstr.utils.BoxModel.getElementOuterHeight}.
 */
function getObjHeight(vObject) {
    return  mstr.utils.BoxModel.getElementOuterHeight(getObj(vObject));
}

/**
 * Calculates the computed top position of an element.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The top position of the HTMLElement.
 * @deprecated Please use {@link mstr.utils.BoxModel.getElementTop}.
 */
function getObjTop(vObject) {
    return mstr.utils.BoxModel.getElementTop(getObj(vObject));
}

/**
 * Calculates the computed top position of an element relative to the body element.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The summed top position of the HTMLElement.
 * @deprecated Please use {@link mstr.utils.BoxModel.getElementSumOffsetTop}.
 */
function getObjSumTop(vObject) {
    return mstr.utils.BoxModel.getElementSumOffsetTop(getObj(vObject), document.body);
}

/**
 * Calculates the computed top position of an element relative to the body element, including the amount any ancestor may be scrolled.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The summed and scrolled top position of the HTMLElement.
 */
function getObjSumTopScrolled(vObject) {
    try {
        var obj = getObj(vObject);
        var lTop = 0;    
            for (var i = 0; (obj); i++) {
                lTop += obj.offsetTop;
                if (obj.offsetParent && obj.offsetParent.scrollTop && obj.offsetParent.tagName.toLowerCase() != 'html') {
                    lTop -= obj.offsetParent.scrollTop;
                }
                obj = obj.offsetParent;
            }
            return parseInt(lTop);            
    }
    catch(err) {
        microstrategy.errors.log(err);
        return 0;
    }
}

/**
 * Calculates the computed left position of an element.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The left position of the HTMLElement.
 * @deprecated Please use {@link mstr.utils.BoxModel.getElementLeft}.
 */
function getObjLeft(vObject) {
    return mstr.utils.BoxModel.getElementLeft(getObj(vObject));
}

/**
 * Returns the offsetLeft for IE and the computed left position for all other browsers.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The offsetLeft of the HTMLElement.
 */
function getObjOffsetLeft(vObject) {
    var obj = getObj(vObject);
    if (obj){
        return (bIsIE4)? obj.offsetLeft : mstr.utils.BoxModel.getElementLeft(obj);
    }
}

/**
 * Calculates the computed left position of an element relative to the body element.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The summed left position of the HTMLElement.
 * @deprecated Please use {@link mstr.utils.BoxModel.getElementSumOffsetLeft} for Firefox and IE8.
 */
function getObjSumLeft(vObject) {
    var obj = getObj(vObject);
    var lLeft = 0;

    //GBCHANGE: IE6 has bug with offsets and floating CSS styles
    if (obj && (obj.getClientRects || obj.getBoundingClientRect) && !mstr.utils.ISIE8) {
        lLeft = obj.getBoundingClientRect ? obj.getBoundingClientRect().left : obj.getClientRects()[0].left;
        lLeft = lLeft - 2 + getDocumentScrollLeft();
        return Math.round(lLeft);
    }

    return  mstr.utils.BoxModel.getElementSumOffsetLeft(getObj(vObject), document.body)
}

/**
 * Calculates the computed left position of an element relative to the body element, including the amount any ancestor may be scrolled.
 * @param {String|HTMLElement} vObject The HTMLElement to measure.
 * @type Integer
 * @return The summed and scrolled left position of the HTMLElement.
 */
function getObjSumLeftScrolled(vObject) {
    try {
        var obj = getObj(vObject);
        var lLeft = 0;
        for (var i=0; (obj); i++) {
            lLeft += obj.offsetLeft;
            if (obj.offsetParent && obj.offsetParent.scrollLeft && obj.offsetParent.tagName.toLowerCase() != 'html') {
                lLeft -= obj.offsetParent.scrollLeft;
            }
            obj = obj.offsetParent;
        }
        return parseInt(lLeft);
    } catch(err) {
        return 0;
    }
}


/**
 * Queries the Event object to determine which mouse button was pushed.
 * @param {Event} e The Event.
 * @type Integer
 * @return 1 for left button, 2 for right button.
 * @deprecated Access the button property directly (only used twice). However We might need this since Firefox return 0 on left button click
 */
function getButtonId(/**Event*/ e) {
    if (bIsIE4 && e) return e.button;
    if (bIsW3C && e) return (e.button < 2) ? 1 : 2;
    else return 1;
}

/**
 * Moves the supplied object to a new position.
 * @param {String|HTMLElement} vObject The object to be moved.
 * @param {Integer} iX The new left coordinate.
 * @param {Integer} iY The new top coordinate.
 * @deprecated Set the left and top directly, e.g. foo.style.left = '12px'.
 */
function moveObjTo(vObject, iX, iY) {
    var obj = getObj(vObject);
    if (obj != null) {
        var x = parseInt(iX);
        var y = parseInt(iY);
        if (!isNaN(x) && !isNaN(y)) {
            obj.style.left = x + "px";
            obj.style.top = y + "px";
        }
    }
}


/**
 * Sets the display style property of the given object such that it will be present in the flow of the document.
 * @param {String|HTMLElement} vObject The object to be displayed.
 * @deprecated Please set the display directly, e.g. foo.style.display = 'block'.
 */
function displayObj(vObject) {
    var obj = getObj(vObject);
    if (obj) {
        //Firefox won't display it properly if TABLE is set with style display:block; this change is currently for ribbon menu bar
        obj.style.display = (bIsFirefox && obj.tagName.toLowerCase() == 'table') ? 'table': "block";
        obj.style.visibility = 'visible';
    }
}

/**
 * Sets the display style property of the given object such that it will not be present in the flow of the document.
 * @param {String|HTMLElement} vObject The object to be removed from the flow of the document.
 * @deprecated Please set the display directly, e.g. foo.style.display = 'none'.
 */
function removeObj(vObject) {
    var obj = getObj(vObject);
    if (obj) {
        obj.style.display = "none";
        obj.style.visibility = 'hidden';
    }
}

/**
 * Determines if a given reference is present in the DOM tree.
 * @param {HTMLElement|String} vObject An HTMLElement reference.
 * @type Boolean
 * @return true if the HTMLElement is in the DOM, false if not.
 */
function isInDocument(vObject) {
    if (!vObject) return false;
    var obj = getObj(vObject);
    if (!obj) return false;
    if (!obj.parentNode) return false;
    if (bIsW3C) return (obj.ownerDocument == window.document);
    return (obj.document == window.document);
}

/**
 * Stores the mouse coordinates in the global lMouseX and lMouseY fields.
 * @param {Event} e The Event object associated with the mouse event.
 */
function getMouse(e) {
    if (bIsIE4) {
        lMouseX = event.clientX + getDocumentScrollLeft();
        lMouseY = event.clientY + getDocumentScrollTop();
    }
    else if (bIsW3C && e != null) {
        lMouseX = e.pageX;
        lMouseY = e.pageY;
    }
}

/**
 * Sets the supplied message as the innerHTML of a specified HTMLElement. 
 * @param {String} sMessage The new html.
 * @param {String|HTMLElement} sDivID The ID of, or reference to, the target HTMLElement. 
 */
function writeToDiv(sMessage, sDivID) {
    var oDiv = getObj(sDivID);
    if (oDiv) oDiv.innerHTML = sMessage;
}

/**
 * Extracts the target of the Event.
 * @param {Event} e The Event in question.
 * @type HTMLElement
 * @return The target of the supplied Event.
 */
function getEventTarget(e) {
    try {
        if (bIsW3C && !bIsIE8 && e) {
            if (!e) return null;

            var target = e.target;
            if (typeof(e.target) == 'function') target = e.target();
            if (bIsW3C && target.tagName == 'scrollbar') target = target.parentNode;
            if (target.nodeType == 3) target = target.parentNode;

            return target;
        }
        else if (bIsIE4) {
            return event.srcElement;
        }
    } catch(err) { /* keyDownHandler triggering from a flash object is an example of when we might end up coming here. */ }
        
    return null;
}

/**
 * Cancels Event bubbling for all browsers.
 * @param {Event} e The Event to cancel.
 */
function stopEventBubbling(/**Event*/ e) {
    if (e) {
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
    }    
}

/**
 * Cancels the default action for all browsers.
 * @param {Event} e The Event to cancel.
 */
function cancelEvent(e) {
    if (bIsW3C && !bIsIE8) e.preventDefault();
    else if (bIsIE4) event.returnValue = false;
}

/**
 * Searches through all the attributes of the given HTML node and checks if the given attribute is present within the node. This function is there because using the DOM
 * getAttribute API will not work in our case as it returns an empty string when the attribute does not exist. In certain cases(e.g CX attribute), we do have attributes
 * with empty string values so it becomes difficult to determine the presence of such attributes using the getAttribute API.
 * @param {HTMLElement} oTarget The HTMLElement with which to begin the search.
 * @param {String} sFind The name of the attribute we are looking for.
 * @param {String} sValue The value of the named attribute.
 * @type Boolean
 * @returns True if the attribute was found.
 */
function isAttributePresent(oTarget, sFind, sValue)
{
    var att = oTarget.attributes && oTarget.attributes.getNamedItem(sFind);
    if (!att || !att.specified) return false;
    if (sValue) return (att.nodeValue == sValue);
    return true;
}

/**
 * Steps up through the DOM tree looking for a node with the attribute and attribute value supplied.
 * @param {HTMLElement} oTarget The HTMLElement with which to begin the search.
 * @param {String} sFind The name of the attribute we are looking for.
 * @param {String} sValue The value of the named attribute.
 * @type HTMLElement
 * @return The found HTMLElement, or null.
 */
function findTarget(oTarget, sFind, sValue) {
    while (oTarget) {
        if (isAttributePresent(oTarget, sFind, sValue)) return oTarget;
        oTarget = oTarget.parentNode;
    }
    return null;
}

/**
 * Steps up through the DOM tree looking for a node with the given tag name.
 * @param {HTMLElement} oTarget The HTMLElement with which to begin the search.
 * @param {String} sTagName The tag name of the target element.
 * @type HTMLElement
 * @return The HTMLElement if found, otherwise, null.
 */
function findTargetTag(oTarget, sTagName) {
    while (oTarget.parentNode) {
        if (oTarget.nodeName.toLowerCase() == sTagName.toLowerCase()) return oTarget;
        oTarget = oTarget.parentNode;
    }
    return null;
}

/**
 * Enables/Disables an HTMLElement by setting it's className and disabled property to given value.
 * 
 * @param {HTMLElement|String} vObject The ID of, or reference to, the HTMLElement to be enabled. 
 * @param {String} cssClass The new className value.
 * @param {Boolean} status The new value for disabled property.  
 */
function toggleElement(vObject, cssClass, enabled){
    var obj = getObj(vObject);
    if (obj) {
        obj.disabled = !enabled;
        if (cssClass.length > 0) obj.className = cssClass;
    }
}

/**
 * Appends URL values as hidden inputs to the supplied form.
 * @param {HTMLElement} oForm The form that will receive the new hidden inputs.
 * @param {String} URL The URL with the parameters and values to be added to the form.
 * @param {Boolean} replaceInputs Indicates whether to replace or update any existing hidden inputs.
 * @type Boolean
 * @return false
 * @deprecated please use {@link UpdateHelper.addURLToParams} instead
 */
function addURLAsHiddenInputsToForm(oForm, URL, replaceInputs){
    if (oForm.nodeName != "FORM") {
        oForm = findTargetTag(oForm, "FORM");
    }

    URL = URL.substring(URL.indexOf("?") + 1,URL.length);
    var URLParameters = URL.split("&");
    var temp = "";
    var parameterName = "";
    var parameterValue = "";

    //Replace ALL + characters with space. The reason for that is the unescape function does not take care of this conversion.
    //That function just converts all strings of format %HH to the character value of the HH hex value
    //Our URL encoding codes spaces to + characters. Hence we have to reverse that effect over here.
    var myRegExp = /\+/g;

    for (var i = 0, cnt = URLParameters.length; i < cnt; i++) {
        temp = URLParameters[i].split("=");
        parameterName = temp[0];
        parameterValue = temp[1];

        if (parameterValue) {
            parameterValue = decodeURIComponent(parameterValue.replace(myRegExp, ' '));
        }

        if (replaceInputs) {
            updateDynamicInput(oForm, parameterName, parameterValue)
        } else {
            createHiddenInput(oForm, parameterName, parameterValue);
        }
    }
    return false;
}

/**
 * Used for Exporting RWDs to Excel. Shows a message for Office Excel.
 * @param {String} href A URL containing parameters to be added to the export form.
 * @param {String} target The form target.
 */
function openExport(href, target) {
    if (typeof(microstrategy) != 'undefined' && microstrategy.EXECUTION_SCOPE == microstrategy.RWD_EXECUTION &&
        microstrategy.bones["rwb_viewer"] && microstrategy.bones["rwb_viewer"].isFeatureAvailable(microstrategy.FEATURE_USE_OFFICE) &&
        (microstrategy.IS_RWD_DIRTY == microstrategy.TRUE || hasRWDChanged())) { // rwd and office-excel and (isDirty or hasChanged)
        showMessage({contents:microstrategy.descriptors.getDescriptor("3809"), elements:microstrategy.OK_BUTTON + microstrategy.CANCEL_BUTTON, okEval:"submitExportForm('" + href + "','" + target + "');", type:mstrMsgBoxImpl.MSG_WARNING});
    } else {
        submitExportForm(href, target);
    }
}

/**
 * This is used to know if the RWD has changed. Used for exporting RWDs.  We do this by checking if there are any actions on the Update Manager that are 
 * different than the FIX STATE event.  This is done because, every time we export we add the FIX_STATE event but the RWD has not changed (issue 211454).
 */
function hasRWDChanged() {
    if (typeof(microstrategy) != 'undefined' && microstrategy.updateManager) {
        var um = microstrategy.updateManager;

        // undo actions
        for (var i = 0, cnt = um.undoActions.length; i < cnt; i++) {
            var actionCol = um.undoActions[i];
            if (actionCol == mstrUpdateManager.STATIC_ACTION) continue;

            for (var a = 0, cnt2 = actionCol.length; a < cnt2; a++) {
                if (actionCol[a].id != mstrUpdateManager.FIX_STATE) return true;
            }
        }
    }
    return false;
}


/**
 * Submits form for PDF and Excel.  Before sending the form it submits an empty form to avoid an issue with IE.
 * @param {String} href A URL containing parameters to be added to the export form.
 * @param {String} target The form target.
 * @param {Boolean} useGet Indicates whether the form should use GET or POST.
 * @param {Boolean} dontShowEmptyForm Indicates whether to omit the IE only empty form. 
 * @return false
 */
function submitExportForm(href, target, useGet, dontShowEmptyForm) {
    //@class=dhtmlAPI;@method=submitExportForm;
    if (!href) return;
    if (!dontShowEmptyForm && (bIsIE6 && target != "_blank")) {
        if (target == "_blank") target = Date.parse(new Date()); // set it to some unique ID as we want the empty window to be reused by the form submission
        submitEmptyForm(target);
        window.setTimeout("submitExportForm('" + href + "','" + target + "', " + useGet + ", true);", 500);
        return;
    }
    var oNewForm = createDynamicForm(href);
    if (target != '') oNewForm.target = target;
    if (useGet) oNewForm.method = "get";

    // Add unique id to form's action. Issue 204358.
    oNewForm.action = oNewForm.action + "?name=" + Date.parse(new Date());

    if (typeof(microstrategy) != 'undefined' && (microstrategy.EXECUTION_SCOPE == microstrategy.REPORT_EXECUTION) && microstrategy.IN_OUTLINE_MODE) {
        var rb = microstrategy.bone("UniqueReportID");
        if (rb != null && rb.outlineMode != null) {
            var state = rb.outlineMode.getExpansionState('UniqueReportID');
            if (state.length > 0) {
                createHiddenInput(oNewForm, "PDFOutlineModeState", state);
            }
        }
    }

    if (target == '_new') iframe.hideWaitPage();

    submitForm(oNewForm);
    return false;
}

/**
 * Exports a Report Services document.
 * @param {Integer} execMode The export mode (PDF, Excel, etc).
 * @param {String} target The form target.
 * @param {Boolean} dontShowMsg Indicates whether to omit the Office or Flash message.
 * @param {Boolean} dontShowOptions Indicates whether to omit the export options for Excel and PDF.
 * @param {Boolean} dontShowEmptyForm Indicates whether to omit the IE only empty form. 
 */
function exportRW(execMode, target, dontShowMsg, dontShowOptions, dontShowEmptyForm) {
    var docViewer = microstrategy.getViewerBone();
    if (!docViewer) return;
    
    // - Show Warning Message based on the exec mode
    if (!dontShowMsg) { 
        if (execMode == microstrategy.EXEC_MODE_EXCEL) { // - Office message
           if (docViewer.isFeatureAvailable(microstrategy.FEATURE_USE_OFFICE) && (microstrategy.IS_RWD_DIRTY == microstrategy.TRUE || hasRWDChanged())) { // rwd and office-excel and (isDirty or hasChanged)
                showMessage({contents:microstrategy.descriptors.getDescriptor("3809"), elements:microstrategy.OK_BUTTON + microstrategy.CANCEL_BUTTON, okEval:"exportRW(" + execMode + ",'" + target + "',true," + dontShowOptions + "," + dontShowEmptyForm + ");", type:mstrMsgBoxImpl.MSG_WARNING});
                return;
           }
        } else if (execMode == microstrategy.EXEC_MODE_FLASH && bIsIE6 && microstrategy.FlashExportFileFormat == '0') { // - Flash message
            showMessage({contents:microstrategy.descriptors.getDescriptor("5873"), elements:microstrategy.OK_BUTTON , okEval:"exportRW(" + execMode + ",'" + target + "',true," + dontShowOptions + "," + dontShowEmptyForm + ");", type:mstrMsgBoxImpl.MSG_WARNING});//Descriptor: You need to save the exported file locally before you can open it
            return;
        }
    }
    
    // - Show export options for excel and PDF
    if (execMode == microstrategy.EXEC_MODE_EXCEL || execMode == microstrategy.EXEC_MODE_PDF) {
        if (!dontShowOptions && 
            docViewer.isFeatureAvailable("show-rw-export-options") && // property
            (docViewer.isFeatureAvailable("is-multi-layout-doc") || // multilayout
            (!docViewer.containsGroupByDifferentThanAll && docViewer.isFeatureAvailable("show-groupby-for-export") || (docViewer.containsGroupByDifferentThanAll && docViewer.containsGroupByDifferentThanAll()))) // groupby different than all (Flash - client side, Non-Flash - use Server side feature)
            ) {        
            var p = (execMode == microstrategy.EXEC_MODE_PDF) ? "&isPDF=true" : '';
            toggleShowBean("exportOptionsEditor", true, "executionMode=" + execMode + p);
            return;
        }
    }
    
    // - Empty form (issue 203160)
    if (!dontShowEmptyForm && (bIsIE6 && target != "_blank")) {
        submitEmptyForm(target); 
        window.setTimeout("exportRW(" + execMode + ",'" + target + "'," + dontShowMsg + "," + dontShowOptions + ",true);", 500);
        return;
    }
        
    // -- EXPORT -- 
    // remember update manager's old values
    var newWindowOldValue = microstrategy.updateManager.newWindow;
    var windowNameOldValue = microstrategy.updateManager.newWindowName;
    var actionFormOldValue = microstrategy.updateManager.getFormAction();
    var fixStateActions = microstrategy.updateManager.getFixStateActions();
    
    // First part here is for the new popup export window
    microstrategy.updateManager.newWindow = true;
    microstrategy.updateManager.newWindowName = target;
    microstrategy.updateManager.setFormAction(microstrategy.servletName + "?name=" + Date.parse(new Date())); // Add unique id to form's action. Issue 204358
    microstrategy.updateManager.add(getRWExportActionObject(execMode), true);
    microstrategy.updateManager.flushAndSubmitChanges();
    // resetting update manager to previous values
    // Second part is for the original RW document window, which
    // gets invoked the second and subsequent times export is
    // called.
    microstrategy.updateManager.newWindow = newWindowOldValue;
    microstrategy.updateManager.newWindowName = windowNameOldValue;
    microstrategy.updateManager.setFormAction(actionFormOldValue);
    microstrategy.updateManager.acknowledgeRequest();
    microstrategy.updateManager.add([microstrategy.updateManager.createActionObject(this.elem, mstrUpdateManager.FIX_STATE, microstrategy.getViewerBone().beanPath, [], [], [], [])], true);
    microstrategy.updateManager.add(fixStateActions, true);
}

/**
 * Creates an Update Manager action collection populated for exporting.
 * @param execMode
 * @type String[]
 * @return An Update Manager action collection.
 */
function getRWExportActionObject(execMode) {
    if (execMode == '-1') {
        return [microstrategy.updateManager.createActionObject(this.elem, mstrUpdateManager.RW_HTML_EXPORT, microstrategy.servletName, [], [], [], [])];
    } else {
        return [microstrategy.updateManager.createActionObject(this.elem, mstrUpdateManager.RW_FAST_EXPORT, microstrategy.servletName, ["3115"], [execMode], [], [])];
    }
}

/**
 * Submits an empty export form do prevent an IE issue (TQMS #203160).
 * @param {String} target The form target.
 */
function submitEmptyForm(target) {
    var oNewForm = createDynamicForm("../html/Empty.html");
    oNewForm.target = target;
    oNewForm.method = "GET";
    oNewForm.submit();
}

/**
 * Submits a form with the MicroStrategy page state appended as hidden inputs.
 * @param {HTMLElement} oForm The form to be submitted.
 * @param {Boolean} noXHR [true] indicating that we really want to do a true form.submit but not xhr calls, this is used in Filter2.js and several other places
 * @return false
 */
function submitForm(oForm, noXHR) {
    //@class=dhtmlAPI;@method=submitForm;
    var stateForm = getObj('pageStateForm');
    var aInputs = null;
    var aOriginalInputs = null;
    var i;
    var j;
    var oNewItem;
    var found;

    appendPageState(oForm);

    //Add the selections to the form
    if (typeof(microstrategy) != 'undefined' && typeof(microstrategy.bones["rwb_viewer"]) != 'undefined' && microstrategy.EDIT_MODE == microstrategy.ALLOW_EDIT_MODE){
        var docViewer = microstrategy.bones["rwb_viewer"];

        updateDynamicInput(oForm, "docSelections", docViewer.commands.queryState('selectionsKey'));

        docViewer.adjustScrollValues();

        //updateDynamicInput(oForm, "viewerScroll", docViewer.elem.scrollTop + "," + docViewer.elem.scrollLeft);
        updateDynamicInput(oForm, "viewerScroll", docViewer.dScrollTop + "," + docViewer.dScrollLeft);
        var ctrlToolbar = microstrategy.bones["rwControlsToolbar"];
        if (ctrlToolbar != null){
            updateDynamicInput(oForm, "isLocked", (ctrlToolbar.locked)?1:0);
            if(ctrlToolbar.selected && ctrlToolbar.selected.id) {
                updateDynamicInput(oForm, "currentControl",ctrlToolbar.selected.id);
            }
        }
    }

    if (typeof(microstrategy) != 'undefined' && microstrategy.DISPLAY_MODE == microstrategy.VIEW_MODE && microstrategy.EDIT_MODE == microstrategy.ALLOW_EDIT_MODE){
        for (var id in microstrategy.bones){
            if(microstrategy.bones[id] != null && microstrategy.bones[id].type == microstrategy.OBJTYPE_GRID){
                var gridBone = microstrategy.bones[id];
                if (gridBone && gridBone.gridStructureInfo && !gridBone.gridStructureInfo.emptyCase && !gridBone.gridStructureInfo.isEmptyTemplate){
                    if(gridBone.isGrid) {
                        var value = gridBone.commands.queryState('selections');
                        if (value) updateDynamicInput(oForm,gridBone.id, value);
                    }
                    if(gridBone.isGraph && id.indexOf('_graph')==-1) updateDynamicInput(oForm,gridBone.id+'_gs', gridBone.commands.queryState('graphSelections'));                    
                }
            }
        }
    }

    //FOR DEBUG:
    if (false) {
        var aInputs = oForm.getElementsByTagName('INPUT');
        var s = '';

        for (i = 0; i < aInputs.length; i++) {
            s += aInputs[i].name + ": " + aInputs[i].value + "\n";
        }

        var start = 0;

        while (start < s.length) {
            alert(s.substr(start, 5000));
            start += 5000;
        }

    }

    //@todo: this is a hack so that most of partial update request in our app can leverage the XHR transoprt right-away        
    if(oForm.target == 'frameManager' && useXHR && !noXHR) {        //partial update
        if(microstrategy.updateManager){
            microstrategy.updateManager.submitPartialUpdate(UpdateHelper.createParamsFromForm(oForm));
        }
    } else {
        try {
            oForm.submit();
        } catch(err) {
            if (oForm.target != '' && !window.open('','','width=1,height=1,left=0,top=0,scrollbars=no')) {
                // Issues 329572 & 329572. The only cause I know of a failure is if the popup blocker is enabled 
                // To double check, I attempt to call a window.open and if this fails then I tell the user to enable popups on the browser 
                showMessage({contents:microstrategy.descriptors.getDescriptor("5877"), elements:microstrategy.OK_BUTTON, type:mstrMsgBoxImpl.MSG_WARNING}); //Descriptor: This action requires popups to be allowed in the browser
            } else {
                microstrategy.errors.log(err);
            }
        }
    }

    return false;
}

/**
 * Appends the MicroStrategy page state to the supplied form.
 * @param {HTMLElement} oForm The form that should have the page state appended as hidden inputs.
 * @deprecated please use {@link UpdateHelper.appendPageStateToParams} instead.
 */
function appendPageState(oForm) {
    //@class=dhtmlAPI;@method=appendPageState;
    var stateForm = getObj('pageStateForm');
    var aInputs = null;
    var aOriginalInputs = null;
    var i;

    if (typeof(microstrategy) != 'undefined' && microstrategy.updateManager && microstrategy.updateManager.hasChangesToSubmit()) {
        microstrategy.updateManager.flushChanges(oForm);
        //Make form capable to handle multiple events
        addEvtOrder(oForm, mstrUpdateManager.multipleEventID);
    }

    if (stateForm) {
        if (oForm.method == "get" || oForm.method == "GET") {
            addURLAsHiddenInputsToForm(oForm, pageState, true);
        } else {
            aInputs = stateForm.getElementsByTagName('INPUT');
            aOriginalInputs = oForm.getElementsByTagName('INPUT');

            for (i = 0, cnt = aInputs.length; i < cnt; i++) {
               updateDynamicInput(oForm, aInputs[i].name, aInputs[i].value, aOriginalInputs);
            }
        }
    }
}

/**
 * Calls {@link mstrUpdateManager.flushAndSubmitChanges} and then {@link submitLink} for the supplied anchor tag.
 * @param {HTMLElement} oAnchor
 */
function updateAndSubmitLink(oAnchor) {
    microstrategy.updateManager.flushAndSubmitChanges();
    submitLink(oAnchor);
    return;
}

/**
 * Calls {@link submitLink} for the supplied anchor tag and then also calls window.open using the same anchor tag.
 * @param {HTMLElement} oAnchor
 */
function openLink(oAnchor) {
    submitLink(oAnchor);
    window.open(oAnchor.href, oAnchor.target);
    return false;
}

/**
 * Calls {@link updateLink} for the supplied anchor tag and then also calls window.open using the same anchor tag.
 * @param {HTMLElement} oAnchor
 */
function updateAndOpenLink(sUrl, sTarget){
    var newUrl = updateLink(sUrl);
    window.open(newUrl, sTarget);
    iframe.hideWaitPage();
    return false;
}

/**
 * Replaces all the MicroStrategy page state parameters in the supplied url.
 * @param {String} oldUrl The url to have it's page state parameters replaced.
 * @type String
 * @return The URL with the new page state.
 */
function updateLink(oldUrl){
    var sResultURL = oldUrl;
    var sURL = pageState;
    var endPos, nextPos, currParam, currValue;

    if (sURL) {
        while((endPos = sURL.indexOf("=")) >= 0) {
            currParam = sURL.substr(0, endPos);
            currValue = ((nextPos = sURL.indexOf("&")) >= 0) ? sURL.substr(endPos + 1, nextPos - endPos - 1) : sURL.substr(endPos + 1);
            sResultURL = replaceURLParameter(sResultURL, currParam, currValue);
            sURL = (nextPos >= 0) ? sURL.substr(nextPos + 1) : "";
        }
    }
    return sResultURL;
}
/**
 * Creates an Update Manager action collection to hide/show the indicated bean. 
 * @param {String} beanName The name of the bean to toggle.
 * @param {Boolean} show Whether to show or hide the bean.
 * @param {String} args A URL with parameters that gets added to the Update Manager.
 * @type Boolean
 * @return false
 */
function toggleShowBean(beanName, show, args, noXHR) {
    if (typeof(microstrategy) != 'undefined' && microstrategy.updateManager) {
        var actionCollection = new Array();
        actionCollection.push(microstrategy.updateManager.createActionObject(null, mstrUpdateManager.SHOW_BEAN, microstrategy.servletName + "." + microstrategy.pageName, ["5017","5018"], [show,beanName], []));
        microstrategy.updateManager.add(actionCollection);
        microstrategy.updateManager.addURL(args);
        microstrategy.updateManager.flushAndSubmitChanges(noXHR);
    }
    return false;
}

/**
 * Adds a parameter name/value pair to the supplied anchor, based on the field indicated.
 * @param {String|HTMLElement} fieldName The ID of, or reference to, the field that should supply the name/value for this parameter.
 * @param {HTMLElment} oAnchor The anchor tag that will receive the new parameter.
 */
function addArgument(fieldName, oAnchor) {
    if (fieldName) {
        var oField = getObj(fieldName);
        var argumentValue, argumentName;
        if (oField) {
            argumentName = oField.id;
            argumentValue = oField.value;
            if ((typeof(argumentName) != 'undefined') && (argumentName.length > 0) && (typeof(argumentValue) != 'undefined')) {
                oAnchor.href = oAnchor.href + "&" + argumentName + "=" + escape(argumentValue); //issue 210651: double byte lang need to be encoded
            }
        }
    }
}

/**
 * Calls {@link addArgument} for the supplied values and then submits the anchor.
 * @param {String|HTMLElement} fieldName The ID of, or reference to, the field that should supply the name/value for this parameter.
 * @param {HTMLElment} oAnchor The anchor tag that will be submitted.
 */
function addArgumentAndSubmitLink(fieldName, oAnchor) {
    addArgument(fieldName, oAnchor);
    submitLink(oAnchor);
}

/**
 * Converts the supplied anchor tag into a form and submits it.
 * @param {HTMLElment} oAnchor The anchor tag that will be converted into a form and submitted.
 * @type Boolean
 * @return false
 */
function submitLinkAsForm(oAnchor) {
    var sURL = oAnchor.href,
        sTarget = oAnchor.target,
        oForm = createDynamicForm(sURL);
    
    if (sTarget) oForm.target = sTarget;
    submitForm(oForm);
    return false;
}

/*
 * Retrieves the value for a cookie
 */
/**
 * Retrieves the cookie value for the supplied cookie name.
 * @param {String} cookieName The name of the cookie.
 * @type String
 * @return The cookie value for the supplied cookie name.
 */
function getCookie(cookieName) {
    var cookieStart = cookieEnd = -1;
    if (document.cookie.length > 0) {
        // a name-value pair is separated by an equal sign
        cookieStart = document.cookie.indexOf(cookieName + "=");
        if (cookieStart != -1) {
            cookieStart = cookieStart + cookieName.length + 1;
            // cookies are separated by semicolons
            cookieEnd = document.cookie.indexOf(";", cookieStart);
            if (cookieEnd == -1) {
                cookieEnd = document.cookie.length;
            }
            return unescape(document.cookie.substring(cookieStart, cookieEnd));
        }
    }
    // a cookie with the requested name does not exist
    return null;
}

/**
 * Modifies the supplied anchor tag with page state.  If it's an IFRAME request the Update Manager will be submitted as well. 
 * @param {HTMLElement} oAnchor The anchor tag to be submitted.
 * @type Boolean
 * @return False if the Update Manager was submitted (to avoid link submission), true if not.
 * @deprecated please use {@link UpdateHelper.submitLink} instead.
 */
function submitLink(oAnchor, e) {
    if (!e) e = window.event;
    if (e && e.ctrlKey) {
        return false;
    }
    
    if (oAnchor.getAttribute("useIframe")) oAnchor.href = replaceURLParameter(oAnchor.href, "iframe", "true");
    var sURL = oAnchor.href,
        sTarget = oAnchor.target;

    //CSS Analyzer validation. If present, the IFrame manipulation should not
    //be triggered
    var cssAnalyzerToolbar = document.getElementById("cssAnalyzerToolbar");
    var isCSSAnalyzerEnabled = (getCookie(ENABLE)=="true") && (cssAnalyzerToolbar!=null) && e.altKey;

    //Don't submit the link if the CSS Analyzer is enabled
    if (isCSSAnalyzerEnabled) return false;

    //Submit the changes from the update manager
    if (sTarget == "frameManager" || (typeof(microstrategy) != 'undefined' && microstrategy.updateManager && microstrategy.updateManager.hasChangesToSubmit())) {
        
        if(!bIsIE7 || document.readyState == 'complete'){
            var oForm = createDynamicForm(sURL);
            if (sTarget) oForm.target = sTarget;
            submitForm(oForm);
        }
        return false;
        
    }

    if (typeof(pageState) != 'undefined') {
        var sNewLink = updateLink(sURL);
        sNewLink = moveAnchor(sNewLink);
        var anchorText = null;
        // check for text-only anchor: IE 6 bug: 210373, 210456,210926
        if (bIsIE6 && oAnchor.childNodes && (oAnchor.childNodes.length == 1) && oAnchor.childNodes[0].nodeType == 3) {
            anchorText = oAnchor.innerHTML;
        }

        oAnchor.href = sNewLink;
        if (bIsIE6 && anchorText != null) oAnchor.innerHTML = anchorText;
        return true;
    } else {
        // no information to submit, still link needs to be called
        return true;
    }
}

/**
 * Moves the named anchor id (#) to the end of the url.
 * @param {String} sURL The url for editing.
 * @type String
 * @returns The newly edited url.
 */
function moveAnchor(sURL) {
    var iInitialPos = -1,
        iFinalPos = -1,
        sAnchor = '';
    
    iInitialPos = sURL.indexOf('#');
    if (iInitialPos > -1) {
        iFinalPos = sURL.indexOf('?', iInitialPos);
        if (iFinalPos == -1) iFinalPos = sURL.indexOf('&', iInitialPos);
        if (iFinalPos > -1) {
            sAnchor = sURL.substr(iInitialPos, iFinalPos-iInitialPos);
            sURL = sURL.replace(sAnchor,'') + sAnchor;
        }
    }
    return sURL;
}

/**
 * Adds the event order hidden input (evtorder) to the supplied form.
 * @param {HTMLElement} oForm The form to receive the hidden input.
 * @param {String} eventID The ID of the event.
 * @param {Boolean} isLastEvent Indicates whether to insert the new event at the beginning or end of the input value.
 * @deprecated pelase use {@link UpdateHelper.addEvtOrderToParams} instead.
 */
function addEvtOrder(oForm, eventID, isLastEvent) {
    //Add a hidden input for the event order:
    var aOriginalInputs = oForm.getElementsByTagName('input'),
        found = false,
        multipleEvents = 0;

    for (j = 0, cnt = aOriginalInputs.length; j < cnt; j++) {
        found = aOriginalInputs[j].name == "evtorder";
        if (found) break;
    }

    if (found) {
        //If found, add only if not already there:
        if (aOriginalInputs[j].value.indexOf(eventID) < 0) {
            aOriginalInputs[j].value = (isLastEvent) ?  (aOriginalInputs[j].value + "," + eventID) : (eventID + "," + aOriginalInputs[j].value);
            updateDynamicInput(oForm, eventID, "1", aOriginalInputs);
        }
    } else {
        //Add a evtOrder to make sure the update event is executed first:
        updateDynamicInput(oForm, "evtorder", eventID);

        //Add a hidden input for each event so it gets executed other than the passed :
        for (j = 0, cnt = aOriginalInputs.length; j < cnt; j++) {
            if (aOriginalInputs[j].name == "evt") multipleEvents++;
        }

        if (multipleEvents < 3) {
            for(j = 0, cnt = aOriginalInputs.length; j < cnt; j++) {
                if (aOriginalInputs[j].name == "evt") updateDynamicInput(oForm, aOriginalInputs[j].value, "1");
            }
        }
    }
}

/**
 * Replaces the value of the supplied parameter in the supplied url with the supplied value.
 * @param {String} sURL The URL for editing.
 * @param {String} sFieldToChange The name of the parameter to whose value should be replaced.
 * @param {String} sValueToChange The new value.
 * @type String
 * @return The newly edited URL.
 * @deprecated please use {@link UpdateHelper.addEvtOrderToParams} intead.
 */
function replaceURLParameter(sURL, sFieldToChange, sValueToChange) {
    var jumpLink = "";
    if (sURL.indexOf("#") > -1) {
        jumpLink = sURL.substr(sURL.indexOf("#"));
        sURL = sURL.substr(0, sURL.indexOf("#"));
    }
    
    //Removes the given parameter name/value from the supplied URL.
    var iInitialPos = iFinalPos = -1,
        sUrlUpper = sURL.toUpperCase(),
        sSearch  = sFieldToChange.toUpperCase() + '=',
        sLeadChar = '';
        
    iInitialPos = sUrlUpper.indexOf(sSearch);
    if (iInitialPos > -1) {
        sLeadChar = sUrlUpper.substr(iInitialPos - 1, 1);
        if ((sLeadChar != '&') && (sLeadChar != '?')) {
            iInitialPos = sUrlUpper.indexOf(sSearch, iInitialPos + 1);
        }
        if (iInitialPos > -1) {
            iFinalPos = sURL.indexOf('&', iInitialPos);
            if (iFinalPos == -1) {
                sLeadChar = sURL.substr(iInitialPos - 1, 1);
                if (sLeadChar == '&') sURL = sURL.substr(0, iInitialPos - 1);
            } else {
                sURL = (sLeadChar == '?') ?  sURL.substr(0, iInitialPos) + sURL.substr(iFinalPos + 1) :
                    sURL.substr(0, iInitialPos - 1) + sURL.substr(iFinalPos);
            }
        }
    }
    
    if (sURL.length > 0) {
        sURL += (sURL.substr(-1) == '?') ? (sFieldToChange + '=' + sValueToChange) : ('&' + sFieldToChange + '=' + sValueToChange);
    } else {
        sURL += sFieldToChange + '=' + sValueToChange;
    }
    return sURL + jumpLink;
}


/**
 * Returns the first value of the given parameter in the URL
 * @param {String} sURL The URL for searching.
 * @param {String} sParameter The name of the parameter to extract.
 * @type String
 * @return The value of the requested parameter, or an empty string if not found.
 * @refactoring This function is only called from three locations so we should find a better place for it.
 */
function getURLParameter(sURL, sParameter) {
    var r = new RegExp(sParameter + '=' + '(.*?)&|$');
    var m = r.exec(sURL, 'i');
    return m[1] || '';
}

/**
 * Builds and inserts a dynamic script tag.

 * @param {String} key The key for identifying this script node.
 * @param {String} filePath The path to the JavaScript file.
 */
function insertDynamicScript(key, filePath) {
    if (bIsIE4 || mstr.utils.ISSAFARI) {
        ////#367569, #372071, #367950, #370530 - dynamic JS loading in IE
        //For IE browsers, we build array of dynamic js filelist.
        //This list of files will be loaded through iframe.replaceComponent() / updateManager.replaceComponent() / eventManager.onload()
        microstrategy.dynamicJS.push({'key':key, 'file': filePath});
    } else {
        if (!checkJSExists(key)) {
            var scriptNode = document.getElementById(key + "_js");
            if (scriptNode) {
                if (scriptNode.src != filePath) {
                    scriptNode.src = filePath;
                }
            } else {
                scriptNode = document.createElement("script");
                scriptNode.id = key + "_js";
                scriptNode.setAttribute('language', 'javascript');
                document.body.appendChild(scriptNode);
                scriptNode.src = filePath;
            }
        }
    }
}


/**
 * Checks to see if the DOM already contains a script tag with the given key.
 * @param {String} key The key to search for.
 * @type Boolean
 * @return True if the node is found, false if not.
 * @refactoring This method is only called from two places {@link insertDynamicScript} and {@link microstrategy.registerBone}.  We should move it out of the global scope.
 */
function checkJSExists(key){
   if (key.indexOf(".") < 0) return window[key];
   
   var keyStr = key.split("."),
        obj = window,
        v = n = null;
   
   for (var i = 0, len = keyStr.length; i < len; i++) {
        n = keyStr[i];
        v = obj[n];
        if (v == undefined) return false;
        obj = v;
        if (obj == null) return false;
   }
  return true;
}

/**
 * Evals the key and executes the methodToExecute if true. Otherwise, this function will wait 500ms and call itself again.
 * @param {String} key The condition to eval().
 * @param {String} methodToExecute The code to eval() if the key evaluates to true. 
 * @refactoring This method stinks on many levels.  We need to eliminate the evals and methodToExecute should be a function.
 */
function loadInit(key, methodToExecute) {
    if(eval(key)) {
        eval(methodToExecute);
    }
    else {
        key = key.replace(/"/g, "\\\"");
        methodToExecute = methodToExecute.replace(/"/g, "\\\"");
        window.setTimeout("loadInit(\"" + key + "\", \"" + methodToExecute + "\");", 500);
    }
}

/**
 * Hides/Shows select boxes in IE6 only to deal with select boxes that bleed through positioned elements.
 * @param {HTMLElement} elem The positioned HTMLElement.
 * @param {Boolean} bShow Indicates whether to hide or show the select elements.
 */
function togglePulldowns(elem, bShow) {
    //#362189 -MSTR Office: <SELECT> tag shows through dialog and floating editor; 
    //        we have to render iframe for all IE browsers.
    if (bIsW3C) return;

    if (!bShow) {
        if (elem) {
            var w = getObjWidth(elem) || getObjInnerWidth(elem);

            var h = getObjHeight(elem) || getObjInnerHeight(elem);

            var popupMask = microstrategy.getPopupMask(elem);
            popupMask.style.left = elem.style.left;
            popupMask.style.top = elem.style.top;
            popupMask.style.width = w + "px";
            popupMask.style.height = h + "px";

            if (elem.style.zIndex > 0) {
                popupMask.style.zIndex = elem.style.zIndex - 1;
            } else {
                if (typeof(microstrategy)!='undefined' && microstrategy.styleObj) {
                    var styleZIndex = microstrategy.styleObj.getValue(elem, "zIndex");
                    if (styleZIndex && !isNaN(parseInt(styleZIndex))) {
                        popupMask.style.zIndex = styleZIndex;
                    }
                }
            }
        }
    } else {
        microstrategy.releasePopupMask(elem);
    }
    return;
}

/**
 * Closes editors client-side and modifies MicroStrategy page state, but does not force a trip to the web server.
 * @param {String} sDialogName The name of the dialog, which corresponds to both the HTMLElement ID (sDialogName + '_pane') as well as the bean name.
 * @param {String} sFrameName The name of the frame that contains the bean.
 * @type Boolean
 * @return false
 * @refactoring This function is only called from the EditorImpl.java, we should verify that it's still used.  If so, it should be renamed and moved to 
 *  mstrEditorImpl.
 */
function closeDialog(sDialogName, sFrameName) {
    
    //Hide dialog:
    if (getObj(sDialogName + '_pane')) removeObj(sDialogName + '_pane');

    //Hide the resize handles if they were visible
    if (getObj('colHandlesPane')) removeObj('colHandlesPane');

    //Get the new state of the ReportFrame
    var newState = getURLParameter(pageState, sFrameName);
    newState = newState.replace(sDialogName, '*0');

    //Change state of report frame in the pageState variable
    pageState = replaceURLParameter(pageState, sFrameName, newState);

    //Change the state in the pageStateForm:
    var oForm = getObj('pageStateForm'),
        oInput;
    for(var i = 0, len = oForm.elements.length; i < len; i++) {
        oInput = oForm.elements[i];
        if (oInput.name == sFrameName) {
            oInput.value = newState;
            break;
        }
    }
    //Notify for a closing Dialog
    
    if (microstrategy.observer) microstrategy.observer.notifyAll('onstatechange');
    //#365409 resize other bones for resizing
    microstrategy.eventManager.ondialogresize();
    return false;
}

/**
 * Looks very similar to {@link closeDialog} but also updates menus.
 * @param {String} sEditorName The name of the editor, which corresponds to both the HTMLElement ID (sEditorName + '_pane') as well as the bean name.
 * @type Boolean
 * @return false
 * @refactoring We should verify that we still need this.  Seems to be called from EditorImpl.java and a bunch of transforms.
 */
function closeEditor(sEditorName) {
    //Hide dialog:
    if (getObj(sEditorName + '_pane')) removeObj(sEditorName + '_pane');
    //Update all menus marked to close this editor:
    var reEvent = new RegExp("6012", "g");

    //Update cookies:
    if (microstrategy) {
        var updateManager = microstrategy.updateManager;
        if (updateManager) {
            var actionCollection = new Array();
            actionCollection.push(updateManager.createActionObject(this,
                                                mstrUpdateManager.SHOW_BEAN,
                                                microstrategy.servletName + "." + microstrategy.pageName,
                                                ['5017','5018'],
                                                ['false', sEditorName], [] ));

            updateManager.add(actionCollection, true);
        }
    }

    return false;
}

/**
 * A wrapper for the {@link mstrMsgBoxImpl} used to display popup messages on the client.
 * @param {Object} messageInfo has the following properties
 * @param {String} messageInfo.contents The string to display as the main message.
 * @param {Integer} messageInfo.elements A bitwise flag indicating which buttons should be visible.
 * @param {String} messageInfo.okEval A string of text that will be eval() when the user hits the 'Ok' button.
 * @param {String} messageInfo.cancelEval A string of text that will be eval() when the user hits the 'Cancel' button.
 * @param {String} messageInfo.type One of several 'MSG_' constants on {@link mstrMsgBoxImpl} indicating what type of message box to display.
 * @param {String} messageInfo.messageBoxID='msgBox' The ID of the message box to use.
 * @param {String} messageInfo.title The title of the message box.
 * @param {String} messageInfo.href The URL for the help associated with this message box.
 * @param {Integer} messageInfo.zIndex The value to set the zIndex of the message box.
 * @param {String} messageInfo.applyEval A string of text that will be eval() when the user hits the 'Apply' button.
 * @param {String[]} messageInfo.buttonLabels An array of labels for the buttons.
 * @param {Boolean} messageInfo.positionInMiddle whether to show the message box in the middle of the screen or not. False if not the case, otherwise default to true
 * @refactoring We should refactor this to accept functions instead of eval(string). 
 */
function showMessage(messageInfo) {
    var bone = null;

    if(messageInfo.messageBoxID == null) {
       messageInfo.messageBoxID = "msgBox";
    }

    if(messageInfo.positionInMiddle == null || typeof(messageInfo.positionInMiddle) == 'undefined') {
       messageInfo.positionInMiddle  = true;    
    }
    
    bone = microstrategy.bones[messageInfo.messageBoxID];

    if (bone) {
        if (messageInfo.href != null) {
            bone.setHelpHref(messageInfo.href);
        }
        bone.setMessage(messageInfo.contents, messageInfo.type);
        bone.setButtons(messageInfo.elements, messageInfo.okEval, messageInfo.cancelEval, messageInfo.applyEval, messageInfo.buttonLabels);
        bone.setTitle(messageInfo.title);
        bone.show(messageInfo.positionInMiddle, messageInfo.zIndex);
    }
}

/**
 * Enables/Disables select elements (IE6 only) for a modal editor that were hidden/shown by {@link togglePulldowns}.
 * @param {HTMLElement} obj The object whose select boxes should be enabled/disabled.
 * @paran {Boolean} bShow Indicates whether to enable or disable the select elements.
 */ 
function enablePulldowns(obj, bShow) {
    if (mstr.utils.ISIE6) {
        var pulldowns = obj.getElementsByTagName("select");
        if (pulldowns) {
            if (bShow) {
                for (var i = 0; i < pulldowns.length; i++)
                    if (pulldowns[i].getAttribute("db") == "true") {
                        pulldowns[i].disabled = false;
                        pulldowns[i].removeAttribute("db");
                    }
            } else {
                for (var i = 0; i < pulldowns.length; i++) {
                    if (!pulldowns[i].disabled) {
                        pulldowns[i].disabled = true;
                        pulldowns[i].setAttribute("db", "true");
                    }
                }
            }
        }
    }
}

/**
 * Encodes an html string.
 * @param {String} oldStr The html to encode.
 * @param {Boolean} [toServer=false] Indicates whether newlines should be encoded for html display ('<br />').
 * @type String
 * @return The encoded string value. 
 */ 
function encode(oldStr, toServer) {
        var sb = oldStr;
        if (toServer == null) toServer = false;

        if ((oldStr != null) && (oldStr.length > 0)) {
                sb = "";

                for (var i = 0, len = oldStr.length; i < len; i++) {
                        switch (oldStr.charAt(i)) {
                        case '&':
                                if ((oldStr.length != (i + 1)) && (oldStr.charAt(i + 1) == '#')) {
                                        // we don't want to encode if &#
                                        sb += "&";
                                } else {
                                        sb += "&amp;";
                                }
                                break;

                        case '<':
                                sb += "&lt;";
                                break;

                        case '>':
                                sb += "&gt;";
                                break;

                        case '\'':
                                sb += "&#039;";
                                break;

                        case '\n':
                                    if (!toServer) {
                                        sb += "<br />";
                                    } else {
                                        sb += oldStr.charAt(i);
                                    }
                                break;

                        case '"':
                                sb += "&quot;";
                                break;
                        case ' ':
                                if (i == 0 || (i < oldStr.length - 1 && oldStr.charAt(i + 1) == ' ')) {
                                    sb += "&nbsp;";
                                } else {
                                    sb += oldStr.charAt(i);
                                }
                                break;
                        default:
                                sb += oldStr.charAt(i);
                                break;
                        }
                }
        }

        return sb;

}

/**
 * Decodes and encoded html string.
 * @param {String} oldStr The html to decode.
 * @param {Boolean} [toServer=false] Indicates whether '<br>' tags should be decoded.
 * @type String
 * @return The decoded string value. 
 */ 
function decode(oldStr, toServer) {
    var newString = oldStr;
    if (oldStr != null) {
        newString = newString.replace(/&amp;/g, "&");
        newString = newString.replace(/&lt;/g, "<");
        newString = newString.replace(/&gt;/g, ">");
        newString = newString.replace(/&#039;/g, "'");
        newString = newString.replace(/&nbsp;/g, " ");
        if (!toServer) {
            newString = newString.replace(/<BR>/ig, "\n");
        }
        newString = newString.replace(/&quot;/g, "\"");
    }
    return newString;
}

/**
 * Trims the supplied string of enclosing whitespace.
 * @param {String} str The String to be trimmed.
 * @type String
 * @return The trimmed String.
 */ 
function trim(str) {
    if (!str) return "";
    
    return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}

/**
 * Scrolls the browser to the current prompt and resizes the prompt container.
 */
function gotoPromptAnchor() {
    if (promptFunctionsScript == true) {
        gotoAnchor(currentPin);
        resizePromptContent();
    }
}


SimpleRect.prototype = new Object();

/**
 * @class A Simple rectangle object representing the left, top, right and bottom positions of an HTMLElement.
 * @constructor
 * @param {HTMLElement} obj The HTMLElement whose position and dimensions will be used to populate this object. 
 */
function SimpleRect(obj) {
    this.left = getObjSumLeftScrolled(obj);
    this.top = getObjSumTopScrolled(obj);
    this.right = this.left + getObjWidth(obj);
    this.bottom = this.top + getObjHeight(obj);
    return this;
}

/**
 * Modifies the filter style property of the supplied HTMLElement.
 * @param {HTMLElement} elem The HTMLElement on which to set the opacity.
 * @param {String} name The name of the filter type to set, e.g., Alpha
 * @param {Object} props An associative array of filter properties.
 */
function setFilter(elem, name, props) {
    if (bIsIE4){
        var filter = getFilter(elem, name);
        var prop;
    
        if(filter) {
        	filter.enabled = true;
            for (prop in props) {
                filter[prop] = props[prop];
            }
	        if (name == "Alpha" && props["opacity"] == 100) {
	        	filter.enabled = false;
	        }
        } else{
            if (name == "Alpha" && props["opacity"] == 100) return;
            var filterDefinition = " progid:DXImageTransform.Microsoft." + name + "(";
            for (prop in props) {
                filterDefinition += prop + "=" + props[prop] + ",";
            }
            filterDefinition = filterDefinition.substr(0, filterDefinition.length - 1) + ")";
            var filterText = elem.style.filter;
            if (!filterText) {
                filterText = getFilter(elem);
                if (filterText) {
                    elem.style.filter += filterText + filterDefinition;
                } else {
                    elem.style.filter += filterDefinition;
                }
            } else {
                elem.style.filter += filterDefinition;
            }
            
        }
    }
    else if(mstr.utils.ISFF || mstr.utils.ISWK){
        if (name == "Alpha") {
            elem.style.opacity = props["opacity"]/100.00;
        }
    }
}
/**
 * Retrieves a specific filter style property value for the given HTMLElement. 
 * @param {HTMLElement} elem The element from which to retrieve the filter.
 * @param {String} name The name of the filter type to retrieve, e.g., Alpha
 * @type String
 * @return The filter type value.
 */
function getFilter(elem, name) {
    try {
        if (microstrategy && microstrategy.styleObj) {
            return microstrategy.styleObj.getFilter(elem, name);
        }
    
        var filter = null;
    
        if(bIsIE4){
            //#328633 - part of fix to this issue, need to access currentStyle.filter instead of style.filter which returns only inline style
            var filterText = elem.currentStyle.filter; //elem.style.filter;
            if(!name)  return filterText;

            if (filterText.length > 0 ) {
                filter = elem.filters['DXImageTransform.Microsoft.' + name];
            }
        }   
        return filter;
        
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * Removes a specific filter from the filters collection of the given HTMLElement. 
 * @param {HTMLElement} elem The element from which to retrieve the filter.
 * @param {String} name The name of the filter type to retrieve, e.g., Alpha
 */
function removeFilter(elem, name) {
    try {
        if (microstrategy && microstrategy.styleObj) {
            return microstrategy.styleObj.getFilter(elem, name);
        }
    
        var filter = null;
    
        if(bIsIE4){
            //#328633 - part of fix to this issue, need to access currentStyle.filter instead of style.filter which returns only inline style
            var filterText = elem.currentStyle.filter; //elem.style.filter;
    
            if(!name)  return filterText;
    
            if (filterText.length > 0 ) {
                filter = elem.filters['DXImageTransform.Microsoft.' + name];
            }
        }   
        return filter;
        
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}


/**
 * Determines if the length of a TEXTAREA's contents exceeds the maximum.
 * @param {HTMLElement} oTextArea The TEXTAREA to limit.
 * @param {Integer} lMaxLength The max length of the TEXTAREA's contents.
 * @type Boolean
 * @return false if the maximum was exceeded, true if not.
 */
function CheckTextAreaMaxLength(oTextArea, lMaxLength) {
    var oStr = (typeof(oTextArea.innerText) != 'undefined') ? oTextArea.innerText : oTextArea.value;
    return !(oStr.length >= lMaxLength);
}

/**
 * Truncates the contents of a TEXTAREA if it's length exceeds the maximum.
 * @param {HTMLElement} oTextArea The TEXTAREA to limit.
 * @param {Integer} lMaxLength The max length of the TEXTAREA's contents.
 */
function LimitTextAreaMaxLength(oTextArea, lMaxLength) {
    if (oTextArea.value.length > lMaxLength) {
        oTextArea.value = oTextArea.value.substring(0, lMaxLength);
    }
}

/**
 * Toggles between full screen mode and normal mode.
 * @type Boolean
 * @return false
 */
function toggleScreenMode() {
    var updateManager;
    if (typeof(microstrategy) != 'undefined' && microstrategy.updateManager) {
        updateManager = microstrategy.updateManager;
    }
    if (!updateManager) return true;

    var featureResolver, homeToolbar, actionCollection;
    
    if (microstrategy.EXECUTION_SCOPE == microstrategy.REPORT_EXECUTION) {
        featureResolver = mstr.$obj('UniqueReportID');
        homeToolbar = mstr.$obj("rptRibbonToolbarModel");
    } else if (microstrategy.EXECUTION_SCOPE == microstrategy.RWD_EXECUTION) {
        featureResolver = microstrategy.getViewerBone();
        homeToolbar = mstr.$obj("rwRibbonToolbarModel");
    }

    if (microstrategy.pageScreenMode == microstrategy.PAGE_FULL_SCREEN_MODE) {//already in full screen mode
        //create a action to set normal screen mode
        actionCollection = new Array();
        actionCollection.push(updateManager.createActionObject(this.elem, mstrUpdateManager.SWITCH_FULL_SCREEN_MODE, microstrategy.servletName + "." + microstrategy.pageName, ["5028"], ["1"], []));
        microstrategy.updateManager.add(actionCollection, true);

        var shortcut=document.getElementById('mstrWeb_shortcutsBar');
        if((featureResolver.currentRWViewMode!=microstrategy.RW_VIEW_MODE_FLASH)||(shortcut)){ 	
        	document.body.className = document.body.className.replace(' mstrFullScreen', '');
        }
        else{
            updateManager.useIframe = false;
            updateManager.flushAndSubmitChanges();
        }
        
        
        if(mstr.utils.ISIE4) {
           var cc = document.getElementById("td_mstrWeb_dockLeft");
           if(cc) {
              cc.parentNode.insertBefore(cc, cc.nextSibling);
           }
        }
        
        //hide the standard toolbar or Reload the rw_standard toolbar for show the correct controls
        featureResolver['features']['page-full-screen-mode'] = false;

        microstrategy.pageScreenMode = microstrategy.PAGE_NORMAL_SCREEN_MODE;
        
        if (featureResolver.observer) featureResolver.observer.notifyAll("onScreenModeChange");
    } else {

        //create an action object to set full sceen mode
        actionCollection = new Array();
        actionCollection.push(updateManager.createActionObject(this.elem, mstrUpdateManager.SWITCH_FULL_SCREEN_MODE, microstrategy.servletName + "." + microstrategy.pageName, ["5028"], ["2"], []));
        microstrategy.updateManager.add(actionCollection, true);

        microstrategy.pageScreenMode = microstrategy.PAGE_FULL_SCREEN_MODE;
        if (!homeToolbar) {//if no standard toolbar
            updateManager.useIframe = false;
            updateManager.flushAndSubmitChanges();
            return false;
        } else {
            homeToolbar.execSelectValue(0);
            featureResolver['features']['page-full-screen-mode'] = true;
            if (featureResolver.observer) featureResolver.observer.notifyAll("onScreenModeChange");
        }
        
        document.body.className += ' mstrFullScreen';
        
    }

    microstrategy.eventManager.notifyOrphanBones("onwinresize");

    return false;
}

/* I.B. Please don't remove this code for now.
function getCalculatedStyle(elem) {
    if ( bIsIE6 ) {
        return elem.currentStyle;
    } else if (bIsFirefox) {
        return document.defaultView.getComputedStyle(elem, null);
    } else {
        return null;
    }
}

function getCalculatedBgColor(elem) {
    var style;
    var val;
    while (elem) {
        style = getCalculatedStyle(elem);
        if ( ! style ) {
            return null;
        }
        val = style.backgroundColor;
        if ( val && val != 'transparent' ) {
            //return convertColorHexToRGB(val);
            return mstr.utils.Color.hex2rgb(val);
        }
        elem = elem.parentNode;
    }
}
*/

/**
 * Similar to {@link submitLink} but it adds an additional parameter (styleName) which is the name of the selected visualization.
 * @param {String} href The url used to populate the dynamic form.
 * @param {String} target The dynamic form target.
 * @refactoring Not used in OOTB application, but is used in a customization scenario so it should be moved there.
 * what customization ?
 */
function submitSaveVisualization(href, target) {
    // this function is not used in the OOTB application but is used in a customization scenario
    var oNewForm = createDynamicForm(href);
    if (target) oNewForm.target = target;
    oNewForm.method = 'GET';
    var bone = microstrategy.bone("UniqueReportID");
    if (!bone) bone = microstrategy.bone("rwb_viewer");
    if (bone && bone.selectedVisualization) {
        createHiddenInput(oNewForm, "styleName", bone.selectedVisualization);
    }
    submitForm(oNewForm);
}


var graphTooltipCache = null;

/**
 * Event handler fired when the mouse cursor moves over a graph with tooltips.
 * @param {Event} e The mouse event object.
 * @param {String} boneName The ID of the associated graph bone. 
 */
function onGraphMouseMove(e, boneName) {
    if (!e) e = window.event;
    var src = getEventTarget(e);
    if (src) {
        src.onmouseout = new Function("e", "onGraphExit(e);");
        graphShowTooltip(src, e, boneName);
    }
}

/**
 * Event handler fired when the mouse cursor leaves a graph with tooltips.
 * @param {Event} e The mouse event object.
 */
function onGraphExit(e) {
    if (!e) e = window.event;
    if (graphTooltipCache) { 
        graphTooltipCache.style.left = "-10000px";
        togglePulldowns(graphTooltipCache, true);
    }
}

/**
 * Displays a tooltip for a graph area.
 * @param {HTMLElement} src The event target from the mouse event.
 * @param {Event} e The mouse event object.
 * @param {String} boneName The ID of the associated graph bone. 
 */
function graphShowTooltip(src, e, boneName) {
    if (!e) e = window.event;
    var image = null;

    if (boneName) {
        var bone = microstrategy.bone(boneName);
        if (bone) image = bone.image;
    } else if (microstrategy) {
        var imageParent = microstrategy.findAncestorWithAtt(src, microstrategy.HTMLATTR_SUBOBJTYPE, microstrategy.SUBOBJTYPE_DOC_GRAPH_TEMPLATE);
        if (imageParent) image = microstrategy.objectFind(imageParent, "img", microstrategy.OBJTYPE_GRAPH);
    }

    if (!image) {  // G+G mode
        var imageParent = src.parentNode.parentNode;
        if (imageParent) image = microstrategy.objectFind(imageParent, "img", microstrategy.OBJTYPE_GRAPH);
    }

    if (e && src && image) {
        var tooltipText = src.getAttribute("tooltip"),
            x = y = 99999;

        if (!tooltipText) {
            if (graphTooltipCache) { 
                graphTooltipCache.style.left = "-10000px";
                togglePulldowns(graphTooltipCache, true);
            }
            return;
        }

        var coords = src.getAttribute("coords"),
            imgLeft = getObjSumLeftScrolled(image),
            imgWidth = getObjWidth(image),
            zoom = 100;

        if (coords && coords.length > 0) {
            coords = coords.split(",");
            x = 99999;
            y = 99999;
            var i = 0;
            while (i + 1 < coords.length) {
                x = Math.min(x, parseInt(coords[i++]));
                y = Math.min(y, parseInt(coords[i++]));
            }
            x += imgLeft;
            y += getObjSumTopScrolled(image);
        } else {
            getMouse(e);
            x = lMouseX;
            y = lMouseY;
        }
        if (!graphTooltipCache) {
            graphTooltipCache = document.createElement("span");
            graphTooltipCache.className = "graph-tooltip";
            if (graphTooltipCache) graphTooltipCache.style.left = "-10000px";
            document.body.appendChild(graphTooltipCache);
        }
        graphTooltipCache.innerHTML = tooltipText;
        if (microstrategy.ZOOM_FACTOR) {
            zoom = microstrategy.ZOOM_FACTOR;
        }
        graphTooltipCache.style.fontSize = (zoom / 100) + "em";

        y -= getObjHeight(graphTooltipCache);
        var tooltipWidth = getObjWidth(graphTooltipCache);

        x = (x + tooltipWidth > imgLeft + imgWidth) ? imgLeft + imgWidth - tooltipWidth : x;

        moveObjTo(graphTooltipCache, x, y);
        togglePulldowns(graphTooltipCache, false);
    }
}

var templateTooltipCache = null;
/**
 * Event handler fired when the mouse cursor moves over a doc template with tooltips.
 * @param {Event} e The mouse event object.
 */
function onTemplateMouseMove(e) {
    if (!e) e = window.event;
    var src = getEventTarget(e);
    if (src) {
        src.onmouseout = new Function("e", "onTemplateExit(e);");        
        tempShowTooltip(src, e);
    }
}

/**
 * Event handler fired when the mouse cursor leaves a tempalte with tooltips.
 * @param {Event} e The mouse event object.
 */
function onTemplateExit(e) {
    if (!e) e = window.event;
    if (templateTooltipCache) { 
        templateTooltipCache.style.left = "-15000px";
        togglePulldowns(templateTooltipCache, true);
    }
}

/**
 * Displays a tooltip for the entire graph template
 * @param {HTMLElement} src The event target from the mouse event.
 * @param {Event} e The mouse event object.
 */
function tempShowTooltip(src, e) {
    if (!e) e = window.event;

    if (e && src) {
        var template = microstrategy.findAncestorWithAtt(src, microstrategy.HTMLATTR_SUBOBJTYPE, microstrategy.SUBOBJTYPE_DOC_TEMPLATE);
        
        var x = y = 99999,
            zoom = 100,
            tooltipText = null;        
        if (template) tooltipText = template.getAttribute("tooltip");

        if (!tooltipText) {
            if (templateTooltipCache) { 
                templateTooltipCache.style.left = "-15000px";
                togglePulldowns(templateTooltipCache, true);
            }
            return;
        }

        getMouse(e);
        x = lMouseX;
        y = lMouseY;

        if (!templateTooltipCache) {
            templateTooltipCache = document.createElement("span");
            templateTooltipCache.className = "graph-tooltip";
            if (templateTooltipCache) templateTooltipCache.style.left = "-15000px";
            document.body.appendChild(templateTooltipCache);
        }
        templateTooltipCache.innerHTML = tooltipText;
        if (microstrategy.ZOOM_FACTOR) {
            zoom = microstrategy.ZOOM_FACTOR;
        }
        templateTooltipCache.style.fontSize = (zoom / 100) + "em";

        y -= getObjHeight(templateTooltipCache) - 40;

        moveObjTo(templateTooltipCache, x, y);
        togglePulldowns(templateTooltipCache, false);
    }
}

/**
 * Calculates the height of the MicroStrategy footer.
 * @type Integer
 * @return The height of the MicroStrategy footer.
 */
function getFooterHeight() {
   var f = document.getElementById('mstrWeb_footer'); //this is footer wrapper
   f = microstrategy.findChildWithAtt(f, 'div', (mstr.utils.ISW3C ? 'class' : 'className'), 'mstrFooter') || f; //actual footer should be <Div.mstrFooter

   var mt = parseInt(mstr.utils.CSS.getStyleValue(f, 'marginTop'));

   return (f) ? mstr.utils.BoxModel.getElementOuterHeight(f) + (isNaN(mt) ? 0 : mt) : 0;
}
 
/**
 * Exports a Report.
 * @param {Integer} defaultRunMode 
 * @param {String} target The form target.
 * @param {String} type Whether it's export, print or pdf. 
 * @param {String} viewMode 
 * @param {Boolean} dontShowEmptyForm Indicates whether to omit the IE only empty form. 
 */
function exportReport(defaultRunMode, target, type, viewMode, dontShowEmptyForm, dontShowMsg) {	
    // - Show Warning Message for flash
    if (!dontShowMsg && type == 'buttonFlash' && bIsIE6) {
    	showMessage({contents:microstrategy.descriptors.getDescriptor("5873"), elements:microstrategy.OK_BUTTON , okEval:"exportReport('" + defaultRunMode + "','" + target + "','" + type + "'," + viewMode + "," + dontShowEmptyForm + ",true);", type:mstrMsgBoxImpl.MSG_WARNING});//Descriptor: You need to save the exported file locally before you can open it
    	return;
    }	
	
    // - Empty form (issue 203160)
    if (!dontShowEmptyForm && (bIsIE6 && target != "_blank")) {
        submitEmptyForm(target); 
        if (defaultRunMode == null) defaultRunMode = ""; 
        window.setTimeout("exportReport('" + defaultRunMode + "','" + target + "','" + type + "'," + viewMode + ",true," + dontShowMsg + ");", 500);
        return;
    }
    
    // -- EXPORT -- 
    // remember update manager's old values
    var newWindowOldValue = microstrategy.updateManager.newWindow;
    var windowNameOldValue = microstrategy.updateManager.newWindowName;
    var actionFormOldValue = microstrategy.updateManager.getFormAction();
    var fixStateActions = microstrategy.updateManager.getFixStateActions();
    
    // First part here is for the new popup export window
    microstrategy.updateManager.newWindow = true;
    microstrategy.updateManager.newWindowName = target;
    microstrategy.updateManager.setFormAction(microstrategy.servletName + "?name=" + Date.parse(new Date())); // Add unique id to form's action. Issue 204358

    //Retrieves the outline mode expansion state from the grid bone.  Only works in Report mode.
    function getOutlineState() {
        if (typeof(microstrategy) != 'undefined' && (microstrategy.EXECUTION_SCOPE == microstrategy.REPORT_EXECUTION) && microstrategy.IN_OUTLINE_MODE) {
            var rb = microstrategy.bone("UniqueReportID");
            if (rb != null && rb.outlineMode != null) {
                return rb.outlineMode.getExpansionState('UniqueReportID');
            }
        }
        return "";
    }
    
    switch (type) {
        case 'export': // export
            var ids = ["3033", "3005", "3114"],
                values = ["export", viewMode, getOutlineState()];
                
            if (defaultRunMode) {
                ids.splice(2, 0, "3157");
                values.splice(2, 0, defaultRunMode);
            }
            microstrategy.updateManager.add([microstrategy.updateManager.createActionObject(this.elem, mstrUpdateManager.EXPORT_REPORT, microstrategy.servletName, ids, values, [], [])], true);
            break;
        case 'printPDF': // print button PDF
            microstrategy.updateManager.addURL("pdfPrint=1");//TQMS 406080: the preference value should be "1" or "0"
            //fall through buttonPDF
        case 'buttonPDF': // PDF button PDF
            microstrategy.updateManager.add([microstrategy.updateManager.createActionObject(this.elem, mstrUpdateManager.EXPORT_PDF_REPORT, microstrategy.servletName, ["3033", "3114"], ["pdf", getOutlineState()], [], [])], true);
            break;
        case 'print': // Print
            microstrategy.updateManager.add([microstrategy.updateManager.createActionObject(this.elem, mstrUpdateManager.PRINT_REPORT, microstrategy.servletName, ["3033"], ["print"], [], [])], true);
            break;
        case 'buttonFlash': // Flash button
            microstrategy.updateManager.add([microstrategy.updateManager.createActionObject(this.elem, mstrUpdateManager.EXPORT_FLASH_REPORT, microstrategy.servletName, [], [], [], [])], true);
            break;            
    }
    microstrategy.updateManager.flushAndSubmitChanges();
    
    // resetting update manager to previous values
    microstrategy.updateManager.newWindow = newWindowOldValue;
    microstrategy.updateManager.newWindowName = windowNameOldValue;
    microstrategy.updateManager.setFormAction(actionFormOldValue);
    microstrategy.updateManager.acknowledgeRequest();
    microstrategy.updateManager.add(fixStateActions, true);
}

/**
 * This method is used for the customization scenario "Embedding a Report into an Expandable-Collapsible Web Panel"
 * Handle the webPanel's show/expand and hide/collapse. Should be used through one of its interfaces: sPanelHandler, xPanelHandler.
 * @param {String} sObjName The main name of the control to handle.
 * @param {String} openToolTip The tooltip to display the panel is hidden/collapsed.
 * @param {String} openImg The src of the image to show when the panel is hidden/collapsed.
 * @param {String} closeToolTip The tooltip to display the panel is shown/expanded.
 * @param {String} closeImg The src of the image to show when the panel is shown/expanded.
 */
function panelHandler(sObjName, openToolTip, openImg, closeToolTip, closeImg){
    var oTitleArray;
    var oContentArray;
    var oImageArray;
    var i;
    var j;
    var displayed;

    oContentArray = document.getElementsByName(sObjName + "_Content");

    function isDisplayed(vObject) {

    var obj = getObj(vObject);
        if (bIsIE4 || bIsW3C) {
            return((obj.style.visibility == "visible") || (obj.style.visibility.length == 0));
        } else {
            return((document.layers[obj.id].visibility == "show") || (document.layers[obj.id].visibility.length == 0));
        }

    }
    
    if(oContentArray.length > 0) {
        displayed =  (isDisplayed(oContentArray.item(0)));
    }

    for(i = 0; i < oContentArray.length; i ++) {
        if (displayed){

            if (bIsIE4 || bIsW3C) {
                oContentArray.item(i).style.display = "none";
                oContentArray.item(i).style.visibility = "hidden";
            }
            else {
                document.layers[oContentArray.item(i).id].visibility = "hide";
            }

            oTitleArray = document.getElementsByName(sObjName);

            for(j = 0; j < oTitleArray.length; j ++) {
                oTitleArray.item(j).title = openToolTip;
            }

            oImageArray = document.getElementsByName(sObjName + "_Image");

            for(j = 0; j < oImageArray.length; j ++) {
                oImageArray.item(j).src = openImg;
                oImageArray.item(j).alt = openToolTip;
            }

        }
        else {
            if (bIsIE4 || bIsW3C) {
                oContentArray.item(i).style.display = "block";
                oContentArray.item(i).style.visibility = "visible";
            }
            else {
                document.layers[oContentArray.item(i).id].visibility = "show";
            }

            oTitleArray = document.getElementsByName(sObjName);

            for(j = 0; j < oTitleArray.length; j ++) {
                oTitleArray.item(j).title = closeToolTip;
            }

            oImageArray = document.getElementsByName(sObjName + "_Image");

            for(j = 0; j < oImageArray.length; j ++) {
                oImageArray.item(j).src = closeImg;
                oImageArray.item(j).alt = closeToolTip;
            }

        }

    }

    var isUpdateManagerAvailable=false;
    try {
        isUpdateManagerAvailable = (mstrUpdateManager!=null);
    }
    catch(localerr) {}
    if (oContentArray.length > 0 && isUpdateManagerAvailable) {
        if (microstrategy) {
            microstrategy.updateBrowserSetting(sObjName, (displayed) ? "0" : "1");
        }
    }
}

function encodeBrowsePathElement(elem){
	if(elem){
		elem +="";
	return elem.replace(/~|,|%/g, 
			function tokenRep(token){
					switch(token){
					case "~":return "%7E";
					case ",":return "%2C";
					case "%":return "%25";
					default: return token;
					}
		});
	}
	return "";
}

