/**********************************************************************
   $Author: greynold $
   $Date: 2008/09/17 21:35:46 $
   $Revision: 1.22.8.1 $


   Copyright 2001 - 2004. Surgient, Inc. All rights reserved. This 
   software code is an unpublished work and contains trade secrets of 
   Surgient, Inc. and is distributed only under license restrictions. No 
   part of this software code may be displayed, used, reproduced, stored 
   on a retrieval system, distributed, or transmitted without the 
   express written consent of Surgient, Inc. Violation of the provisions 
   contained herein may result in severe civil and criminal penalties, 
   and any violators will be prosecuted to the maximum extent possible 
   under the law. 
   
   "Surgient", "Virtualization Control Server" and "Surgient VCS" are 
   trademarks or registered trademarks of Surgient, Inc. in the United 
   States and foreign countries. 
**********************************************************************/
/// <summary>
/// BrowserTestResults struct defines the available test result states for 
/// the BrowserTest objects.
/// </summary>
BrowserTestResults = {
    /// <summary>
    /// Sets the test result to Pass.
    /// </summary>
    Pass : 0,
    /// <summary>
    /// Sets the test result to Fail.
    /// </summary>
    Fail : 1,
    /// <summary>
    /// Sets the test result to Warning.
    /// </summary>
    Warn : 2, 
    /// <summary>
    /// Sets the test result to Error.
    /// </summary>
    Error : 3
};

/// <summary>
/// BrowserTestResults struct defines the available text label for result states for 
/// the BrowserTest objects.
/// </summary>
BrowserTestResultsLabel = {
    /// <summary>
    /// Sets the test result to Pass.
    /// </summary>
    Pass : "Pass",
    /// <summary>
    /// Sets the test result to Fail.
    /// </summary>
    Fail : "Fail",
    /// <summary>
    /// Sets the test result to Warning.
    /// </summary>
    Warn : "Warning",
    /// <summary>
    /// Sets the test result to Error.
    /// </summary>
    Error : "Error"
};

/// <summary>
/// SupportedBrowsers struct defines the supported browser names for Surgient 
/// applications.
/// </summary>
SupportedBrowsers = {
    /// <summary>
    /// Sets the test result to InternetExplorer.
    /// </summary>
    InternetExplorer : 0,
    /// <summary>
    /// Sets the test result to Firefox.
    /// </summary>
    Firefox : 1,
    /// <summary>
    /// Sets the test result to Other.
    /// </summary>
    Other : 2
};

/// <summary>
/// StatusTemplates are HTML snippets used to display the status of a given test in 
/// the status table.
/// </summary>
StatusTemplates = {
    /// <summary>
    /// Sets the template to the testing display.
    /// </summary>
    Testing : '<img src="/URA/img/indicator.gif" alt="Checking icon" />Checking...',
    /// <summary>
    /// Sets the template to the Pass display.
    /// </summary>
    Pass : '<img src="/URA/img/pass-icon.gif" alt="Passed icon" />Passed',
    /// <summary>
    /// Sets the template to the Fail display.
    /// </summary>
    Fail : '<img src="/URA/img/fail-icon.gif" alt="Failed icon" />Failed',
    /// <summary>
    /// Sets the template to the Warning display.
    /// </summary>
    Warn : '<img src="/URA/img/warning-icon.gif" alt="Warning icon" />Warning',
    /// <summary>
    /// Sets the template to the Error display.
    /// </summary>
    Error : '<img src="/URA/img/warning-icon.gif" alt="Error icon" />Problem Encountered'
};

/// <summary>
/// HelpsTemplates are HTML snippets used to display the help links of a given test in 
/// the status table.
/// </summary>
HelpTemplates = {
    /// <summary>
    /// Sets the template to the Browser Test
    /// </summary>
    BrowserTest: "<a href='#' onclick='javascript:LaunchHelp(\"5001\");'>More Information</a>",
    /// <summary>
    /// Sets the template to the Javascript Test
    /// </summary>
    JavascriptTest: "<a href='#' onclick='javascript:LaunchHelp(\"5001\");'>More Information</a>",
    /// <summary>
    /// Sets the template to the Frames Test
    /// </summary>
    FramesTest: "<a href='#' onclick='javascript:LaunchHelp(\"5001\");'>More Information</a>",
    /// <summary>
    /// Sets the template to the Cookis Test
    /// </summary>
    CookiesTest: "<a href='#' onclick='javascript:LaunchHelp(\"5001\");'>More Information</a>",
    /// <summary>
    /// Sets the template to the Bandwidth Test
    /// </summary>
    BandwidthTest: "<a href='#' onclick='javascript:LaunchHelp(\"5001\");'>More Information</a>",
    /// <summary>
    /// Sets the template to the Connections Test
    /// </summary>
    ConnectionsTest: "<a href='#' onclick='javascript:LaunchHelp(\"5001\");'>More Information</a>",
    /// <summary>
    /// Sets the template to the Embedded Content Test
    /// </summary>
    ContentTest: "<a href='#' onclick='javascript:LaunchHelp(\"5001\");'>More Information</a>"
};

function OpenHelp(location){
    window.open(location, 'Help', 'width=500,height=500,scrollbars=yes,resizable=yes');
    return false;
}

/// <summary>
/// Method takes a current and baseline string matching a Java version number
/// and compares the two to see if the current version is >= the baseline. 
/// </summary>
/// <param name="currentVersion" type="string">string version of the current JVM</param>
/// <param name="baselineVersion" type="string">string version of the baseline JVM</param>
/// <return type="boolean">true if current version is >= baseline</return>
function CompareJavaVersions(currentVersion, baselineVersion){
    if(currentVersion == "" || currentVersion.toLowerCase() == "unavailable" ||
        baselineVersion == "" || baselineVersion.toLowerCase() == "unavailable"){
        return false;
    }
    var curMajor = new Array();
    var curMinor = 0;
    var reqMajor = new Array();
    var reqMinor = 0;

    var cur = currentVersion.split("_");
    curMajor = cur[0].split(".");
    if(currentVersion.indexOf("_") != -1){
        curMinor = cur[1];
    }

    var req = baselineVersion.split("_");
    reqMajor = req[0].split(".");
    if(baselineVersion.indexOf("_") != -1){
        reqMinor = req[1];
    }

    var len;
    // only cycle through to the length of the longest array
    (reqMajor.length >= curMajor.length)? len = curMajor.length : len = reqMajor.length;
    for(var i = 0; i < len; i++){
        var reqInt = parseInt(reqMajor[i]);
        var curInt = parseInt(curMajor[i]);
        // if any slot in the required version number is greater than the 
        // same slot in the current version number, the test must return false
        if(reqInt > curInt){
            return false;
        }
        // if any index of the current version is greater than the required version
        // we can return true
        if(curInt > reqInt){
            return true;
        }
    }
    
    if(reqMinor != 0){
        // trim leading zeros from the minor versions
        while (reqMinor.substr(0, 1) == "0")
        {
            reqMinor = reqMinor.substr(1, reqMinor.length - 1);
        }
    }

    if(curMinor != 0){
        while (curMinor.substr(0, 1) == "0")
        {
            curMinor = curMinor.substr(1, curMinor.length - 1);
        }
    }

    // if the required minor version is greater than the current 
    // minor version 
    if(parseInt(reqMinor) > parseInt(curMinor)){
        return false;
    } else {
        return true;
    }
}

/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/

