/*
 Tests that java is installed on the machine, and that an applet successfully launches.

 Notes:
 this test populates the TestContext with the created applet instance (which can be used by subsequent tests)
 */

var TestJava = function(name) {
    this._initialize(name);
    this.completed = false;
}

extend(TestJava.prototype, new BaseTest(), {
    start : function() {
        this.context.recordTestDatapoint("java_version", getJavaVersionSafe());

        var appletElement = document.createElement("applet")
        appletElement.setAttribute("code", "com.animotion.client3d.applets.javaversion.JavaVersionApplet")
        appletElement.setAttribute("archive", "/jars/javaversion-applet.jar")
        appletElement.setAttribute("width", "25px")
        appletElement.setAttribute("height", "25px")
        appletElement.setAttribute("mayscript", "true")
        appletElement.setAttribute("scriptable", "true")

        // launch it
        $(pems.versionAppletContainer).append(appletElement)

        //
        // poll applet to see if it is alive.  
        //
        this.intervalId = window.setInterval(this.checkApplet.bind(this, appletElement, new Date().getTime()), 500);
        this.logInfo("AppletWatch created interval " + this.intervalId);
    },

    checkApplet: function(appletElement, started) {
        if (this.completed) {
            this.cleanupInterval();
            return;
        }

        var now = new Date().getTime();

        if((now - started) % 2000 <= 500)
            this.logInfo("Stilling waiting for version applet availability...")

        if (now - started >= 15000) {
            this.completed = true;

            return this.notifyFailure("LAUNCH", "APPLET", {lastException: this.lastException});
        }

        try {
            if (appletElement.isActive()) {
                this.completed = true;
                this.setVersionApplet(appletElement);

                this.continueJavaTests();
            }
        } catch (e) {
            this.lastException = e;
        }
    },

    cleanupInterval : function() {
        this.logInfo("Clearing AppletWatch interval " + this.intervalId);
        window.clearInterval(this.intervalId);
    },

    continueJavaTests : function() {
        try {
            delegateToNextJavaTest(this, new TestJavaVersion("JAVAVERSION"));
        } catch (e) {
            return this.notifyFailure("CHECKJAVA", "EXCEPTION", {e: e});
        }
    }

    //
    // candidate for removal  -ewebb, 090601
    //

    //    versionAppletLaunchListener : function(success, code, message) {
    //        if (!success)
    //            return this.notifyFailure("LAUNCH", code, {message : message});
    //
    //        this.context.versionAppletLauncher = this.versionLauncher;
    //
    //        this.notifySuccess();
    //    }
})

/*
 Tests that the version of Java reported is compatible and behaves as expected
 */

var TestJavaVersion = function(name) {
    this._initialize(name);

    TestJavaVersion.SUPPORTED_JAVA_VERSIONS = ">=1.5.0";
    TestJavaVersion.UNSUPPORTED_JAVA_VERSIONS = null;
}

