"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TaskProcessor = void 0;
var types_1 = require("src/utils/types");
function canTransferArrayBuffer() {
    if (!(0, types_1.isDefined)(TaskProcessor._canTransferArrayBuffer)) {
        var worker = new Worker(getWorkerUrl("Workers/transferTypedArrayTest.js"));
        worker.postMessage = worker.webkitPostMessage || worker.postMessage;
        var value = 99;
        var array = new Int8Array([value]);
        try {
            // postMessage might fail with a DataCloneError
            // if transferring array buffers is not supported.
            worker.postMessage({
                array: array,
            }, [array.buffer]);
        }
        catch (e) {
            TaskProcessor._canTransferArrayBuffer = false;
            return TaskProcessor._canTransferArrayBuffer;
        }
        var deferred = new Promise(function () { });
        worker.onmessage = function (event) {
            var array = event.data.array;
            // some versions of Firefox silently fail to transfer typed arrays.
            // https://bugzilla.mozilla.org/show_bug.cgi?id=841904
            // Check to make sure the value round-trips successfully.
            var result = (0, types_1.isDefined)(array) && array[0] === value;
            new Promise(function (resolve, reject) {
                resolve(result);
            }).then(function () {
                TaskProcessor._canTransferArrayBuffer = true;
            });
            worker.terminate();
            TaskProcessor._canTransferArrayBuffer = result;
        };
    }
    return TaskProcessor._canTransferArrayBuffer;
}
function completeTask(processor, data) {
    --processor._activeTasks;
    var id = data.id;
    if (!(0, types_1.isDefined)(id)) {
        // This is not one of ours.
        return;
    }
    var deferreds = processor._deferreds;
    var deferred = deferreds[id];
    if ((0, types_1.isDefined)(data.error)) {
        var error = data.error;
        if (error.name === "RuntimeError") {
            error = console.log(data.error.message);
        }
        else if (error.name === "DeveloperError") {
            error = console.log(data.error.message);
        }
        // taskCompletedEvent.raiseEvent(error);
        deferred.reject(error);
    }
    else {
        // taskCompletedEvent.raiseEvent();
        deferred.resolve(data.result);
    }
    delete deferreds[id];
}
function getWorkerUrl(moduleID) {
    var url = moduleID;
    // if (isCrossOriginUrl(url)) {
    //     //to load cross-origin, create a shim worker from a blob URL
    //     var script = 'importScripts("' + url + '");';
    //     var blob;
    //     try {
    //         blob = new Blob([script], {
    //             type: "application/javascript",
    //         });
    //     } catch (e) {
    //         var BlobBuilder =
    //             (window as any).BlobBuilder ||
    //             (window as any).WebKitBlobBuilder ||
    //             (window as any).MozBlobBuilder ||
    //             (window as any).MSBlobBuilder;
    //         var blobBuilder = new BlobBuilder();
    //         blobBuilder.append(script);
    //         blob = blobBuilder.getBlob("application/javascript");
    //     }
    //     var URL = window.URL || window.webkitURL;
    //     url = URL.createObjectURL(blob);
    // }
    return url;
}
var bootstrapperUrlResult;
function getBootstrapperUrl() {
    if (!(0, types_1.isDefined)(bootstrapperUrlResult)) {
        bootstrapperUrlResult = getWorkerUrl("Workers/cesiumWorkerBootstrapper.js");
    }
    return bootstrapperUrlResult;
}
function createWorker(processor) {
    var worker = new Worker(getBootstrapperUrl());
    worker.postMessage = worker.webkitPostMessage || worker.postMessage;
    var bootstrapMessage = {};
    worker.postMessage(bootstrapMessage);
    worker.onmessage = function (event) {
        completeTask(processor, event.data);
    };
    return worker;
}
var emptyTransferableObjectArray = [];
/**
 * A wrapper around a web worker that allows scheduling tasks for a given worker,
 * returning results asynchronously via a promise.
 *
 * The Worker is not constructed until a task is scheduled.
 *
 * @alias TaskProcessor
 * @constructor
 *
 * @param {String} workerPath The Url to the worker. This can either be an absolute path or relative to the Cesium Workers folder.
 * @param {Number} [maximumActiveTasks=5] The maximum number of active tasks.  Once exceeded,
 *                                        scheduleTask will not queue any more tasks, allowing
 *                                        work to be rescheduled in future frames.
 */
var TaskProcessor = /** @class */ (function () {
    function TaskProcessor(workerPath, maximumActiveTasks) {
        if (maximumActiveTasks === void 0) { maximumActiveTasks = 5; }
        this._workerPath = '';
        this._deferreds = {};
        this._workerPath = TaskProcessor._workerModulePrefix + workerPath;
        this._maximumActiveTasks = maximumActiveTasks;
        this._activeTasks = 0;
        this._deferreds = {};
        this._nextID = 0;
    }
    TaskProcessor.prototype.scheduleTask = function (parameters, transferableObjects) {
        if (!(0, types_1.isDefined)(this._worker)) {
            this._worker = createWorker(this);
        }
        if (this._activeTasks >= this._maximumActiveTasks) {
            return undefined;
        }
        ++this._activeTasks;
        var processor = this;
        var deferred = new Promise(function (resolve, reject) {
            resolve(canTransferArrayBuffer());
        }).then(function (canTransferArrayBuffer) {
            if (!(0, types_1.isDefined)(transferableObjects)) {
                transferableObjects = emptyTransferableObjectArray;
            }
            else if (!canTransferArrayBuffer) {
                transferableObjects.length = 0;
            }
            var id = processor._nextID++;
            processor._deferreds[id] = deferred;
            if (processor._worker)
                processor._worker.postMessage({
                    id: id,
                    parameters: parameters,
                    canTransferArrayBuffer: canTransferArrayBuffer,
                }, transferableObjects);
        });
    };
    TaskProcessor.prototype.isDestroyed = function () {
        return false;
    };
    ;
    /**
     * Destroys this object.  This will immediately terminate the Worker.
     * <br /><br />
     * Once an object is destroyed, it should not be used; calling any function other than
     * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
     */
    TaskProcessor.prototype.destroy = function () {
        if ((0, types_1.isDefined)(this._worker)) {
            this._worker.terminate();
        }
    };
    ;
    TaskProcessor._defaultWorkerModulePrefix = "Workers/";
    TaskProcessor._workerModulePrefix = TaskProcessor._defaultWorkerModulePrefix;
    TaskProcessor._canTransferArrayBuffer = true;
    return TaskProcessor;
}());
exports.TaskProcessor = TaskProcessor;