/// <summary>
/// Abstract class for BrowserTest objects.
/// </summary>
function BrowserTest (id, statusRowId, dataRowId, helpRowId){
/// region : inheritance --------------------------------------------
    this.base = BaseObject;
    this.base(id, statusRowId, dataRowId);

/// region : private fields -----------------------------------------
    this._statusRowId = statusRowId;
    this._statusRow = null;
    this._dataRowId = dataRowId;
    this._dataRow = null;
    this._helpRowId = helpRowId;
    this._helpRow = null;
    // the following are local overrides of the global StatusTemplates strings 
    // used to update the status section of the tests.  By default these are empty
    // but concrete BrowserTest objects may override the empty property with a custom 
    // status line for each state to differentiate themselves as needed.
    this.testingStatus = "";
    this.passStatus = "";
    this.failStatus = "";
    this.warnStatus = "";
    this.errorStatus = "";

/// region : Properties ---------------------------------------------
    /// <summary>
    /// Gets/sets the the results value for the test.  Set to BrowserTestResults.Fail 
    /// until the test has been executed.
    /// </summary>
    this.TestResult = BrowserTestResults.Fail;

    /// <summary>
    /// Gets/sets the target IFrame that tests can use for execution.
    /// </summary>
    this.TargetFrame = null;

/// region : Methods ------------------------------------------------
    /// <summary>
    /// Noop alerts the user that the calling method has not been implemented by the class.
    /// </summary>
    /// <param name="configSettings">array of <see cref="URAConfigSetting"/> settings to use</param>
    function _noop(caller){
        alert(caller + ' method must be overridden by implementing class');
    }

    /// <summary>
    /// Method executes the test and upon completion raises the OnComplete event.  In 
    /// the case of an error during execution, the test raises the OnError event.
    /// </summary>
    this.execute = _execute;
    function _execute(){
        _noop("execute()");
    }

    /// <summary>
    /// Method binds all the required HTML elements to the test so that it can update the 
    /// display with the current info/results of the test.
    /// </summary>
    this.init = _init;
    function _init(){
        this._statusRow = document.getElementById(this._statusRowId);
        this._dataRow = document.getElementById(this._dataRowId);
        this._helpRow = document.getElementById(this._helpRowId);
        if(this._statusRow == null || this._dataRow == null || this._helpRow == null){
            log.info("[" + this._getClass + "]:  unable to locate required HTML elements."); 
            throw this._newError("Invalid DOM structure for test page.");
        }
    }

    /// <summary>
    /// Replaces the innerHTML of the status row for this BrowserTest so that it shows the 
    /// current state of the control.  By default the status row should be set to the "checking"
    /// state by the asp.net page, this method changes that to show the results of the test once 
    /// execution is complete.
    /// </summary>
    this._updateStatus = _updateStatus;
    function _updateStatus(){
        var newHtml = "";
        switch(this.TestResult){
            case BrowserTestResults.Pass :
                if(this.passStatus == ""){
                    newHtml = StatusTemplates.Pass;
                } else {
                    newHtml = this.passStatus
                }
                break;
            case BrowserTestResults.Fail : 
                if(this.failStatus == ""){
                    newHtml = StatusTemplates.Fail;
                } else {
                    newHtml = this.failStatus;
                }
                break;
            case BrowserTestResults.Error :
                if(this.errorStatus == ""){
                    newHtml = StatusTemplates.Error;
                } else {
                    newHtml = this.errorStatus;
                }
                break;
            case BrowserTestResults.Warn :
                if(this.warnStatus == ""){
                    newHtml = StatusTemplates.Warn;
                } else {
                    newHtml = this.warnStatus;
                }
                break;
        }

        this._statusRow.innerHTML = newHtml;
    }
    
        /// <summary>
    /// Replaces the innerHTML of the help row for this BrowserTest so that it shows the 
    /// current state of the control.  
    /// </summary>
    this._updateHelp = _updateHelp;
    function _updateHelp(_template){
        var helpHtml = "<span></span>";
        switch(this.TestResult){
    // Don't show help for passed tests.
    //      case BrowserTestResults.Pass : 
    //          helpHtml = _template;
    //          break;
            case BrowserTestResults.Fail : 
                helpHtml = _template;
                break;
            case BrowserTestResults.Error :
                helpHtml = _template;
                break;
            case BrowserTestResults.Warn :
                helpHtml = _template;
                break;
        }
        this._helpRow.innerHTML = helpHtml
    }

    /// <summary>
    /// Replaces the innerHTML of the data row for this BrowserTest so that it shows the 
    /// results of the test.
    /// </summary>
    this._updateData = _updateData;
    function _updateData(){
        _noop("_updateData()");
    }

    /// <summary>
    /// Gets a string representation of the test result details.
    /// </summary>
    this.getDetails = _getDetails;
    function _getDetails(){
        _noop("getDetails()");
    }

    /// <summary>
    /// Private method takes a BrowserTestResults value and returns 
    /// the proper label for it.
    /// </summary>
    this._getTestResultString = _getTestResultString;
    function _getTestResultString(result){
        switch (result){
            case BrowserTestResults.Pass :
                return BrowserTestResultsLabel.Pass;
            case BrowserTestResults.Fail : 
                return BrowserTestResultsLabel.Fail;
            case BrowserTestResults.Error : 
                return BrowserTestResultsLabel.Error;
            case BrowserTestResults.Warn : 
                return BrowserTestResultsLabel.Warn;
        }
    }

/// region : Event Delegates ----------------------------------------
    /// <summary>
    /// Event delegate for the OnComplete event.
    /// </summary>
    /// <param name="sender" type="object">this object</param>
    /// <param name="args" type="object">any event arguments for this object</param>
    this.OnComplete = null;

    /// <summary>
    /// Event delegate for the OnError event.
    /// </summary>
    /// <param name="sender" type="object">this object</param>
    /// <param name="args" type="object">any event arguments for this object</param>
    this.OnError = null;
}

/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/