extend(TestJavaVersion.prototype, new BaseTest(), {
    start : function() {
        this.testFF35Java();
    },

    testFF35Java: function() {
        this.logInfo("Testing if FF35 + Old Java compat issue applicable")
        if (firefox35OldJavaFixApplicable()) {
            this.logInfo("Testing FF35 + Old Java")
            var options = {};

            options.applet = this.getVersionApplet();

            options.handler = {};
            options.handler.onFailure = function() {
                var javaVersion = "";

                try {
                    javaVersion = this.getVersionApplet().getJavaVersion();
                } catch(e) {
                    javaVersion = "error";
                    // do nothing
                }

                return this.notifyFailure("CHECKJAVA", "FF35OLDJAVA", {javaVersion: javaVersion});
            }.bind(this);

            options.handler.onSuccess = this.postTestFF35Java.bind(this);
            options.handler.onTimeout = this.postTestFF35Java.bind(this);

            startFirefox35OldJavaTest(options)
        } else {
            this.postTestFF35Java();
        }
    },

    postTestFF35Java: function() {
        this.testKnownIncompatibleCombinations();
    },

    testKnownIncompatibleCombinations: function() {
        this.logInfo("Starting Tests for Java/Browser Known Incompatibilties");

        // BrowserDetect.init() already called in an earlier verifier test
        var browser = BrowserDetect.browser;
        var browserVersion = BrowserDetect.version;

        try {
            var javaVersion = this.getVersionApplet().getJavaVersion();

            if(browser == "Firefox" && browserVersion == 3 && javaVersion == "1.5.0_06") {
                return this.notifyFailure("CHECKJAVA", "KNOWN_COMPAT_ISSUE", {browser: browser, browserVersion: browserVersion, javaVersion: javaVersion});
            }
        } catch (e) {
            this.logInfo("Exception testing for known browser/java version compatibitily issues: " + e.name + " - " + e.message);
        }

        this.postTestKnownIncompatibleCombinations();
    },

    postTestKnownIncompatibleCombinations: function() {
        this.testJavaVersion();
    },

    testJavaVersion: function() {
        this.logInfo("Starting Java Version test proper")
        
        try {
            var results = {};
            var versionApplet = this.getVersionApplet();

            try {
                var javaResults = versionApplet.getJavaProperties(new Object());

                if (javaResults["java.version"])
                    results = javaResults;
            } catch (e) {
                // this can sometimes fail. :(
            }

            var javaVersionString = versionApplet.getJavaVersion()
            var osNameString = versionApplet.getOsName();

            results.javaVersion = javaVersionString;
            results.osName = osNameString;

            // test the java version here because Safari needs elevated Java permissions
            try {
                var applet = versionApplet;

                try {  // sometimes these fail for old versions of java...we should flag it as a java version error
                    var unsupportedVersionRange = applet.createSingleJavaVersionRange(TestJavaVersion.UNSUPPORTED_JAVA_VERSIONS);
                    var supportedVersionRange = applet.createSingleJavaVersionRange(TestJavaVersion.SUPPORTED_JAVA_VERSIONS);
                } catch (e) {
                    return this.notifyFailure("CHECKJAVA", "UNSUPPORTED", {javaVersion : javaVersionString, javaVersions: TestJavaVersion.SUPPORTED_JAVA_VERSIONS, supportedJavaVersionsString: TestJavaVersion.SUPPORTED_JAVA_VERSIONS, unsupportedJavaVersionsString: TestJavaVersion.UNSUPPORTED_JAVA_VERSIONS, exception: e})
                }

                // check java version
                // carl: these aren't javascript Array(s) :) -ewebb
                if (unsupportedVersionRange.containsString(javaVersionString) || ! supportedVersionRange.containsString(javaVersionString))
                    return this.notifyFailure("CHECKJAVA", "UNSUPPORTED", {javaVersion : javaVersionString, javaVersions: TestJavaVersion.SUPPORTED_JAVA_VERSIONS, supportedJavaVersionsString: TestJavaVersion.SUPPORTED_JAVA_VERSIONS, unsupportedJavaVersionsString: TestJavaVersion.UNSUPPORTED_JAVA_VERSIONS})
            } catch (e) {
                return this.notifyFailure("CHECKJAVA", "UNSUPPORTED", {javaVersion : javaVersionString, javaVersions: TestJavaVersion.SUPPORTED_JAVA_VERSIONS, supportedJavaVersionsString: TestJavaVersion.SUPPORTED_JAVA_VERSIONS, unsupportedJavaVersionsString: TestJavaVersion.UNSUPPORTED_JAVA_VERSIONS, exception: e})
            }

            var results_params = new TestParameters();
            results_params.merge(results);

            this.context.params = results_params; // pass along an instance of TestParameters, so that we can add to it easily 

            // continue
            this.postTestJavaVersion();
        } catch (e) {
            this.notifyFailure("CALL", "EXCEPTION", {exception : e});
        }
    },

    postTestJavaVersion: function() {
        this.continueJavaTests();
    },

    continueJavaTests: function() {
        delegateToNextJavaTest(this, new TestJavaPermissions("PERMISSIONS"));
    }
})

/*
 Checks that the java applet has necessary permissions to do what it needs to do, ie:

 * read protected system properties
 * read and write to the file system
 *
 */

var TestJavaPermissions = function(name) {
    this._initialize(name)
    this.superclass = BaseTest;
    
    this.ran = false;
}

