var jsTestIsAsync = true;
if (self.importScripts && !self.postMessage) {
    // Shared worker.  Make postMessage send to the newest client, which in
    // our tests is the only client.

    // Store messages for sending until we have somewhere to send them.
    self.postMessage = function(message)
    {
        if (typeof self.pendingMessages === "undefined")
            self.pendingMessages = [];
        self.pendingMessages.push(message);
    };
    self.onconnect = function(event)
    {
        self.postMessage = function(message)
        {
            event.ports[0].postMessage(message);
        };
        // Offload any stored messages now that someone has connected to us.
        if (typeof self.pendingMessages === "undefined")
            return;
        while (self.pendingMessages.length)
            event.ports[0].postMessage(self.pendingMessages.shift());
    };
}

function unexpectedSuccessCallback()
{
    testFailed("Success function called unexpectedly.");
    finishJSTest();
}

function unexpectedErrorCallback(event)
{
    testFailed("Error function called unexpectedly: (" + event.target.error.name + ") " + event.target.error.message);
    finishJSTest();
}

function unexpectedAbortCallback(e)
{
    testFailed("Abort function called unexpectedly! Message: [" + e.target.error.message + "]");
    finishJSTest();
}

function unexpectedCompleteCallback()
{
    testFailed("oncomplete function called unexpectedly!");
    finishJSTest();
}

function unexpectedBlockedCallback(e)
{
    testFailed("onblocked called unexpectedly. oldVersion = " + e.oldVersion + ", newVersion = " + e.newVersion);
    finishJSTest();
}

function unexpectedUpgradeNeededCallback()
{
    testFailed("onupgradeneeded called unexpectedly");
    finishJSTest();
}

function unexpectedVersionChangeCallback(e)
{
    testFailed("onversionchange called unexpectedly. oldVersion = " + e.oldVersion + ". newVersion = " + e.newVersion);
    finishJSTest();
}

function evalAndExpectException(cmd, exceptionCode, exceptionName, _quiet)
{
    if (!_quiet)
        debug("Expecting exception from " + cmd);
    try {
        eval(cmd);
        testFailed("No exception thrown! Should have been " + exceptionCode);
    } catch (e) {
        code = e.code;
        if (!_quiet)
            testPassed("Exception was thrown.");
        shouldBe("code", exceptionCode, _quiet);
        if (exceptionName) {
            ename = e.name;
            shouldBe("ename", exceptionName, _quiet);
        }
        if (!_quiet)
            debug("Exception message: " + e.message);
    }
}

function evalAndExpectExceptionClass(cmd, expected)
{
    debug("Expecting " + expected + " exception from " + cmd);
    try {
        eval(cmd);
        testFailed("No exception thrown!" );
    } catch (e) {
        testPassed("Exception was thrown.");
        if (eval("e instanceof " + expected))
            testPassed(cmd + " threw " + e);
        else
            testFailed("Expected " + expected + " but saw " + e);
    }
}

function evalAndLogCallback(cmd) {
  function callback() {
    evalAndLog(cmd);
  }
  return callback;
}

// If this function is deleted, a standalone layout test exercising its
// functionality should be added.
function deleteAllObjectStores(db)
{
    while (db.objectStoreNames.length)
        db.deleteObjectStore(db.objectStoreNames.item(0));
    debug("Deleted all object stores.");
}

function setDBNameFromPath(suffix) {
    var name = self.location.pathname.substring(1 + self.location.pathname.lastIndexOf("/"));
    if (suffix)
        name += suffix;
    evalAndLog('dbname = "' + name + '"');
}

function preamble(evt)
{
    if (evt)
        event = evt;
    debug("");
    var name = preamble.caller?.name ?? '';
    debug(name + "():");
}

// For Workers
if (!self.DOMException) {
    self.DOMException = {
        INDEX_SIZE_ERR: 1,
        DOMSTRING_SIZE_ERR: 2,
        HIERARCHY_REQUEST_ERR: 3,
        WRONG_DOCUMENT_ERR: 4,
        INVALID_CHARACTER_ERR: 5,
        NO_DATA_ALLOWED_ERR: 6,
        NO_MODIFICATION_ALLOWED_ERR: 7,
        NOT_FOUND_ERR: 8,
        NOT_SUPPORTED_ERR: 9,
        INUSE_ATTRIBUTE_ERR: 10,
        INVALID_STATE_ERR: 11,
        SYNTAX_ERR: 12,
        INVALID_MODIFICATION_ERR: 13,
        NAMESPACE_ERR: 14,
        INVALID_ACCESS_ERR: 15,
        VALIDATION_ERR: 16,
        TYPE_MISMATCH_ERR: 17,
        SECURITY_ERR: 18,
        NETWORK_ERR: 19,
        ABORT_ERR: 20,
        URL_MISMATCH_ERR: 21,
        QUOTA_EXCEEDED_ERR: 22,
        TIMEOUT_ERR: 23,
        INVALID_NODE_TYPE_ERR: 24,
        DATA_CLONE_ERR: 25
    };
}

function indexedDBTest(upgradeCallback, optionalOpenCallback, optionalParameters) {
    if (optionalParameters && 'suffix' in optionalParameters) {
        setDBNameFromPath(optionalParameters['suffix']);
    } else {
        setDBNameFromPath();
    }
    var deleteRequest = evalAndLog("indexedDB.deleteDatabase(dbname)");
    deleteRequest.onerror = unexpectedErrorCallback;
    deleteRequest.onblocked = unexpectedBlockedCallback;
    deleteRequest.onsuccess = function() {
        self.openRequest = null;
        if (optionalParameters && 'version' in optionalParameters)
            openRequest = evalAndLog("indexedDB.open(dbname, " + optionalParameters['version'] + ")");
        else
            openRequest = evalAndLog("indexedDB.open(dbname)");
        shouldBe("openRequest.readyState", "'pending'", true/*quiet*/);
        openRequest.onerror = unexpectedErrorCallback;
        openRequest.onupgradeneeded = upgradeCallback;
        openRequest.onblocked = unexpectedBlockedCallback;
        if (optionalOpenCallback)
            openRequest.onsuccess = optionalOpenCallback;
        delete self.openRequest;
        if (optionalParameters && 'runAfterOpen' in optionalParameters)
            (optionalParameters['runAfterOpen'])();
    };
}

function waitForRequests(requests, callback) {
    var count = requests.length;

    if (!count) {
        callback(requests);
        return;
    }

    requests.forEach(function(req) {
        req.onsuccess = function() {
            --count;
            if (!count)
                callback(requests);
        };
        req.onerror = unexpectedErrorCallback;
    });
}