/// <summary>
/// BrowserTest class for determining whether or not the current browser is 
/// a Surgient supported browser type.
/// </summary>
function BrowserCapsTest (id, statusRowId, dataRowId, helpRowId){
/// region : inheritance --------------------------------------------
    this.base = BrowserTest;
    this.base(id, statusRowId, dataRowId, helpRowId);

/// region : private fields -----------------------------------------
    var agt = navigator.userAgent.toLowerCase();
    var ver = navigator.appVersion.toLowerCase();
    var minVer = parseFloat(ver);
    var majVer = parseInt(minVer);

    // specific version parsing for IE
    var isMac = (agt.indexOf("mac")!=-1);
    var iePos  = ver.indexOf('msie');
    if (iePos != -1) {
       if(isMac) {
           var iePos = agt.indexOf('msie');
           minVer = agt.substring(iePos+5, agt.indexOf(';',iePos));
       }
       else {
           minVer = ver.substring(iePos+5, ver.indexOf(';',  iePos));
       }
       majVer = parseInt(minVer);
    }

    // Netscape and Mozilla browser detect
    this._isNav = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
                && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
                && (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
    this._isNav6Up = (this._isNav && (majVer >= 5));
    this._isGecko = ((agt.indexOf('gecko') != -1) && (agt.indexOf('safari') == -1) && 
                    (agt.indexOf('konqueror') == -1));
    this._isFFX = ((agt.indexOf('mozilla/5') != -1) && (agt.indexOf('spoofer') == -1) &&
                 (agt.indexOf('compatible') == -1) && (agt.indexOf('opera') == -1)  &&
                 (agt.indexOf('webtv') == -1) && (agt.indexOf('hotjava') == -1)     &&
                 (this._isGecko) && ((navigator.vendor=="Firefox")||(agt.indexOf('firefox')!=-1)));

    // specific version parsing for firefox
    if(this._isFFX){
        var isMozVer = agt.indexOf('firefox/');
        isMozVer = agt.substring(isMozVer + 8);
        minVer = isMozVer;
        majVer = parseInt(minVer);
    }

    // IE browser detect
    this._isIE     = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
    this._isIE3    = (this._isIE && (majVer < 4));
    this._isIE4    = (this._isIE && (majVer == 4) && (agt.indexOf("msie 4")!=-1) );
    this._isIE4up  = (this._isIE && (majVer >= 4));
    this._isIE5    = (this._isIE && (majVer == 5) && (agt.indexOf("msie 5.0")!=-1) );
    this._isIE5_5  = (this._isIE && (majVer >= 5) && (agt.indexOf("msie 5.5") !=-1));
    this._isIE5up  = (this._isIE && !this._isIE3 && !this._isIE4);
    this._isIE5_5up =(this._isIE && !this._isIE3 && !this._isIE4 && !this._isIE5);
    this._isIE6    = (this._isIE && (majVer == 4) && (agt.indexOf("msie 6.")!=-1) );
    this._isIE6up  = (this._isIE && !this._isIE3 && !this._isIE4 && !this._isIE5 && !this._isIE5_5); 
    
    // 64bit IE browser detect
    this._is64Bit = false;
    if(this._isIE){
        this._is64Bit  = ((agt.indexOf("x64") != -1) && (agt.indexOf("win64") != -1));
    } else {
        // currently no test for Firefox in 64-bit mode
    }


/// region : Properties ---------------------------------------------
    /// <summary>
    /// Gets/sets the browser name of the navigator object
    /// </summary>
    this.BrowserName = "";
    
    /// <summary>
    /// Gets/sets the appName of the navigator object.
    /// </summary>
    this.AppName = (this._isFFX)? "Firefox" : navigator.appName;

    /// <summary>
    /// Gets/sets the appVersion of the navigator object.
    /// </summary>
    this.AppVersion = majVer;

    /// <summary>
    /// Gets/sets the appMinorVersion of the navigator object.
    /// </summary>
    this.AppMinorVersion = minVer;

    /// <summary>
    /// Gets/sets the appCodeName of the navigator object.
    /// </summary>
    this.AppCodeName = navigator.appCodeName;

    /// <summary>
    /// Gets/sets the platform of the navigator object.
    /// </summary>
    this.Platform = navigator.platform;

    /// <summary>
    /// Gets/sets the oscpu of the navigator object.
    /// </summary>
    this.OSCPU = navigator.oscpu;

    /// <summary>
    /// Gets/sets the cpuClass of the navigator object.
    /// </summary>
    this.CPUClass = navigator.cpuClass;

    /// <summary>
    /// Gets/sets the userAgent of the navigator object.
    /// </summary>
    this.UserAgent = navigator.userAgent;

    /// <summary>
    /// Gets/sets the mimeTypes of the navigator object.
    /// </summary>
    this.MimeTypes = new Array();
    try{
        this.MimeTypes = navigator.mimeTypes;
    } catch (e){}

    /// <summary>
    /// Gets/sets the plugins of the navigator object.
    /// </summary>
    this.Plugins = new Array();
    try{
        this.Plugins = navigator.plugins;
    } catch (e){}


/// region : Methods ------------------------------------------------
    /// <summary>
    /// Method executes the test and upon completion raises the OnComplete event.  In 
    /// the case of an error during execution, the test raises the OnError event.
    /// </summary>
    this.execute = _execute;
    function _execute(){
        log.info("[" + this.Id + "]:  BrowserCapsTest beginning execution."); 
        if(this._isFFX){
            this.BrowserName = SupportedBrowsers.Firefox;
            this.TestResult = BrowserTestResults.Pass;
        } else if(this._isIE6up) {
            this.BrowserName = SupportedBrowsers.InternetExplorer;
            if(this._is64Bit){
                this.TestResult = BrowserTestResults.Fail;
            } else {
                this.TestResult = BrowserTestResults.Pass;
            }
        } else {
            this.BrowserName = SupportedBrowsers.Other;
            this.TestResult = BrowserTestResults.Fail;
        }
        this._updateStatus();
        this._updateHelp(HelpTemplates.BrowserTest);
        this._updateData();
        log.info("[" + this.Id + "]: BrowserCapsTest completed execution.");
        this._raiseEvent("OnComplete", null);
    }

    /// <summary>
    /// Replaces the innerHTML of the data row for this BrowserTest so that it shows the 
    /// results of the test.
    /// *** NOTE: ***  _updateData expects the following DOM structure for a given data row:
    /// <tr> 
    ///     <td> Static Field Label </td>
    ///     <td> dynamic results field </td>
    ///     <td> dynamic details field </td>
    /// </tr>
    /// </summary>
    this._updateData = _updateData;
    function _updateData(){
        // update the 2nd cell 
        switch (this.TestResult){
            case BrowserTestResults.Pass :
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Pass;
                break;
            case BrowserTestResults.Fail : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Fail;
                break;
            case BrowserTestResults.Error : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Error;
                break;
        }

        this._dataRow.cells[2].innerHTML = this.AppName + "&nbsp;" + this.AppMinorVersion;
    
    }

    /// <summary>
    /// Gets a string representation of the test result details.
    /// </summary>
    this.getDetails = _getDetails;
    function _getDetails(){
        return this.AppName + " " + this.AppMinorVersion;
    }

    /// <summary>
    /// Method returns the browser capabilities in an HTML format.
    /// </summary>
    /// <return type="string">the HTML formatted browser capabilities</return>
    this.getBrowserCaps = _getBrowserCaps;
    function _getBrowserCaps(){
        log.info("[" + this.Id + "]: BrowserCapsTest getBrowserCaps.");
        var output = "";
        output += "<br/><p>";
        output += "AppName:&nbsp;&nbsp;&nbsp;" + this.AppName + "<br/>";
        output += "AppVersion:&nbsp;&nbsp;&nbsp;" + this.AppVersion + "<br/>";
        output += "AppMinorVersion:&nbsp;&nbsp;&nbsp;" + this.AppMinorVersion + "<br/>";
        output += "AppCodeName:&nbsp;&nbsp;&nbsp;" + this.AppCodeName + "<br/>";
        output += "Platform:&nbsp;&nbsp;&nbsp;" + this.Platform + "<br/>";
        output += "OS CPU:&nbsp;&nbsp;&nbsp;" + this.OSCPU + "<br/>";
        output += "CPU Class:&nbsp;&nbsp;&nbsp;" + this.CPUClass + "<br/>";
        output += "UserAgent:&nbsp;&nbsp;&nbsp;" + this.UserAgent + "<br/>";
        output += "64-Bit:&nbsp;&nbsp;&nbsp;" + this._is64Bit + "<br/>";

        output += "Plugins:&nbsp;&nbsp;&nbsp;";
        if(this.Plugins.length > 0) {
            output += '<ul style="margin-left:40px;">';
            for(var i = 0; i < this.Plugins.length; i++){
                output += "<li>" + this.Plugins[i].name + "</li>";
            }
            output += "</ul> <br/>";
        } else {
            output += "N/A <br/>";
        } 
        
        output += "</p><br/>";
        return output;
    }

    /// <summary>
    /// Method returns the browser capabilities in a string format.
    /// </summary>
    /// <return type="string">the formatted browser capabilities</return>
    this.getBrowserCapsDetails = _getBrowserCapsDetails;
    function _getBrowserCapsDetails(){
        var output = "";
        output += "AppName:   " + this.AppName + "\n";
        output += "AppVersion:   " + this.AppVersion + "\n";
        output += "AppMinorVersion:   " + this.AppMinorVersion + "\n";
        output += "AppCodeName:   " + this.AppCodeName + "\n";
        output += "Platform:   " + this.Platform + "\n";
        output += "OS CPU:   " + this.OSCPU + "\n";
        output += "CPU Class:   " + this.CPUClass + "\n";
        output += "UserAgent:   " + this.UserAgent + "\n";
        output += "64-Bit:   " + this._is64Bit + "\n";

        output += "Plugins:   \n";
        if(this.Plugins.length > 0) {
            for(var i = 0; i < this.Plugins.length; i++){
                output += "          " + this.Plugins[i].name + "\n";
            }
            output += "\n";
        } else {
            output += "N/A \n";
        } 
        
        output += "\n";
        return output;
    }
}

/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/

/// <summary>
/// BrowserTest class for determining whether or not javascript is enabled on 
/// the client.  This uses ASP.Net's built in browser capabilities check to 
/// verify scripting.  If the user's browser has scripting disabled this test 
/// may return a false positive, but the rest of the test execution will fail 
/// to run as well.
/// </summary>
function JavascriptTest (id, statusRowId, dataRowId, helpRowId){
/// region : inheritance --------------------------------------------
    this.base = BrowserTest;
    this.base(id, statusRowId, dataRowId, helpRowId);

/// region : private fields -----------------------------------------
    this._isJSEnabled = gIsJsEnabled;

/// region : Properties ---------------------------------------------
    /// <summary>
    /// Gets/sets the version of Javascript supported by the browser
    /// </summary>
    this.JsVersion = gJsVersion;

/// region : Methods ------------------------------------------------
    /// <summary>
    /// Method executes the test and upon completion raises the OnComplete event.  In 
    /// the case of an error during execution, the test raises the OnError event.
    /// </summary>
    this.execute = _execute;
    function _execute(){
        log.info("[" + this.Id + "]: JavascriptTest begin execution.");
        if(this._isJSEnabled){
            this.TestResult = BrowserTestResults.Pass;
        } else {
            this.TestResult = BrowserTestResults.Fail;
        }
        this._updateStatus();
        this._updateHelp(HelpTemplates.JavascriptTest);
        this._updateData();
        log.info("[" + this.Id + "]: JavascriptTest end execution.");
        this._raiseEvent("OnComplete", null);
    }

    /// <summary>
    /// Replaces the innerHTML of the data row for this BrowserTest so that it shows the 
    /// results of the test.
    /// *** NOTE: ***  _updateData expects the following DOM structure for a given data row:
    /// <tr> 
    ///     <td> Static Field Label </td>
    ///     <td> dynamic results field </td>
    ///     <td> dynamic details field </td>
    /// </tr>
    /// </summary>
    this._updateData = _updateData;
    function _updateData(){
        // update the 2nd cell 
        switch (this.TestResult){
            case BrowserTestResults.Pass :
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Pass;
                this._dataRow.cells[2].innerHTML = "JavaScript version: " + this.JsVersion;
                break;
            case BrowserTestResults.Fail : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Fail;
                this._dataRow.cells[2].innerHTML = "JavaScript Disabled or Unavailable";
                break;
            case BrowserTestResults.Error : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Error;
                this._dataRow.cells[2].innerHTML = "Test Error";
                break;
        }
    }

    /// <summary>
    /// Gets a string representation of the test result details.
    /// </summary>
    this.getDetails = _getDetails;
    function _getDetails(){
        switch (this.TestResult){
            case BrowserTestResults.Pass :
                return "JavaScript version: " + this.JsVersion;
            case BrowserTestResults.Fail : 
                return "JavaScript Disabled or Unavailable";
            case BrowserTestResults.Error : 
                return "Test Error";
        }
    }
}

/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/

/// <summary>
/// BrowserTest class for determining whether or not frames is enabled on 
/// the client.  This uses ASP.Net's built in browser capabilities check to 
/// verify frames support.
/// </summary>
function FramesTest (id, statusRowId, dataRowId, helpRowId){
/// region : inheritance --------------------------------------------
    this.base = BrowserTest;
    this.base(id, statusRowId, dataRowId, helpRowId);

/// region : private fields -----------------------------------------
    this._isFramesEnabled = gFramesEnabled;

/// region : Properties ---------------------------------------------

/// region : Methods ------------------------------------------------
    /// <summary>
    /// Method executes the test and upon completion raises the OnComplete event.  In 
    /// the case of an error during execution, the test raises the OnError event.
    /// </summary>
    this.execute = _execute;
    function _execute(){
        log.info("[" + this.Id + "]: FramesTest begin execution.");
        if(this._isFramesEnabled){
            this.TestResult = BrowserTestResults.Pass;
        } else {
            this.TestResult = BrowserTestResults.Fail;
        }
        this._updateStatus();
        this._updateHelp(HelpTemplates.FramesTest);
        this._updateData();
        log.info("[" + this.Id + "]: FramesTest end execution.");
        this._raiseEvent("OnComplete", null);
    }

    /// <summary>
    /// Replaces the innerHTML of the data row for this BrowserTest so that it shows the 
    /// results of the test.
    /// *** NOTE: ***  _updateData expects the following DOM structure for a given data row:
    /// <tr> 
    ///     <td> Static Field Label </td>
    ///     <td> dynamic results field </td>
    ///     <td> dynamic details field </td>
    /// </tr>
    /// </summary>
    this._updateData = _updateData;
    function _updateData(){
        // update the 2nd cell 
        switch (this.TestResult){
            case BrowserTestResults.Pass :
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Pass;
                this._dataRow.cells[2].innerHTML = "Frames supported";
                break;
            case BrowserTestResults.Fail : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Fail;
                this._dataRow.cells[2].innerHTML = "Frames unsupported";
                break;
            case BrowserTestResults.Error : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Error;
                this._dataRow.cells[2].innerHTML = "Test Error";
                break;
        }
    }

    /// <summary>
    /// Gets a string representation of the test result details.
    /// </summary>
    this.getDetails = _getDetails;
    function _getDetails(){
        switch (this.TestResult){
            case BrowserTestResults.Pass :
                return "Frames supported";
            case BrowserTestResults.Fail : 
                return "Frames unsupported";
            case BrowserTestResults.Error : 
                return "Test Error";
        }
    }
}

/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/

/// <summary>
/// BrowserTest class for determining whether or not cookies is enabled on 
/// the client.  This uses ASP.Net's built in browser capabilities check to 
/// verify frames support.
/// </summary>
function CookiesTest (id, statusRowId, dataRowId, helpRowId){
/// region : inheritance --------------------------------------------
    this.base = BrowserTest;
    this.base(id, statusRowId, dataRowId, helpRowId);

/// region : private fields -----------------------------------------
    this._isCookiesEnabled = navigator.cookieEnabled;
    this._isServerCookiesEnabled = gCookiesEnabled;

/// region : Properties ---------------------------------------------

/// region : Methods ------------------------------------------------
    /// <summary>
    /// Method executes the test and upon completion raises the OnComplete event.  In 
    /// the case of an error during execution, the test raises the OnError event.
    /// </summary>
    this.execute = _execute;
    function _execute(){
        log.info("[" + this.Id + "]: CookiesTest begin execution.");
        if(this._isCookiesEnabled || this._isServerCookiesEnabled){
            if(this._setCookie()){
                if(this._getCookie()){
                    if(this._deleteCookie()){
                        this.TestResult = BrowserTestResults.Pass;
                    } else {
                        log.info("[" + this.Id + "]: CookiesTest unable to delete cookie.");
                        this.TestResult = BrowserTestResults.Fail;
                    }
                } else {
                    log.info("[" + this.Id + "]: CookiesTest unable to retrieve cookie.");
                    this.TestResult = BrowserTestResults.Fail;
                }
            } else {
                log.info("[" + this.Id + "]: CookiesTest unable to write cookie.");
                this.TestResult = BrowserTestResults.Fail;
            }
        } else {
            this.TestResult = BrowserTestResults.Fail;
        }
        this._updateStatus();
        this._updateHelp(HelpTemplates.CookiesTest);
        this._updateData();
        log.info("[" + this.Id + "]: CookiesTest end execution.");
        this._raiseEvent("OnComplete", null);
    }

    /// <summary>
    /// Private method to try writing a cookie.
    /// </summary>
    this._setCookie = _setCookie;
    function _setCookie(){
        try{
            document.cookie = "surgienturt=urt";
            return true;
        } catch (e) {
            return false;
        }
    }

    /// <summary>
    /// Private method to try retrieving a cookie.
    /// </summary>
    this._getCookie = _getCookie;
    function _getCookie(){
        var token = "surgienturt=urt";
        try{
        if(document.cookie.indexOf(token) != -1){
            return true;
        } else {
            return false;
        }
        } catch (e) {
            return false;
        }
    }

    /// <summary>
    /// Private method to delete a cookie.
    /// </summary>
    this._deleteCookie = _deleteCookie;
    function _deleteCookie(){
        var exp = new Date();
        exp.setTime (exp.getTime() - 1);
        try{
            document.cookie = "surgienturt=urt; expires=" + exp.toGMTString();
            return true;
        }
        catch (e){
            return false;
        }
    }

    /// <summary>
    /// Replaces the innerHTML of the data row for this BrowserTest so that it shows the 
    /// results of the test.
    /// *** NOTE: ***  _updateData expects the following DOM structure for a given data row:
    /// <tr> 
    ///     <td> Static Field Label </td>
    ///     <td> dynamic results field </td>
    ///     <td> dynamic details field </td>
    /// </tr>
    /// </summary>
    this._updateData = _updateData;
    function _updateData(){
        // update the 2nd cell 
        switch (this.TestResult){
            case BrowserTestResults.Pass :
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Pass;
                this._dataRow.cells[2].innerHTML = "Cookies enabled";
                break;
            case BrowserTestResults.Fail : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Fail;
                this._dataRow.cells[2].innerHTML = "Cookies disabled";
                break;
            case BrowserTestResults.Error : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Error;
                this._dataRow.cells[2].innerHTML = "Test Error";
                break;
        }
    }

    /// <summary>
    /// Gets a string representation of the test result details.
    /// </summary>
    this.getDetails = _getDetails;
    function _getDetails(){
        switch (this.TestResult){
            case BrowserTestResults.Pass :
                return "Cookies enabled";
            case BrowserTestResults.Fail : 
                return "Cookies disabled";
            case BrowserTestResults.Error : 
                return "Test Error";
        }
    }
}

/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/

/// <summary>
/// BrowserTest class for determining the bandwidth available over the network 
/// from the client to the server.
/// </summary>
function BandwidthTest (id, statusRowId, dataRowId, helpRowId){
/// region : inheritance --------------------------------------------
    this.base = BrowserTest;
    this.base(id, statusRowId, dataRowId, helpRowId);

/// region : private fields -----------------------------------------
    this._startTime = 0;
    this._endTime = 0;
    this._timeDiff = 0;
    this._downloadKb = 1578.3; // size of img/browsertest.jpg file in Kb
    this._testDiv = null;
    this._bandwidth = 0;

/// region : Properties ---------------------------------------------
    /// <summary>
    /// Gets/sets the minimum bandwidth in Kilobytes.
    /// </summary>
    this.MinBandwidth = 25;

    /// <summary>
    /// Gets/sets the preferred bandwidth in Kilobytes.
    /// </summary>
    this.PrefBandwidth = 100;

/// region : Methods ------------------------------------------------
    /// <summary>
    /// Method executes the test and upon completion raises the OnComplete event.  In 
    /// the case of an error during execution, the test raises the OnError event.
    /// </summary>
    this.execute = _execute;
    function _execute(){
        log.info("[" + this.Id + "]: BandwidthTest begin execution.");
        this._writeHtml();
    }

    /// <summary>
    /// Replaces the innerHTML of the data row for this BrowserTest so that it shows the 
    /// results of the test.
    /// *** NOTE: ***  _updateData expects the following DOM structure for a given data row:
    /// <tr> 
    ///     <td> Static Field Label </td>
    ///     <td> dynamic results field </td>
    ///     <td> dynamic details field </td>
    /// </tr>
    /// </summary>
    this._updateData = _updateData;
    function _updateData(){
        // update the 2nd cell 
        switch (this.TestResult){
            case BrowserTestResults.Pass :
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Pass;
                break;
            case BrowserTestResults.Fail : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Fail;
                break;
            case BrowserTestResults.Error : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Error;
                break;
        }

        if(this.TestResult == BrowserTestResults.Error){
            this._dataRow.cells[2].innerHTML = "Test Error";
        } else {
            var newHtml = "";
            if(this._bandwidth < this.MinBandwidth) {
                newHtml += "Bandwidth Assessment: Slow <br/>";
                newHtml += "Tested bandwidth: " + this._bandwidth + " Kilobytes/second";
            } else if(this._bandwidth > this.MinBandwidth && this._bandwidth < this.PrefBandwidth) {
                newHtml += "Bandwidth Assessment: Acceptable <br/>";
                newHtml += "Tested bandwidth: " + this._bandwidth + " Kilobytes/second";
            } else if(this._bandwidth > this.PrefBandwidth) {
                newHtml += "Bandwidth Assessment: Preferred <br/>";
                newHtml += "Tested bandwidth: " + this._bandwidth + " Kilobytes/second";
            }
            this._dataRow.cells[2].innerHTML = newHtml;
        }
    }

    /// <summary>
    /// Gets a string representation of the test result details.
    /// </summary>
    this.getDetails = _getDetails;
    function _getDetails(){
        if(this.TestResult == BrowserTestResults.Error){
            return "Test Error";
        } else {
            var newHtml = "";
            if(this._bandwidth < this.MinBandwidth) {
                newHtml += "Bandwidth Assessment: Slow \n";
                newHtml += "Tested bandwidth: " + this._bandwidth + " Kilobytes/second";
            } else if(this._bandwidth > this.MinBandwidth && this._bandwidth < this.PrefBandwidth) {
                newHtml += "Bandwidth Assessment: OK \n";
                newHtml += "Tested bandwidth: " + this._bandwidth + " Kilobytes/second";
            } else if(this._bandwidth > this.PrefBandwidth) {
                newHtml += "Bandwidth Assessment: Good \n";
                newHtml += "Tested bandwidth: " + this._bandwidth + " Kilobytes/second";
            }
            return newHtml;
        }
    }

    /// <summary>
    /// Method creates the required DIV element to house the test and appends it to the document.
    /// </summary>
    this._writeHtml = _writeHtml;
    function _writeHtml(){
       this._testDiv = document.createElement('DIV');
       this._testDiv.style.position = "absolute";
       this._testDiv.style.top = "0px";
       this._testDiv.style.left = "-2500px";
       this._testDiv.style.width = "2px";
       this._testDiv.style.height = "2px";
       this._testDiv.style.overflow = "hidden";
       document.body.appendChild(this._testDiv);
       window.setTimeout(this.Id + "._writeTest();", 50);
    }

    /// <summary>
    /// Method writes the test image tag into the test DIV's innerHtml and waits for the 
    /// events to finish test execution.
    /// </summary>
    this._writeTest = _writeTest;
    function _writeTest(){
        this._startTime = (new Date()).getTime();
        var ln = '<img id="img1" src="img/browsertest.jpg?n=' + this._startTime + '" ' +
           'onLoad="' + this.Id + '._handleTestResults();" onAbort="' + this.Id + '._handleTestError(0);" ' + 
           'onError="' + this.Id + '._handleTestError(1);">';
        this._testDiv.innerHTML = ln;
    }

    /// <summary>
    /// Method handles successful test results for the bandwidth test.
    /// </summary>
    this._handleTestResults = _handleTestResults;
    function _handleTestResults(){
        this._endTime = (new Date()).getTime();
        this._timeDiff = (this._endTime - this._startTime) / 1000;
        this._bandwidth = Math.floor(this._downloadKb / this._timeDiff);  
        // fail if less than this.MinBandwidth
        if(this._bandwidth < this.MinBandwidth) {
            this.TestResult = BrowserTestResults.Fail;
        } else {
            this.TestResult = BrowserTestResults.Pass;
        }

        this._updateStatus();
        this._updateHelp(HelpTemplates.BandwidthTest);
        this._updateData();
        log.info("[" + this.Id + "]: BandwidthTest end execution.");
        this._raiseEvent("OnComplete", null);
    }

    /// <summary>
    /// Method handles test error or abort issues with the bandwidth test.
    /// </summary>
    this._handleTestError = _handleTestError;
    function _handleTestError(err){
        if(err == 0){
            log.info("[" + this.Id + "]: BandwidthTest was aborted by client browser.");
            this.TestResult = BrowserTestResults.Fail;
        } else {
            log.info("[" + this.Id + "]: BandwidthTest suffered a fatal error.");
            this.TestResult = BrowserTestResults.Fail;
        }

        this._updateStatus();
        this._updateHelp(HelpTemplates.BandwidthTest);
        this._updateData();
        log.info("[" + this.Id + "]: BandwidthTest end execution.");
        this._raiseEvent("OnComplete", null);
    }
}

/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/

/// <summary>
/// BrowserTest class for determining the browser's support for ActiveX and/or 
/// JavaApplets.
/// </summary>
function EmbeddedContentTest (id, statusRowId, dataRowId, helpRowId){
/// region : inheritance --------------------------------------------
    this.base = BrowserTest;
    this.base(id, statusRowId, dataRowId, helpRowId);

/// region : private fields -----------------------------------------
    this._isActiveXEnabled = gActiveXEnabled;
    this._isJavaEnabled = gJavaEnabled;
    this._activeXResults = BrowserTestResults.Fail;
    this._javaResults = BrowserTestResults.Fail;
    this._testApplet = null;
    this._testActiveX = null;
    this._counter = 0;
    this._minJVM = gMinJavaVersion;

/// region : Properties ---------------------------------------------
    /// <summary>
    /// Gets/sets the version of the Java Virtual Machine.
    /// </summary>
    this.JavaVersion = "";

/// region : Methods ------------------------------------------------
    /// <summary>
    /// Method executes the test and upon completion raises the OnComplete event.  In 
    /// the case of an error during execution, the test raises the OnError event.
    /// </summary>
    this.execute = _execute;
    function _execute(){
        log.info("[" + this.Id + "]: EmbeddedContentTest beginning ActiveX execution.");
        log.info("[" + this.Id + "]:  EmbeddedContentTest attempting to writing ActiveX HTML to target IFrame.");
        try{
            if( browsercaps.isMoz ){
                this.TargetFrame.document.open();
                this.TargetFrame.document.write(this.getHtml());
                this.TargetFrame.document.close();
            } else {
                this.TargetFrame.location = "javascript:parent." + this.Id + ".getHtml();";
            }
        } catch (e) {
            log.error("[" + this.Id + "]:  EmbeddedContentTest sufferred a fatal error during the .getHtml method: " + e.message);
        }
    }

    /// <summary>
    /// Method executes the test and upon completion raises the OnComplete event.  In 
    /// the case of an error during execution, the test raises the OnError event.
    /// </summary>
    this._executeApplet = _executeApplet;
    function _executeApplet(){
        log.info("[" + this.Id + "]: EmbeddedContentTest beginning Applet execution.");
        log.info("[" + this.Id + "]:  EmbeddedContentTest attempting to writing Applet HTML to target IFrame.");
        try{
            if( browsercaps.isMoz ){
                this.TargetFrame.document.open();
                this.TargetFrame.document.write(this.getJavaHtml());
                this.TargetFrame.document.close();
            } else {
                this.TargetFrame.location = "javascript:parent." + this.Id + ".getJavaHtml();";
            }
        } catch (e) {
            log.error("[" + this.Id + "]:  EmbeddedContentTest sufferred a fatal error during the .getJavaHtml method: " + e.message);
        }
    }

    /// <summary>
    /// ActiveX specific method creates the required DIV element to house the test and appends it to the document.
    /// </summary>
    this.getHtml = getHtml;
    function getHtml(){
        log.info("[" + this.Id + "]:  EmbeddedContentTest rendering test controls.");
        var html = '<html><head><title>Surgient ActiveX Version Test</title>' +
            '<script language="javascript">' +
            'function callback(){' +
            'parent.' + this.Id + '.pageReadyHandler("ActiveX");' +
            '}' +
            '</script>' +
            '<style>' + 
            'body{margin:0px;padding:0px;background-color:#E6DEC3;} ' + 
            '.bd{background-color:#E6DEC3;text-align:center;}' + 
            '.tc{background-color:#E6DEC3;text-align:center;} ' + 
            '</style></head><body onload="callback();"><div class="bd">' +  
            '<div id="' + this.Id + '_divActiveX" class="tc">' +
            '<object id="' + this.Id + '_activex" ' +
            'classid="CLSID:380BBEC2-4CAE-4ECE-8AFF-36CDE7916386" ' +
            'codebase="' + appPath + '/URA/lib/srdp.cab#Version=5,3,0,0"></object>' + 
            '</div>' +
            '</div></body></html>';
        return html;
    }

    /// <summary>
    /// Java specific method creates the required DIV element to house the test and appends it to the document.
    /// </summary>
    this.getJavaHtml = getJavaHtml;
    function getJavaHtml(){
        log.info("[" + this.Id + "]:  EmbeddedContentTest rendering test controls.");
        var html = '<html><head><title>Surgient Java Version Test</title>' +
            '<script language="javascript">' +
            'function callback(){' +
            'parent.' + this.Id + '.pageReadyHandler("Applet");' +
            '}' +
            '</script>' +
            '<style>' + 
            'body{margin:0px;padding:0px;background-color:#E6DEC3;} ' + 
            '.bd{background-color:#E6DEC3;text-align:center;}' + 
            '.tc{background-color:#E6DEC3;text-align:center;} ' + 
            '</style></head><body onload="callback();"><div class="bd">' + 
            '<div id="' + this.Id + '_divApplet" class="tc">' +
            '<applet id="' + this.Id + '_applet" code="com.surgient.appletutil.applet.PlatformDetect.class" ' + 
                'archive="' + appPath + '/URA/lib/LocalProxyApplet.jar"' + 
                ' height="0" width="0">' + 
                '<param name="logLevel" value="5" />' + 
                '<param name="cabbase" value="' + appPath + '/URA/lib/LocalProxyApplet11.cab" />' + 
            '</applet>' + 
            '</div>' + 
            '</div></body></html>';
        return html;
    }

    /// <summary>
    /// Method called by the target IFrame's document when the page has finished 
    /// loading indicating that it is ready for the URACoordinator to inject 
    /// the HTML needed for the TunnelConfig and TermClient into the appropriate 
    /// locations.
    /// </summary>
    this.pageReadyHandler = _pageReadyHandler;
    function _pageReadyHandler(ctlType){
        if(ctlType.toLowerCase() == "activex"){
            log.info("[" + this.Id + "]:  EmbeddedContentTest successfully rendered ActiveX control to page."); 
            this._testActiveX = this.TargetFrame.document.getElementById(this.Id + "_activex");
            if(this._testActiveX == null){
                log.info("[" + this.Id + "]:  EmbeddedContentTest could not find test ActiveX object.");
                // we cannot finish the activex test
                this._isActiveXEnabled = false;
                this._activeXResults = BrowserTestResults.Fail;
                // test failed so now execute the Applet test
                this._executeApplet();
            } else {
                this._setTimeout(this.Id + ".executeActiveXTest()", 500);
            }

        } else {
            log.info("[" + this.Id + "]:  EmbeddedContentTest successfully rendered Applet control to page."); 
            // get the objects inside of the IFrame
            this._testApplet = this.TargetFrame.document.getElementById(this.Id + "_applet");
            if(this._testApplet == null){
                log.info("[" + this.Id + "]:  EmbeddedContentTest could not find test Applet object.");
                this._isJavaEnabled = false;
                this._javaResults = BrowserTestResults.Fail;
                // the applet test failed, and ActiveX has already been run, so handle the results
                this._handleTestResults();
            } else {
                this._setTimeout(this.Id + ".executeAppletTest()", 500);
            }
            
        }
    }

    /// <summary>
    /// Method tests the ActiveX control for scriptability.
    /// </summary>
    this.executeActiveXTest = _executeActiveXTest;
    function _executeActiveXTest(){
        try{
            if(typeof(this._testActiveX.GetPropertyBag) != "undefined"){
                log.info("[" + this.Id + "]:  EmbeddedContentTest retrieving ActiveX information.");
                if(typeof(this._testActiveX.GetPropertyBag()) != "undefined"){
                    this._activeXResults = BrowserTestResults.Pass;
                    this._isActiveXEnabled = true;
                    log.info("[" + this.Id + "]:  EmbeddedContentTest ActiveX test passed.");
                    this._executeApplet();
                } else {
                    this._activeXResults = BrowserTestResults.Fail;
                    this._isActiveXEnabled = false;
                    log.info("[" + this.Id + "]:  EmbeddedContentTest ActiveX test failed.");
                    this._executeApplet();
                }
            } else {
                // call back to the activex after a timeout to see if it might just be having 
                // trouble initializing, but after 10 attempts, fail the test
                if(this._counter < 10){
                    this._counter++;
                    window.setTimeout(this.Id + ".executeActiveXTest()", 500);
                } else {
                    log.info("[" + this.Id + "]:  EmbeddedContentTest unable to retrieve ActiveX version.");
                    this._activeXResults = BrowserTestResults.Fail;
                    this._isActiveXEnabled = false;
                    this._executeApplet();
                }
            }
        } catch (e1){
            log.info("[" + this.Id + "]:  EmbeddedContentTest unable to retrieve ActiveX version.");
            // exceptions mean the platform isn't supported
            this._activeXResults = BrowserTestResults.Fail;
            this._isActiveXEnabled = false;
            // execute the applet test
            this._executeApplet();
        }       
    }

    /// <summary>
    /// Method tests the Applet control for scriptability.
    /// </summary>
    this.executeAppletTest = _executeAppletTest;
    function _executeAppletTest(){
        try{
            if(typeof(this._testApplet.JVMVersion()) == "undefined"){
                // call back to the applet after a timeout to see if it might just be having 
                // trouble initializing, but after 10 attempts, fail the test
                if(this._counter < 30){
                    this._counter++;
                    window.setTimeout(this.Id + ".executeAppletTest()", 500);
                } else {
                    log.info("[" + this.Id + "]:  EmbeddedContentTest unable to retrieve Java version.");
                    this.JavaVersion = "Unavailable";
                    this._isJavaEnabled = false;
                    this._javaResults = BrowserTestResults.Fail;
                    this._handleTestResults();
                }
            } else {
                log.info("[" + this.Id + "]:  EmbeddedContentTest retrieving Java version.");
                this.JavaVersion = new String(this._testApplet.JVMVersion());
                this._isJavaEnabled = true;
                this._javaResults = BrowserTestResults.Pass;
                this._handleTestResults();
            }
        } catch (e1){
            log.info("[" + this.Id + "]:  Exception handled, EmbeddedContentTest unable to retrieve Java version.");
            // exceptions mean the platform isn't supported
            this.JavaVersion = "Unavailable";
            this._javaResults = BrowserTestResults.Fail;
            this._isJavaEnabled = false;
            // execute the applet test
            this._handleTestResults();
        }   
    }

    /// <summary>
    /// Method handles successful test results for the bandwidth test.
    /// </summary>
    this._handleTestResults = _handleTestResults;
    function _handleTestResults(){
        // set the global variable for the JavaVersion
        gJavaVersion = this.JavaVersion;
        // split the way the test works based on the browser type.  Mozilla doesn't have ActiveX
        // so only test that Java is enabled and that the java version is supported
        if(browsercaps.isMoz){
            if(this._isJavaEnabled && this._javaResults == BrowserTestResults.Pass){
                if(CompareJavaVersions(this.JavaVersion, this._minJVM)){
                    this.TestResult = BrowserTestResults.Pass;
                } else {
                    this.TestResult = BrowserTestResults.Fail;
                }
            } else {
                this.TestResult = BrowserTestResults.Fail;
            }
        } else {
            // IE needs either ActiveX enabled or an enabled and supported version of Java to pass
            if(this._isActiveXEnabled && this._activeXResults == BrowserTestResults.Pass){
                this.TestResult = BrowserTestResults.Pass;
            } else {
                if(this._isJavaEnabled && this._javaResults == BrowserTestResults.Pass){
                    if(CompareJavaVersions(this.JavaVersion, this._minJVM)){
                        this.TestResult = BrowserTestResults.Pass;
                    } else {
                        this.TestResult = BrowserTestResults.Fail;
                    }
                } else {
                    this.TestResult = BrowserTestResults.Fail;
                }
            }
        }
        
        this._updateStatus();
        this._updateHelp(HelpTemplates.ContentTest);
        this._updateData();
        log.info("[" + this.Id + "]: EmbeddedContent end execution.");
        this.TargetFrame.location = "about:blank";
        log.info("[" + this.Id + "]: EmbeddedContent re-set target Frame contents.");
        this._raiseEvent("OnComplete", null);
    }

    /// <summary>
    /// Replaces the innerHTML of the data row for this BrowserTest so that it shows the 
    /// results of the test.
    /// *** NOTE: ***  _updateData expects the following DOM structure for a given data row:
    /// <tr> 
    ///     <td> Static Field Label </td>
    ///     <td> dynamic results field </td>
    ///     <td> dynamic details field </td>
    /// </tr>
    /// </summary>
    this._updateData = _updateData;
    function _updateData(){
        // update the 2nd cell 
        switch (this.TestResult){
            case BrowserTestResults.Pass :
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Pass;
                break;
            case BrowserTestResults.Fail : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Fail;
                break;
            case BrowserTestResults.Error : 
                this._dataRow.cells[1].innerHTML = BrowserTestResultsLabel.Error;
                break;
        }

        if(this.TestResult == BrowserTestResults.Error){
            this._dataRow.cells[2].innerHTML = "Test Error";
        } else {
            var newHtml = ""; 
            if(!this._isActiveXEnabled){
                newHtml += "ActiveX disabled <br/>";
            } else {
                newHtml += "ActiveX enabled <br/>";
            }

            if(!this._isJavaEnabled){
                newHtml += "Java disabled <br/>";
            } else {
                newHtml += "Java enabled <br/>"; 
                if(!CompareJavaVersions(this.JavaVersion, this._minJVM)){
                    newHtml += "Java Version: " + this.JavaVersion + " (Failed)<br/>";
                    newHtml += "Required Java Version: " + this._minJVM + "<br/>";
                } else {
                    newHtml += "Java Version: " + this.JavaVersion + " (Passed)<br/>";
                    newHtml += "Required Java Version: " + this._minJVM + "<br/>";
                }
            }

            this._dataRow.cells[2].innerHTML = newHtml;
        }
    }

    /// <summary>
    /// Gets a string representation of the test result details.
    /// </summary>
    this.getDetails = _getDetails;
    function _getDetails(){
        if(this.TestResult == BrowserTestResults.Error){
            return "Test Error";
        } else {
            var newHtml = ""; 
            if(!this._isActiveXEnabled){
                newHtml += "ActiveX disabled \n";
            } else {
                newHtml += "ActiveX enabled \n";
            }

            if(!this._isJavaEnabled){
                newHtml += "Java disabled \n";
            } else {
                newHtml += "Java enabled \n"; 
                if(!CompareJavaVersions(this.JavaVersion, this._minJVM)){
                    newHtml += "Java Version: " + this.JavaVersion + " (Failed)\n";
                    newHtml += "Required Java Version: " + this._minJVM + "\n";
                } else {
                    newHtml += "Java Version: " + this.JavaVersion + " (Passed)\n";
                    newHtml += "Required Java Version: " + this._minJVM + "\n";
                }
            }

            return newHtml;
        }
    }
}

/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/

/// <summary>
/// BrowserTest class for determining the client's support for URA connections.
/// </summary>
function ConnectionsTest (id, statusRowId, dataRowId, helpRowId){
/// region : inheritance --------------------------------------------
    this.base = BrowserTest;
    this.base(id, statusRowId, dataRowId, helpRowId);

/// region : private fields -----------------------------------------
    this._currentURAIdx = 0;
    this._testResultsList = new Array();
    this._testDetails = new Array();
    this.errorStatus = '<img src="/URA/img/warning-icon.gif" alt="Error icon" />Test Configuration Error';
    this.warnStatus = '<img src="/URA/img/warning-icon.gif" alt="Warning icon" />Passed, Connection Was Not Optimized.';


/// region : Properties ---------------------------------------------
    /// <summary>
    /// Gets the array of URACoordinators that are cycled through by 
    /// this test in an attempt to verify that each connection method is 
    /// viable.
    /// </summary>
    this.URACoordinators = new Array();

    /// <summary>
    /// Gets/sets the reference to the active URACoordinator.
    /// </summary>
    this.ActiveURA = null;

    /// <summary>
    /// Gets/sets the value of the global gJavaVersion variable and assigns it locally.
    /// </summary>
    this.JavaVersion = gJavaVersion;

/// region : Methods ------------------------------------------------
    /// <summary>
    /// Setter for the URACoordinators property.
    /// </summary>
    this.setURACoordinators = _setURACoordinators;
    function _setURACoordinators(uraCoordinators){
        this.URACoordinators = uraCoordinators;
        this._testResultsList = new Array();
        for(var i = 0; i < this.URACoordinators.length; i++){
            this._testResultsList[i] = BrowserTestResults.Fail;
        }
    }

    /// <summary>
    /// Method executes the test and upon completion raises the OnComplete event.  In 
    /// the case of an error during execution, the test raises the OnError event.
    /// </summary>
    this.execute = _execute;
    function _execute(){
        log.info("[" + this.Id + "]: ConnectionsTest begin execution.");
        // assign the JavaVersion again just in case 
        this.JavaVersion = gJavaVersion;
        log.info("[" + this.Id + "]: ConnectionsTest contains " + this.URACoordinators.length + " URACoordinators.");
        if(this.URACoordinators.length <= 0){
            log.info("[" + this.Id + "]: ConnectionsTest aborting execution, no URACoordinators available.");
            this.TestResult = BrowserTestResults.Error;
            this.finishTest();
        } else {
            // the the URACoordinator to test and assign it's event handlers
            this.ActiveURA = this.URACoordinators[this._currentURAIdx];      
            this.ActiveURA.OnLoadError = this._getHandler("onLoadErrorEventHandler");
            this.ActiveURA.OnConnectError = this._getHandler("onConnectErrorEventHandler");
            this.ActiveURA.OnConnect = this._getHandler("onConnectEventHandler");
            this.ActiveURA.OnDisconnect = this._getHandler("onDisconnectEventHandler");
            this.ActiveURA.OnLoadFailure = this._getHandler("onLoadFailureEventHandler");
            this.ActiveURA.OnConnectFailure = this._getHandler("onConnectFailureEventHandler");
            this.ActiveURA.connect();
        }
    }

    /// <summary>
    /// Event handler for the URACoordinator OnLoadError event.
    /// </summary>
    this.onLoadErrorEventHandler = _onLoadErrorEventHandler;
    function _onLoadErrorEventHandler(){
        // swallow the OnLoadError event silently until the final OnLoadFailure or OnConnectFailure event 
        // is raised 
        log.info("[" + this.Id + "]:  ConnectionsTest received OnLoadError from " + 
            this.ActiveURA.ActiveTermClient.getClass() + " tunneling via " + this.ActiveURA.ActiveTunnelConfig.getClass() + ".");
    }

    /// <summary>
    /// Event handler for the URACoordinator OnConnectError event.
    /// </summary>
    this.onConnectErrorEventHandler = _onConnectErrorEventHandler;
    function _onConnectErrorEventHandler(){
        // swallow the OnConnectError event silently until the final OnConnectFailure event 
        // is raised 
        log.info("[" + this.Id + "]:  ConnectionsTest received OnConnectError from " + 
            this.ActiveURA.ActiveTermClient.getClass() + " tunneling via " + this.ActiveURA.ActiveTunnelConfig.getClass() + ".");
    }

    /// <summary>
    /// Event handler for the URACoordinator OnConnect event.
    /// </summary>
    this.onConnectEventHandler = _onConnectEventHandler;
    function _onConnectEventHandler(){
        log.info("[" + this.Id + "]:  ConnectionsTest received OnConnect from " + 
            this.ActiveURA.ActiveTermClient.getClass() + " tunneling via " + this.ActiveURA.ActiveTunnelConfig.getClass() + ".");
        // if we connected via Java make sure we used the correct java version
        if(this.ActiveURA.ActiveTermClient.getClass().indexOf("Java") != -1 || 
            this.ActiveURA.ActiveTunnelConfig.getClass().indexOf("Java") != -1){
            if(CompareJavaVersions(this.JavaVersion, gMinJavaVersion)){
                this._testResultsList[this._currentURAIdx] = BrowserTestResults.Pass;
            } else {
                this._testResultsList[this._currentURAIdx] = BrowserTestResults.Warn;
            }
        } else {
            // pass the test on successful connection
            this._testResultsList[this._currentURAIdx] = BrowserTestResults.Pass;
        }

        // store the coordinator data in a local collection
        this._testDetails[this._currentURAIdx] = new Object();
        this._testDetails[this._currentURAIdx].TermClientType = this.ActiveURA.ActiveTermClient.getClass();
        this._testDetails[this._currentURAIdx].TunnelConfigType = this.ActiveURA.ActiveTunnelConfig.getClass();

        // call the disconnect method on the URACoordinator and wait for the disconnect event 
        // before attempting the next connection
        this.ActiveURA.abort();
    }

    /// <summary>
    /// Event handler for the URACoordinator OnDisconnect event.
    /// </summary>
    this.onDisconnectEventHandler = _onDisconnectEventHandler;
    function _onDisconnectEventHandler(){
        log.info("[" + this.Id + "]:  ConnectionsTest received OnDisconnect from " + 
            this.ActiveURA.ActiveTermClient.getClass() + " tunneling via " + this.ActiveURA.ActiveTunnelConfig.getClass() + ".");
        // the URA lifecycle is complete and ready to cycle to the next test
        this._setTimeout(this.Id + "._cycleURATest()", 100);
    }

    /// <summary>
    /// Event handler for the URACoordinator OnLoadFailure event.
    /// </summary>
    this.onLoadFailureEventHandler = _onLoadFailureEventHandler;
    function _onLoadFailureEventHandler(){
        log.info("[" + this.Id + "]:  ConnectionsTest received OnLoadFailure from " + 
            this.ActiveURA.ActiveTermClient.getClass() + " tunneling via " + this.ActiveURA.ActiveTunnelConfig.getClass() + ".");
        // fail the test on load failure--no control was able to load
        this._testResultsList[this._currentURAIdx] = BrowserTestResults.Fail;
        // store the coordinator data in a local collection
        this._testDetails[this._currentURAIdx] = new Object();
        this._testDetails[this._currentURAIdx].TermClientType = this.ActiveURA.ActiveTermClient.getClass();
        this._testDetails[this._currentURAIdx].TunnelConfigType = this.ActiveURA.ActiveTunnelConfig.getClass();

        // the test failed so the BrowserTest should cycle to the next test type
        this._setTimeout(this.Id + "._cycleURATest()", 100);
    }

    /// <summary>
    /// Event handler for the URACoordinator OnConnectFailure event.
    /// </summary>
    this.onConnectFailureEventHandler = _onConnectFailureEventHandler;
    function _onConnectFailureEventHandler(){
        log.info("[" + this.Id + "]:  ConnectionsTest received OnConnectFailure from " + 
            this.ActiveURA.ActiveTermClient.getClass() + " tunneling via " + this.ActiveURA.ActiveTunnelConfig.getClass() + ".");       
        // fail the test on connection failure--no client/tunnel combination was able to connect
        this._testResultsList[this._currentURAIdx] = BrowserTestResults.Fail;
        // store the coordinator data in a local collection
        this._testDetails[this._currentURAIdx] = new Object();
        this._testDetails[this._currentURAIdx].TermClientType = this.ActiveURA.ActiveTermClient.getClass();
        this._testDetails[this._currentURAIdx].TunnelConfigType = this.ActiveURA.ActiveTunnelConfig.getClass();

        // the test failed so the BrowserTest should cycle to the next test type
        this._setTimeout(this.Id + "._cycleURATest()", 100);
    }
    
    /// <summary>
    /// Cycles to the next URATest in the queue.  If there are no remaining tests, the method
    /// raises the test complete event.
    /// </summary>
    this._cycleURATest = _cycleURATest;
    function _cycleURATest(){
        var nextURA = this._currentURAIdx + 1;
        if(nextURA < this.URACoordinators.length){
            log.info("[" + this.Id + "]: ConnectionsTest attempting connection on next URACoordinator.");
            this._currentURAIdx = nextURA;
            this.execute();
        } else {
            this.finishTest();
        }
    }

    /// <summary>
    /// Handles the completion of the BrowserTest and any required cleanup.
    /// </summary>
    this.finishTest = _finishTest;
    function _finishTest(){
        log.info("[" + this.Id + "]: ConnectionsTest finishing execution.");
        // determine if the test was a success or failure
        var hasFailed = false;
        var hasWarn = false;
        if(this.TestResult != BrowserTestResults.Error){
            if(this.URACoordinators.length < URACoordinatorCount){
                hasWarn = true;
            }

            for(var i = 0; i < this.URACoordinators.length; i++){
                if(this._testResultsList[i] != BrowserTestResults.Pass){
                    if(this._testResultsList[i] == BrowserTestResults.Warn){
                        hasWarn = true;
                    }
                    if(this._testResultsList[i] == BrowserTestResults.Fail){
                        hasFailed = true;
                    }
                }
            }
            if(!hasFailed){
                if(!hasWarn){
                    this.TestResult = BrowserTestResults.Pass;
                } else {
                    this.TestResult = BrowserTestResults.Warn;
                }
            } else {
                this.TestResult = BrowserTestResults.Fail;
            }

            this._updateStatus();
            this._updateHelp(HelpTemplates.ConnectionsTest);
            this._updateData();
            log.info("[" + this.Id + "]: ConnectionsTest completed execution.");
        } else {
            this._updateStatus();
            this._updateHelp(HelpTemplates.ConnectionsTest);
            this._updateData();
            log.info("[" + this.Id + "]: ConnectionsTest could not execute properly due to misconfiguration.");

        }
        this._raiseEvent("OnComplete", null);
    }

    /// <summary>
    /// Replaces the innerHTML of the data row for this BrowserTest so that it shows the 
    /// results of the test.
    /// *** NOTE: ***  _updateData expects the following DOM structure for a given data row:
    /// <tr> 
    ///     <td> Static Field Label </td>
    ///     <td> dynamic results field </td>
    ///     <td> dynamic details field </td>
    /// </tr>
    /// </summary>
    this._updateData = _updateData;
    function _updateData(){
        // update the 2nd cell
        this._dataRow.cells[1].innerHTML = this._getTestResultString(this.TestResult);

        if(this.TestResult == BrowserTestResults.Error){
            this._dataRow.cells[2].innerHTML = "Test System Configuration Error";
        } else {
            var newHtml = ""; 
            if(this.URACoordinators.length < URACoordinatorCount){
                newHtml += "The number of configured Remote Access Connection Tests <br/> ";
                newHtml += "does not match the number of Remote Access Methods found. " + this.URACoordinators.length + "/" + URACoordinatorCount + "<br/><br/>";
            }
            for(var i = 0; i < this.URACoordinators.length; i++){
                newHtml += "Remote Access Connection Test " + i + ": " + this._getTestResultString(this._testResultsList[i]) + "<br/>";
                newHtml += "Test Terminal Client Type: " + this._testDetails[i].TermClientType + "<br/>";
                newHtml += "Test URA Tunnel Type: " + this._testDetails[i].TunnelConfigType + "<br/>";
                newHtml += "<hr/>";
            }

            this._dataRow.cells[2].innerHTML = newHtml;
        }
    }

    /// <summary>
    /// Gets a string representation of the test result details.
    /// </summary>
    this.getDetails = _getDetails;
    function _getDetails(){
        if(this.TestResult == BrowserTestResults.Error){
            return "Test Error";
        } else {
            var newHtml = ""; 
            if(this.URACoordinators.length < URACoordinatorCount){
                newHtml += "The number of configured Remote Access Connection Tests \n ";
                newHtml += "does not match the number of Remote Access Methods found. " + this.URACoordinators.length + "/" + URACoordinatorCount + "\n\n";
            }
            for(var i = 0; i < this.URACoordinators.length; i++){
                newHtml += "\tRemote Access Connection Test " + i + ": " + this._getTestResultString(this._testResultsList[i]) + "\n";
                newHtml += "\tTest Terminal Client Type: " + this._testDetails[i].TermClientType + "\n";
                newHtml += "\tTest URA Tunnel Type: " + this._testDetails[i].TunnelConfigType + "\n";
                newHtml += "-----------------------------------------------------------------------\n";
            }
            return newHtml;
        }
    }
}

/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/
/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/
/***********************************************************************************************************************************
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
####################################################################################################################################
***********************************************************************************************************************************/

/// <summary>
/// URTCoordinator class handles the order and execution of the various tests 
/// required by URT.
/// </summary>
function URTCoordinator (id){
/// region : inheritance --------------------------------------------
    this.base = BaseObject;
    this.base(id);

/// region : private fields -----------------------------------------
    this._currentTestIdx = 0;
    this._currentTestText = "<p>Now running test {0} of {1}.........</p>";
    this._hadError = false;

/// region : Properties ---------------------------------------------
    /// <summary>
    /// Gets/sets the BrowserName for this navigator.  By default it is 
    /// assumed that the user's browser is SupportedBrowsers.InternetExplorer.
    /// </summary>
    this.BrowserName = SupportedBrowsers.InternetExplorer;

    /// <summary>
    /// Gets/sets the collection of BrowserTest objects.
    /// </summary>
    this.BrowserTests = new Array();

    /// <summary>
    /// Gets/sets the collection of required BrowsserTest objects.
    /// During test execution, if a required test fails, the testing cycle 
    /// short circuits, speeding up the process.
    /// </summary>
    this.RequiredTests = new Object();

    /// <summary>
    /// Gets/sets the current BrowserTest object being executed.
    /// </summary>
    this.ActiveBrowserTest = null;

    /// <summary>
    /// Gets/sets the HTML table element that holds the status of each test.
    /// </summary>
    this.TestStatusTable = null;

    /// <summary>
    /// Gets/sets the HTML element that contains the test status.
    /// </summary>
    this.TestCounter = null;

    /// <summary>
    /// Gets/sets the HTML element that informs the user of a successful test
    /// execution.
    /// </summary>
    this.TestResultsPass = null;

    /// <summary>
    /// Gets/sets the HTML element that informs the user of a failed test
    /// execution.
    /// </summary>
    this.TestResultsFail = null;

    /// <summary>
    /// Gets/sets the HTML element that informs the user of a error in test 
    /// execution.
    /// </summary>
    this.TestResultsError = null;

    /// <summary>
    /// Gets/sets the HTML element that displays the extended test results.
    /// </summary>
    this.BrowserInfo = null;

    /// <summary>
    /// Gets/sets the target IFrame for the test.
    /// </summary>
    this.TargetFrame = null;


/// region : Methods ------------------------------------------------
    /// <summary>
    /// Method binds the URTCoordinator with the required HTML elements needed for 
    /// it to render data to the user.
    /// </summary>
    /// <param type="string" name="testStatusTable">id of the table whose rows indicate the status of 
    /// each test as it is run.</param>
    /// <param type="string" name="testCounter">id of the element that displays the current test counter</param>
    /// <param type="string" name="testResultsPass">id of the element that informs the user of the test successfully passing</param>
    /// <param type="string" name="testResultsFail">id of the element that informs the user of the test failing</param>
    /// <param type="string" name="testResultsError">id of the element that informs the user of a test error</param>
    /// <param type="string" name="browserInfo">id of the element that holds the table for the extended test results</param>
    /// <param type="string" name="iFrameName">id of the element that holds the table for the extended test results</param>
    this.init = _init;
    function _init(testStatusTable, testCounter, testResultsPass, testResultsFail, 
        testResultsError, browserInfo, iFrameName){
        log.info("[" + this.Id + "]: URTCoordinator intialized with: " + testStatusTable + ", " + 
            testCounter + ", " + testResultsPass + ", " + testResultsFail + ", " + 
            testResultsError + ", " + browserInfo + ", " + iFrameName);
        this.TestStatusTable = document.getElementById(testStatusTable);
        this.TestCounter = document.getElementById(testCounter);
        this.TestResultsPass = document.getElementById(testResultsPass);
        this.TestResultsFail = document.getElementById(testResultsFail);
        this.TestResultsError = document.getElementById(testResultsError);
        this.BrowserInfo = document.getElementById(browserInfo);

        try{
            this.TargetFrame = window.frames[iFrameName];
        } catch (e){}

        if(this.TestStatusTable == null || this.TestCounter == null || this.TestResultsPass == null ||
        this.TestResultsFail == null || this.TestResultsError == null || 
        this.BrowserInfo == null || this.TargetFrame == null){
            log.info("[" + this.Id + "]: URTCoordinator failed to initialize due to invalid DOM structure in the test page.");
            throw this._newError("Invalid DOM structure found for test page, the test cannot complete.");
        }

        // display the test rows for the tests configured
        for(var i = 0; i < this.BrowserTests.length; i++){
            var test = this.BrowserTests[i];
            var rowId = test._statusRowId;
            var td = document.getElementById(rowId);
            if(td != null && td.tagName.toUpperCase() == "TD"){
                td.parentNode.style.display = "";
            }
            rowId = test._dataRowId;
            var tr = document.getElementById(rowId);
            if(tr != null){
                tr.style.display = "";
            }
        }
    }

    /// <summary>
    /// AddBrowserTest method adds a BrowserTest to the tests collection and schedule's them 
    /// for execution.
    /// </summary>
    /// <param type="BrowserTest" name="test">a reference to a BrowserTest object</param>
    /// <param type="boolean" name="required">true if the test is required, false otherwise</param>
    this.addBrowserTest = _addBrowserTest;
    function _addBrowserTest (test, required){
        this.BrowserTests[this.BrowserTests.length] = test;
        this.RequiredTests[test.Id] = required;
        log.info("[" + this.Id + "]: URTCoordinator added test: " + test.getClass());
    }

    /// <summary>
    /// Method binds the event handlers to the active BrowserTest object and calls it's 
    /// execute method.  Once the TestComplete or TestError event has been caught by the 
    /// URTCoordinator the URTCoordinator automatically cycles to the next BrowserTest in 
    /// it's collection.
    /// </summary>
    this.execute = _execute;
    function _execute(){
        // get the BrowserTest object, bind it's event delegates and 
        // call the execute method
        log.info("[" + this.Id + "]:  URTCoordinator entering test execution.");
        var countIdx = this._currentTestIdx + 1;
        var testCount = this.BrowserTests.length;
        this.TestCounter.innerHTML = this._formatString(this._currentTestText, 
                countIdx, testCount);
        this.ActiveBrowserTest = this.BrowserTests[this._currentTestIdx];
        this.ActiveBrowserTest.OnComplete = this._getHandler("browserTestCompleteHandler");
        this.ActiveBrowserTest.OnError = this._getHandler("browserTestErrorHandler");
        this.ActiveBrowserTest.TargetFrame = this.TargetFrame;
        try{
            this.ActiveBrowserTest.init();
            this.ActiveBrowserTest.execute();
        } catch (e) {
            if(e.message == "Invalid DOM structure for test page."){
                log.info("[" + this.Id + "]:  URTCoordinator is missing the proper DOM structure to run the test.");
                throw e;
            }
        }
    }

    /// <summary>
    /// Cycles to the next BrowserTest object in the queue.  If there are no 
    /// remaining tests the method calls the complete tests method.
    /// </summary>
    this._cycleBrowserTest = _cycleBrowserTest;
    function _cycleBrowserTest(){
        var nextTest = this._currentTestIdx + 1;
        if(nextTest < this.BrowserTests.length){    
            log.info("[" + this.Id + "]:  URTCoordinator calling next test for execution.");
            this._currentTestIdx = nextTest;
            this.execute();
        } else {
            // all the tests have been completed so handle processing the test results
            this.finishTest();
        }
    }

    /// <summary>
    /// Finishes the test cycle and raises the on complete events.
    /// </summary>
    this.finishTest = _finishTest;
    function _finishTest(){
        // begin by hiding the counter box
        this.TestCounter.style.display = "none";

        var hasFailed = false;
        var hasError = false;
        for(var i = 0; i < this.BrowserTests.length; i++){
            var test = this.BrowserTests[i];
            if(this.RequiredTests[test.Id]){
                if(test.TestResult == BrowserTestResults.Fail){
                    hasFailed = true;
                }
                if(test.TestResult == BrowserTestResults.Error){
                    hasError = true;
                }
            }
        }

        if(hasError){
            this.TestResultsPass.style.display = "none";
            this.TestResultsFail.style.display = "none";
            this.TestResultsError.style.display = "block";
        } else {
            if(hasFailed){
                this.TestResultsPass.style.display = "none";
                this.TestResultsFail.style.display = "block";
                this.TestResultsError.style.display = "none";
            } else {
                this.TestResultsPass.style.display = "block";
                this.TestResultsFail.style.display = "none";
                this.TestResultsError.style.display = "none";
            }
        }
        log.info("[" + this.Id + "]:  URTCoordinator testing is complete.");
        this._raiseEvent("OnComplete", null);
    }

    /// <summary>
    /// Event handler for the BroswersTest TestComplete event.
    /// </summary>
    /// <param name="sender" type="object">object raising the event</param>
    /// <param name="args" type="object">any event arguments</param>
    this.browserTestCompleteHandler = _browserTestCompleteHandler;
    function _browserTestCompleteHandler(sender, args){
        // log the test complete statement and move to the next test
        log.info("[" + this.Id + "]:  URTCoordinator received OnComplete event from " + this.ActiveBrowserTest.getClass());
        var logdata = "";
        log.info("[" + this.Id + "]:  " + this.ActiveBrowserTest.getClass() + " test result: " + this.ActiveBrowserTest.TestResult);
        if(this.ActiveBrowserTest.getClass() == "BrowserCapsTest"){
            this.BrowserName = this.ActiveBrowserTest.BrowserName;
            // add the browser info to the extended test results
            this.BrowserInfo.innerHTML = this.ActiveBrowserTest.getBrowserCaps();
            logdata += this.ActiveBrowserTest.getBrowserCapsDetails();
        }
        logdata += this.ActiveBrowserTest.getDetails();
        log.info("[" + this.Id + "]:  " + this.ActiveBrowserTest.getClass() + " test result details:\n" + logdata); 

        // give the test time to close the event callstack before removing it
        this._setTimeout(this.Id + "._cycleBrowserTest()", 500);
    }



    /// <summary>
    /// Event handler for the TermClient LoadError event.
    /// </summary>
    /// <param name="sender" type="object">object raising the event</param>
    /// <param name="args" type="object">any event arguments</param>
    this.browserTestErrorHandler = _browserTestErrorHandler;
    function _browserTestErrorHandler(sender, args){
        log.info("[" + this.Id + "]:  URTCoordinator received OnError event from " + this.ActiveBrowserTest.getClass()); 
        // give the test time to close the event callstack before removing it
        this._setTimeout(this.Id + "._cycleBrowserTest()", 500);
    }

    /// <summary>
    /// Method replaces each format item in a specified String with the text equivalent of a corresponding object's value.
    /// </summary>
    /// <param name="sourceString" type="string">object raising the event</param>
    /// <param name="args" type="object">**** IMPLICIT **** the method takes N number of args and 
    /// will iterate through the entire set</param>
    this._formatString = _formatString;
    function _formatString(sourceString){
        if(arguments.length > 1){
            for(var i = 1; i < arguments.length; i++){
                var idx = i - 1;
                sourceString = sourceString.replace("{" + idx + "}", arguments[i]);
            }
        }
        return sourceString;
    }

    /// <summary>
    /// Method builds a string of test results data from all the BrowserTests run.
    /// </summary>
    this.getTestResults = getTestResults;
    function getTestResults(){
        var output = "URT Test Results \n";
        output += "------------------------------------------------------------------------\n\n";
        for(var i = 0; i < this.BrowserTests.length; i++){
            var test = this.BrowserTests[i];
            output += test.getClass() + ":\t";
            switch (test.TestResult){
                case BrowserTestResults.Pass :
                    output += BrowserTestResultsLabel.Pass;
                    break;
                case BrowserTestResults.Fail : 
                    output += BrowserTestResultsLabel.Fail;
                    break;
                case BrowserTestResults.Error : 
                    output += BrowserTestResultsLabel.Error;
                    break;
            }            
            output += "\n";
            output += test.getDetails();
            output += "\n------------------------------------------------------------------------\n\n";
        }
        return output;
    }

/// region : Event Delegates ----------------------------------------
    /// <summary>
    /// Event delegate for the OnComplete event.
    /// </summary>
    /// <param name="sender" type="object">this object</param>
    /// <param name="args" type="object">any event arguments for this object</param>
    this.OnComplete = null;

    /// <summary>
    /// Event delegate for the OnError event.
    /// </summary>
    /// <param name="sender" type="object">this object</param>
    /// <param name="args" type="object">any event arguments for this object</param>
    this.OnError = null;
}