extend(TestJavaPermissions.prototype, new BaseTest(), {
    start : function() {
        this.logInfo("Start of TestJavaPermissions");
        
        this.verifierLauncher = new AppletLauncher(pems.verifierAppletContainer, { // applet attributes
            code : "com.animotion.client3d.applets.verifier.VerifierApplet",
            archive : "/jars/verify-applet.jar",
            width : "25px",
            height : "25px",
            mayscript: "true",
            scriptable: "true"
        }, { // applet parameters
            id : "verify",
            testUrl : "http://" + window.location.host
        })

        this.logInfo("Pre-Launch of VerifierApplet")
        this.verifierLauncher.addLaunchListener(this.launchListener.bind(this));
        this.verifierLauncher.start();
        this.logInfo("Post-Launch of VerifierApplet")
    },

    launchListener : function(success, code, message) {
        this.logInfo("TestJavaPermissions.launchListener called with success " + success);

        // test if we've run before, IE seems to keep running us...
        if (!this.ran)
            this.ran = true;
        else
            return this.logInfo("WARNING: TestJavaPermissions launchListener already called");

        try {
            if (success) {
                this.setVerifierAppletLauncher(this.verifierLauncher);
                this.testPermissions();
            } else {
                return this.notifyFailure("LAUNCHSIGNED", code, {message : message})
            }
        } catch(e) {
            this.notifyFailure("TESTPERMS-EXCEPTION", "TESTPERMS-EXCEPTION", this.context.params.merge({exception: e}));
        }
    },

    testPermissions : function() {
        var retrier = new MethodRetrier(this.getVerifierApplet())
        var test_params = this.context.params;

        //
        // test if we thing java was completely restarted since the last test
        //
        var restarted = true;
        try {
            var context_id = retrier.call_noargs("getContextId");
            this.context.recordTestDatapoint(TestContext.JAVA_CONTEXT_KEY, context_id);

            var last_verification_session = this.context.getLastVerificationHistory();
            var last_context_id = (typeof last_verification_session[TestContext.JAVA_CONTEXT_KEY] != "undefined") ? last_verification_session[TestContext.JAVA_CONTEXT_KEY] : null;

            restarted = context_id != last_context_id // flag restarted here, only warn if the user runs into permission problems
        } catch(e) {
            // do nothing!
        }

        try {
            if (!retrier.call_noargs("testJavaProperties")) {
                if(! restarted)
                    this.notifyWarning("NOT_FULLY_RESTARTED", null, test_params)

                return this.notifyFailure("CHECKPROPS", "EXCEPTION", test_params);
            }

        } catch (e) {
            if(! restarted)
                this.notifyWarning("NOT_FULLY_RESTARTED", null, test_params)
            
            return this.notifyFailure("CHECKPROPS", "EXCEPTION", test_params.merge({exception: e}));
        }

        try {
            if (!retrier.call_noargs("testReadWriteFilesystem"))
                return this.notifyFailure("CHECKREADWRITE", "EXCEPTION", test_params);
        } catch (e) {
            return this.notifyFailure("CHECKREADWRITE", "EXCEPTION", test_params.merge({exception: e}));
        }

        try {
            if (!retrier.call_noargs("testConnectToServer"))
                return this.notifyFailure("CHECKCONNECTION", "EXCEPTION", test_params);

        } catch (e) {
            return this.notifyFailure("CHECKCONNECTION", "EXCEPTION", test_params.merge({exception: e}));
        }

        try {
            var proxies_detected = retrier.call_noargs("testProxyDetected");

            if(proxies_detected) {
                this.notifyWarning("PROXY_DETECTED", null, test_params)

                var proxy_string = retrier.call_noargs("getProxyString");
                test_params.merge({proxyString: proxy_string});
            }

            test_params.merge({proxyDetected: proxies_detected});
        } catch (e) {
        }

        this.notifySuccess(null, test_params);
    },

    notifyWarning: function(code, msg, params) {
        var newParams = {};
        newParams["WARNING_" + code] = code;

        params.merge(newParams);

        // call super notifyWarning method
        this.superclass.prototype.notifyWarning.apply(this, arguments);
    }
})

function delegateToNextJavaTest(currentTest, nextTest) {
    logInfoMessage("Delegating to next test " + nextTest.id);

    currentTest.populate(nextTest);
    nextTest.start();
}
