/*!
 * NevWare21 Solutions LLC - ts-async, 0.5.4
 * https://github.com/nevware21/ts-async
 * Copyright (c) NevWare21 Solutions LLC and contributors. All rights reserved.
 * Licensed under the MIT license.
 */
import { isPromiseLike, objDefineProperties, getDocument, createCachedValue, safe, getInst, dumpObj, arrSlice, objDefineProp, hasSymbol, getKnownSymbol, isFunction, throwTypeError, iterForOf, isArray, arrForEach, isIterable, createCustomError, scheduleTimeout, isNode, getWindow, getGlobal, objDefine, objToString, isUndefined, isNumber, scheduleIdleCallback, utcNow, getLength, isIterator, fnCall, arrIndexOf } from '@nevware21/ts-utils';

const STR_PROMISE = "Promise";
const DONE = "done";
const VALUE = "value";
const RETURN = "return";
const REJECTED = "rejected";

function doAwaitResponse(value, cb) {
    return doAwait(value, (value) => {
        return cb ? cb({
            status: "fulfilled",
            rejected: false,
            value: value
        }) : value;
    }, (reason) => {
        return cb ? cb({
            status: REJECTED,
            rejected: true,
            reason: reason
        }) : reason;
    });
}
function doAwait(value, resolveFn, rejectFn, finallyFn) {
    let result = value;
    try {
        if (isPromiseLike(value)) {
            if (resolveFn || rejectFn) {
                result = value.then(resolveFn, rejectFn);
            }
        }
        else {
            try {
                if (resolveFn) {
                    result = resolveFn(value);
                }
            }
            catch (err) {
                if (rejectFn) {
                    result = rejectFn(err);
                }
                else {
                    throw err;
                }
            }
        }
    }
    finally {
        if (finallyFn) {
            doFinally(result, finallyFn);
        }
    }
    return result;
}
function doFinally(value, finallyFn) {
    let result = value;
    if (finallyFn) {
        if (isPromiseLike(value)) {
            if (value.finally) {
                result = value.finally(finallyFn);
            }
            else {
                result = value.then(function (value) {
                    finallyFn();
                    return value;
                }, function (reason) {
                    finallyFn();
                    throw reason;
                });
            }
        }
        else {
            finallyFn();
        }
    }
    return result;
}

function _pureAssign(func1, func2) {
    return func1 || func2;
}

let _debugState;
let _debugResult;
let _debugHandled;
let _promiseDebugEnabled = false;
function _addDebugState$1(thePromise, stateFn, resultFn, handledFn) {
    _debugState = _debugState || { toString: () => "[[PromiseState]]" };
    _debugResult = _debugResult || { toString: () => "[[PromiseResult]]" };
    _debugHandled = _debugHandled || { toString: () => "[[PromiseIsHandled]]" };
    let props = {};
    props[_debugState] = { get: stateFn };
    props[_debugResult] = { get: resultFn };
    props[_debugHandled] = { get: handledFn };
    objDefineProperties(thePromise, props);
}
function setPromiseDebugState(enabled, logger) {
    _promiseDebugEnabled = enabled;
}

const STRING_STATES = [
    "pending", "resolving", "resolved", REJECTED
];

const DISPATCH_EVENT = "dispatchEvent";
let _hasInitEvent;
function _hasInitEventFn(doc) {
    let evt;
    if (doc && doc.createEvent) {
        evt = doc.createEvent("Event");
    }
    return (!!evt && evt.initEvent);
}
function emitEvent(target, evtName, populateEvent, useNewEvent) {
    let doc = getDocument();
    !_hasInitEvent && (_hasInitEvent = createCachedValue(!!safe(_hasInitEventFn, [doc]).v));
    let theEvt = _hasInitEvent.v ? doc.createEvent("Event") : (useNewEvent ? new Event(evtName) : {});
    populateEvent && populateEvent(theEvt);
    if (_hasInitEvent.v) {
        theEvt.initEvent(evtName, false, true);
    }
    if (theEvt && target[DISPATCH_EVENT]) {
        target[DISPATCH_EVENT](theEvt);
    }
    else {
        let handler = target["on" + evtName];
        if (handler) {
            handler(theEvt);
        }
        else {
            let theConsole = getInst("console");
            theConsole && (theConsole["error"] || theConsole["log"])(evtName, dumpObj(theEvt));
        }
    }
}

const NODE_UNHANDLED_REJECTION = "unhandledRejection";
const UNHANDLED_REJECTION = NODE_UNHANDLED_REJECTION.toLowerCase();
let _currentPromiseId = [];
let _uniquePromiseId = 0;
let _unhandledRejectionTimeout = 10;
let _aggregationError;
let _hasPromiseRejectionEvent;
function dumpFnObj(value) {
    if (isFunction(value)) {
        return value.toString();
    }
    return dumpObj(value);
}
function _createAggregationError(values) {
    !_aggregationError && (_aggregationError = createCachedValue(safe(getInst, ["AggregationError"]).v || createCustomError("AggregationError", (self, args) => {
        self.errors = args[0];
    })));
    return new _aggregationError.v(values);
}
function _createPromise(newPromise, processor, executor) {
    let additionalArgs = arrSlice(arguments, 3);
    let _state = 0;
    let _hasResolved = false;
    let _settledValue;
    let _queue = [];
    let _id = _uniquePromiseId++;
    let _parentId = _currentPromiseId.length > 0 ? _currentPromiseId[_currentPromiseId.length - 1] : undefined;
    let _handled = false;
    let _unHandledRejectionHandler = null;
    let _thePromise;
    function _then(onResolved, onRejected) {
        try {
            _currentPromiseId.push(_id);
            _handled = true;
            _unHandledRejectionHandler && _unHandledRejectionHandler.cancel();
            _unHandledRejectionHandler = null;
            let thenPromise = newPromise(function (resolve, reject) {
                _queue.push(function () {
                    try {
                        let handler = _state === 2 ? onResolved : onRejected;
                        let value = isUndefined(handler) ? _settledValue : (isFunction(handler) ? handler(_settledValue) : handler);
                        if (isPromiseLike(value)) {
                            value.then(resolve, reject);
                        }
                        else if (handler) {
                            resolve(value);
                        }
                        else if (_state === 3) {
                            reject(value);
                        }
                        else {
                            resolve(value);
                        }
                    }
                    catch (e) {
                        reject(e);
                    }
                });
                if (_hasResolved) {
                    _processQueue();
                }
            }, additionalArgs);
            return thenPromise;
        }
        finally {
            _currentPromiseId.pop();
        }
    }
    function _catch(onRejected) {
        return _then(undefined, onRejected);
    }
    function _finally(onFinally) {
        let thenFinally = onFinally;
        let catchFinally = onFinally;
        if (isFunction(onFinally)) {
            thenFinally = function (value) {
                onFinally && onFinally();
                return value;
            };
            catchFinally = function (reason) {
                onFinally && onFinally();
                throw reason;
            };
        }
        return _then(thenFinally, catchFinally);
    }
    function _strState() {
        return STRING_STATES[_state];
    }
    function _processQueue() {
        if (_queue.length > 0) {
            let pending = _queue.slice();
            _queue = [];
            _handled = true;
            _unHandledRejectionHandler && _unHandledRejectionHandler.cancel();
            _unHandledRejectionHandler = null;
            processor(pending);
        }
    }
    function _createSettleIfFn(newState, allowState) {
        return (theValue) => {
            if (_state === allowState) {
                if (newState === 2 && isPromiseLike(theValue)) {
                    _state = 1;
                    theValue.then(_createSettleIfFn(2, 1), _createSettleIfFn(3, 1));
                    return;
                }
                _state = newState;
                _hasResolved = true;
                _settledValue = theValue;
                _processQueue();
                if (!_handled && newState === 3 && !_unHandledRejectionHandler) {
                    _unHandledRejectionHandler = scheduleTimeout(_notifyUnhandledRejection, _unhandledRejectionTimeout);
                }
            }
        };
    }
    function _notifyUnhandledRejection() {
        if (!_handled) {
            _handled = true;
            if (isNode()) {
                process.emit(NODE_UNHANDLED_REJECTION, _settledValue, _thePromise);
            }
            else {
                let gbl = getWindow() || getGlobal();
                !_hasPromiseRejectionEvent && (_hasPromiseRejectionEvent = createCachedValue(safe((getInst), [STR_PROMISE + "RejectionEvent"]).v));
                emitEvent(gbl, UNHANDLED_REJECTION, (theEvt) => {
                    objDefine(theEvt, "promise", { g: () => _thePromise });
                    theEvt.reason = _settledValue;
                    return theEvt;
                }, !!_hasPromiseRejectionEvent.v);
            }
        }
    }
    _thePromise = {
        then: _then,
        "catch": _catch,
        finally: _finally
    };
    objDefineProp(_thePromise, "state", {
        get: _strState
    });
    if (_promiseDebugEnabled) {
        _addDebugState$1(_thePromise, _strState, () => { return objToString(_settledValue); }, () => _handled);
    }
    if (hasSymbol()) {
        _thePromise[getKnownSymbol(11)] = "IPromise";
    }
    function _toString() {
        return "IPromise" + (_promiseDebugEnabled ? "[" + _id + (!isUndefined(_parentId) ? (":" + _parentId) : "") + "]" : "") + " " + _strState() + (_hasResolved ? (" - " + dumpFnObj(_settledValue)) : "") + ("");
    }
    _thePromise.toString = _toString;
    (function _initialize() {
        if (!isFunction(executor)) {
            throwTypeError(STR_PROMISE + ": executor is not a function - " + dumpFnObj(executor));
        }
        const _rejectFn = _createSettleIfFn(3, 0);
        try {
            executor.call(_thePromise, _createSettleIfFn(2, 0), _rejectFn);
        }
        catch (e) {
            _rejectFn(e);
        }
    })();
    return _thePromise;
}
function _createAllPromise(newPromise) {
    return function (input) {
        let additionalArgs = arrSlice(arguments, 1);
        return newPromise((resolve, reject) => {
            try {
                let values = [];
                let pending = 1;
                iterForOf(input, (item, idx) => {
                    if (item) {
                        pending++;
                        doAwait(item, (value) => {
                            values[idx] = value;
                            if (--pending === 0) {
                                resolve(values);
                            }
                        }, reject);
                    }
                });
                pending--;
                if (pending === 0) {
                    resolve(values);
                }
            }
            catch (e) {
                reject(e);
            }
        }, additionalArgs);
    };
}
function _createResolvedPromise(newPromise) {
    return function (value) {
        let additionalArgs = arrSlice(arguments, 1);
        if (isPromiseLike(value)) {
            return value;
        }
        return newPromise((resolve) => {
            resolve(value);
        }, additionalArgs);
    };
}
function _createRejectedPromise(newPromise) {
    return function (reason) {
        let additionalArgs = arrSlice(arguments, 1);
        return newPromise((_resolve, reject) => {
            reject(reason);
        }, additionalArgs);
    };
}
function _createAllSettledPromise(newPromise, ..._args) {
    return createCachedValue(function (input, ..._args) {
        let additionalArgs = arrSlice(arguments, 1);
        return newPromise((resolve, reject) => {
            let values = [];
            let pending = 1;
            function processItem(item, idx) {
                pending++;
                doAwaitResponse(item, (value) => {
                    if (value.rejected) {
                        values[idx] = {
                            status: REJECTED,
                            reason: value.reason
                        };
                    }
                    else {
                        values[idx] = {
                            status: "fulfilled",
                            value: value.value
                        };
                    }
                    if (--pending === 0) {
                        resolve(values);
                    }
                });
            }
            try {
                if (isArray(input)) {
                    arrForEach(input, processItem);
                }
                else if (isIterable(input)) {
                    iterForOf(input, processItem);
                }
                else {
                    throwTypeError("Input is not an iterable");
                }
                pending--;
                if (pending === 0) {
                    resolve(values);
                }
            }
            catch (e) {
                reject(e);
            }
        }, additionalArgs);
    });
}
function _createRacePromise(newPromise, ..._args) {
    return createCachedValue(function (input, ..._args) {
        let additionalArgs = arrSlice(arguments, 1);
        return newPromise((resolve, reject) => {
            let isDone = false;
            function processItem(item) {
                doAwaitResponse(item, (value) => {
                    if (!isDone) {
                        isDone = true;
                        if (value.rejected) {
                            reject(value.reason);
                        }
                        else {
                            resolve(value.value);
                        }
                    }
                });
            }
            try {
                if (isArray(input)) {
                    arrForEach(input, processItem);
                }
                else if (isIterable(input)) {
                    iterForOf(input, processItem);
                }
                else {
                    throwTypeError("Input is not an iterable");
                }
            }
            catch (e) {
                reject(e);
            }
        }, additionalArgs);
    });
}
function _createAnyPromise(newPromise, ..._args) {
    return createCachedValue(function (input, ..._args) {
        let additionalArgs = arrSlice(arguments, 1);
        return newPromise((resolve, reject) => {
            let theErros = [];
            let pending = 1;
            let isDone = false;
            function processItem(item, idx) {
                pending++;
                doAwaitResponse(item, (value) => {
                    if (!value.rejected) {
                        isDone = true;
                        resolve(value.value);
                        return;
                    }
                    else {
                        theErros[idx] = value.reason;
                    }
                    if (--pending === 0 && !isDone) {
                        reject(_createAggregationError(theErros));
                    }
                });
            }
            try {
                if (isArray(input)) {
                    arrForEach(input, processItem);
                }
                else if (isIterable(input)) {
                    iterForOf(input, processItem);
                }
                else {
                    throwTypeError("Input is not an iterable");
                }
                pending--;
                if (pending === 0 && !isDone) {
                    reject(_createAggregationError(theErros));
                }
            }
            catch (e) {
                reject(e);
            }
        }, additionalArgs);
    });
}

function syncItemProcessor(pending) {
    arrForEach(pending, (fn) => {
        try {
            fn();
        }
        catch (e) {
        }
    });
}
function timeoutItemProcessor(timeout) {
    let callbackTimeout = isNumber(timeout) ? timeout : 0;
    return (pending) => {
        scheduleTimeout(() => {
            syncItemProcessor(pending);
        }, callbackTimeout);
    };
}
function idleItemProcessor(timeout) {
    let options;
    if (timeout >= 0) {
        options = {
            timeout: +timeout
        };
    }
    return (pending) => {
        scheduleIdleCallback((deadline) => {
            syncItemProcessor(pending);
        }, options);
    };
}

let _allAsyncSettledCreator;
let _raceAsyncCreator;
let _anyAsyncCreator;
function createAsyncPromise(executor, timeout) {
    return _createPromise(createAsyncPromise, timeoutItemProcessor(timeout), executor, timeout);
}
const createAsyncAllPromise = _createAllPromise(createAsyncPromise);
const createAsyncResolvedPromise = _createResolvedPromise(createAsyncPromise);
const createAsyncRejectedPromise = _createRejectedPromise(createAsyncPromise);
function createAsyncAllSettledPromise(input, timeout) {
    !_allAsyncSettledCreator && (_allAsyncSettledCreator = _createAllSettledPromise(createAsyncPromise));
    return _allAsyncSettledCreator.v(input, timeout);
}
function createAsyncRacePromise(values, timeout) {
    !_raceAsyncCreator && (_raceAsyncCreator = _createRacePromise(createAsyncPromise));
    return _raceAsyncCreator.v(values, timeout);
}
function createAsyncAnyPromise(values, timeout) {
    !_anyAsyncCreator && (_anyAsyncCreator = _createAnyPromise(createAsyncPromise));
    return _anyAsyncCreator.v(values, timeout);
}

let _promiseCls;
let _allCreator;
let _allNativeSettledCreator;
let _raceNativeCreator;
let _anyNativeCreator;
function _createNativePromiseHelper(name, func) {
    !_promiseCls && (_promiseCls = createCachedValue((safe(getInst, [STR_PROMISE]).v) || null));
    if (_promiseCls.v && _promiseCls.v[name]) {
        return createCachedValue(function (input, timeout) {
            return createNativePromise((resolve, reject) => {
                _promiseCls.v[name](input).then(resolve, reject);
            });
        });
    }
    return func();
}
function createNativePromise(executor, timeout) {
    !_promiseCls && (_promiseCls = createCachedValue((safe(getInst, [STR_PROMISE]).v) || null));
    const PrmCls = _promiseCls.v;
    if (!PrmCls) {
        return createAsyncPromise(executor);
    }
    if (!isFunction(executor)) {
        throwTypeError(STR_PROMISE + ": executor is not a function - " + dumpObj(executor));
    }
    let _state = 0;
    function _strState() {
        return STRING_STATES[_state];
    }
    let thePromise = new PrmCls((resolve, reject) => {
        function _resolve(value) {
            _state = 2;
            resolve(value);
        }
        function _reject(reason) {
            _state = 3;
            reject(reason);
        }
        executor(_resolve, _reject);
    });
    objDefineProp(thePromise, "state", {
        get: _strState
    });
    return thePromise;
}
function createNativeAllPromise(input, timeout) {
    !_allCreator && (_allCreator = _createNativePromiseHelper("all", () => createCachedValue(_createAllPromise(createNativePromise))));
    return _allCreator.v(input, timeout);
}
const createNativeResolvedPromise = _createResolvedPromise(createNativePromise);
const createNativeRejectedPromise = _createRejectedPromise(createNativePromise);
function createNativeAllSettledPromise(input, timeout) {
    !_allNativeSettledCreator && (_allNativeSettledCreator = _createNativePromiseHelper("allSettled", () => _createAllSettledPromise(createNativePromise)));
    return _allNativeSettledCreator.v(input, timeout);
}
function createNativeRacePromise(values, timeout) {
    !_raceNativeCreator && (_raceNativeCreator = _createNativePromiseHelper("race", () => _createRacePromise(createNativePromise)));
    return _raceNativeCreator.v(values, timeout);
}
function createNativeAnyPromise(values, timeout) {
    !_anyNativeCreator && (_anyNativeCreator = _createNativePromiseHelper("any", () => _createAnyPromise(createNativePromise)));
    return _anyNativeCreator.v(values, timeout);
}

let _allSyncSettledCreator;
let _raceSyncCreator;
let _anySyncCreator;
function createSyncPromise(executor) {
    return _createPromise(createSyncPromise, syncItemProcessor, executor);
}
const createSyncAllPromise = _createAllPromise(createSyncPromise);
const createSyncResolvedPromise = _createResolvedPromise(createSyncPromise);
const createSyncRejectedPromise = _createRejectedPromise(createSyncPromise);
function createSyncAllSettledPromise(input, timeout) {
    !_allSyncSettledCreator && (_allSyncSettledCreator = _createAllSettledPromise(createSyncPromise));
    return _allSyncSettledCreator.v(input, timeout);
}
function createSyncRacePromise(values, timeout) {
    !_raceSyncCreator && (_raceSyncCreator = _createRacePromise(createSyncPromise));
    return _raceSyncCreator.v(values, timeout);
}
function createSyncAnyPromise(values, timeout) {
    !_anySyncCreator && (_anySyncCreator = _createAnyPromise(createSyncPromise));
    return _anySyncCreator.v(values, timeout);
}

let _defaultIdleTimeout;
let _allIdleSettledCreator;
let _raceIdleCreator;
let _anyIdleCreator;
function setDefaultIdlePromiseTimeout(idleDeadline) {
    _defaultIdleTimeout = idleDeadline;
}
const setDefaultIdleTimeout = (_pureAssign(setDefaultIdlePromiseTimeout));
function createIdlePromise(executor, timeout) {
    let theTimeout = isUndefined(timeout) ? _defaultIdleTimeout : timeout;
    return _createPromise(createIdlePromise, idleItemProcessor(theTimeout), executor, theTimeout);
}
const createIdleAllPromise = _createAllPromise(createIdlePromise);
const createIdleResolvedPromise = _createResolvedPromise(createIdlePromise);
const createIdleRejectedPromise = _createRejectedPromise(createIdlePromise);
function createIdleAllSettledPromise(input, timeout) {
    !_allIdleSettledCreator && (_allIdleSettledCreator = _createAllSettledPromise(createIdlePromise));
    return _allIdleSettledCreator.v(input, timeout);
}
function createIdleRacePromise(values, timeout) {
    !_raceIdleCreator && (_raceIdleCreator = _createRacePromise(createIdlePromise));
    return _raceIdleCreator.v(values, timeout);
}
function createIdleAnyPromise(values, timeout) {
    !_anyIdleCreator && (_anyIdleCreator = _createAnyPromise(createIdlePromise));
    return _anyIdleCreator.v(values, timeout);
}

let _promiseCreator;
let _allSettledCreator;
let _raceCreator;
let _anyCreator;
function setCreatePromiseImpl(creator) {
    _promiseCreator = creator ? createCachedValue(creator) : null;
}
function createPromise(executor, timeout) {
    !_promiseCreator && (_promiseCreator = createCachedValue(createNativePromise));
    return _promiseCreator.v.call(this, executor, timeout);
}
const createAllPromise = _createAllPromise(createPromise);
const createResolvedPromise = _createResolvedPromise(createPromise);
const createRejectedPromise = _createRejectedPromise(createPromise);
function createAllSettledPromise(input, timeout) {
    !_allSettledCreator && (_allSettledCreator = _createAllSettledPromise(createPromise));
    return _allSettledCreator.v(input, timeout);
}
function createRacePromise(values, timeout) {
    !_raceCreator && (_raceCreator = _createRacePromise(createPromise));
    return _raceCreator.v(values, timeout);
}
function createAnyPromise(values, timeout) {
    !_anyCreator && (_anyCreator = _createAnyPromise(createPromise));
    return _anyCreator.v(values, timeout);
}

function createTimeoutPromise(timeout, resolveReject, message) {
    return createPromise((resolve, reject) => {
        scheduleTimeout(() => {
            (resolveReject ? resolve : reject)(!isUndefined(message) ? message : "Timeout of " + timeout + "ms exceeded");
        }, timeout);
    });
}

function _doneChk(isDone, state, value, thisArg) {
    let result = isDone;
    state.res = value;
    if (!result) {
        if (state.isDone && isFunction(state.isDone)) {
            return doAwait(state.isDone.call(thisArg, state), (done) => {
                state.iter++;
                return !!done;
            });
        }
        else {
            result = !!state.isDone;
        }
    }
    state.iter++;
    return result;
}
function doWhileAsync(callbackFn, isDoneFn, thisArg) {
    let promise;
    let resolve;
    let reject = (reason) => {
        isDone = true;
        throw reason;
    };
    let isDone = false;
    let state = {
        st: utcNow(),
        iter: 0,
        isDone: isDoneFn || false
    };
    if (callbackFn) {
        const _createPromise = () => {
            return createPromise((res, rej) => {
                resolve = res;
                reject = rej;
            });
        };
        const _handleAsyncDone = (done) => {
            isDone = !!done;
            if (!isDone) {
                _processNext();
            }
            else {
                resolve(state.res);
            }
        };
        const _processNext = () => {
            while (!isDone) {
                try {
                    let cbResult = callbackFn.call(thisArg, state);
                    if (isPromiseLike(cbResult)) {
                        promise = promise || _createPromise();
                        doAwait(cbResult, (res) => {
                            try {
                                doAwait(_doneChk(isDone, state, res, thisArg), _handleAsyncDone, reject);
                            }
                            catch (e) {
                                reject(e);
                            }
                        }, reject);
                        return promise;
                    }
                    else {
                        let dnRes = _doneChk(isDone, state, cbResult, thisArg);
                        if (isPromiseLike(dnRes)) {
                            promise = promise || _createPromise();
                            doAwait(dnRes, _handleAsyncDone, reject);
                            return promise;
                        }
                        else {
                            isDone = !!dnRes;
                        }
                    }
                }
                catch (e) {
                    reject(e);
                    return promise;
                }
            }
            if (isDone && resolve) {
                resolve(state.res);
            }
            return promise || state.res;
        };
        return _processNext();
    }
}

function arrForEachAsync(theArray, callbackFn, thisArg) {
    if (theArray) {
        const len = getLength(theArray);
        if (len) {
            const isDone = (state) => {
                if (state.iter >= len || state.res === -1) {
                    return true;
                }
            };
            return doWhileAsync((state) => {
                const idx = state.iter;
                if (idx in theArray) {
                    return callbackFn.call(thisArg || theArray, theArray[idx], idx, theArray);
                }
            }, isDone);
        }
    }
}

let _iterSymbol;
let _iterAsyncSymbol;
function iterForOfAsync(iter, callbackFn, thisArg) {
    let err;
    let iterResult;
    let theIter = iter;
    function onFailed(failed) {
        err = { e: failed };
        if (theIter.throw) {
            iterResult = null;
            theIter.throw(err);
        }
        throw failed;
    }
    function onFinally() {
        try {
            if (iterResult && !iterResult[DONE]) {
                theIter[RETURN] && theIter[RETURN](iterResult);
            }
        }
        finally {
            if (err) {
                throw err.e;
            }
        }
    }
    if (iter) {
        if (!isIterator(iter)) {
            !_iterAsyncSymbol && (_iterAsyncSymbol = createCachedValue(getKnownSymbol(0)));
            theIter = iter[_iterAsyncSymbol.v] ? iter[_iterAsyncSymbol.v]() : null;
            if (!theIter) {
                !_iterSymbol && (_iterSymbol = createCachedValue(getKnownSymbol(3)));
                theIter = iter[_iterSymbol.v] ? iter[_iterSymbol.v]() : null;
            }
        }
        if (theIter && isIterator(theIter)) {
            let result;
            try {
                result = doWhileAsync((state) => {
                    return doAwait(theIter.next(), (res) => {
                        iterResult = res;
                        if (!res[DONE]) {
                            return fnCall(callbackFn, thisArg || theIter, iterResult[VALUE], state.iter, theIter);
                        }
                    }, (reason) => {
                        state.isDone = true;
                        onFailed(reason);
                    });
                }, (state) => {
                    if (!iterResult || iterResult[DONE] || state.res === -1) {
                        onFinally();
                        return true;
                    }
                }, thisArg || theIter);
                if (isPromiseLike(result)) {
                    result = doFinally(result.catch(onFailed), onFinally);
                }
                return result;
            }
            catch (failed) {
                onFailed(failed);
            }
            finally {
                if (result && !isPromiseLike(result)) {
                    onFinally();
                }
            }
        }
    }
}

const REJECT = "reject";
const REJECTED_ERROR = "Rejected";
let _schedulerId = 0;
let _debugName;
let _debugIntState;
let _customErrors = {};
function _rejectDone() {
}
function _createError(type, evt, message) {
    !_customErrors[type] && (_customErrors[type] = createCustomError(type));
    let now = utcNow();
    return new (_customErrors[type])(`Task [${evt.id}] ${message || ""}- ${(evt.st ? "Running" : "Waiting")}: ${_calcTime(now, evt.st || evt.cr)}`);
}
function _calcTime(now, start) {
    return ((now - start) || "0") + " ms";
}
function _abortStaleTasks(taskQueue, staleTimeoutPeriod) {
    let now = utcNow();
    let expired = now - staleTimeoutPeriod;
    arrForEach(taskQueue, (evt) => {
        if (evt && !evt.rj && (evt.st && evt.st < expired) || (!evt.st && evt.cr && evt.cr < expired)) {
            evt && evt[REJECT](evt.rj || _createError("Aborted", evt, "Stale "));
        }
    });
}
function _removeTask(queue, taskDetail) {
    let idx = arrIndexOf(queue, taskDetail);
    if (idx !== -1) {
        queue.splice(idx, 1);
    }
}
function _addDebugState(theScheduler, nameFn, stateFn) {
    _debugName = _debugName || { toString: () => "[[SchedulerName]]" };
    _debugIntState = _debugIntState || { toString: () => "[[SchedulerState]]" };
    objDefineProp(theScheduler, _debugName, { get: nameFn });
    objDefineProp(theScheduler, _debugIntState, { get: stateFn });
}
function createTaskScheduler(newPromise, name) {
    let _theTask;
    let _running = [];
    let _waiting = [];
    let _staleTimeoutPeriod = 600000;
    let _staleTimeoutCheckPeriod = _staleTimeoutPeriod / 10;
    let _taskCount = 0;
    let _schedulerName = (name ? (name + ".") : "") + _schedulerId++;
    let _blockedTimer;
    newPromise = newPromise || createPromise;
    const _startBlockedTimer = () => {
        let hasTasks = (getLength(_running) + getLength(_waiting)) > 0;
        if (_staleTimeoutPeriod > 0) {
            if (!_blockedTimer) {
                _blockedTimer = scheduleTimeout(() => {
                    _abortStaleTasks(_running, _staleTimeoutPeriod);
                    _abortStaleTasks(_waiting, _staleTimeoutPeriod);
                    _blockedTimer && (_blockedTimer.enabled = ((getLength(_running) + getLength(_waiting)) > 0));
                }, _staleTimeoutCheckPeriod);
                _blockedTimer.unref();
            }
            _blockedTimer && (_blockedTimer.enabled = hasTasks);
        }
    };
    const _queueTask = (startAction, taskName, timeout) => {
        let taskId = _schedulerName + "." + _taskCount++;
        if (taskName) {
            taskId += "-(" + taskName + ")";
        }
        let newTask = {
            id: taskId,
            cr: utcNow(),
            to: timeout,
            [REJECT]: (reason) => {
                newTask.rj = reason || _createError(REJECTED_ERROR, newTask);
                newTask[REJECT] = _rejectDone;
            }
        };
        if (!_theTask) {
            newTask.p = newPromise(_runTask(newTask, startAction));
        }
        else {
            newTask.p = _waitForPreviousTask(newTask, _theTask, startAction);
        }
        _theTask = newTask;
        return newTask.p;
    };
    const _runTask = (taskDetail, startAction) => {
        taskDetail.st = utcNow();
        _running.push(taskDetail);
        _startBlockedTimer();
        return (onTaskResolve, onTaskReject) => {
            const _promiseReject = (reason) => {
                taskDetail.rj = taskDetail.rj || reason || _createError(REJECTED_ERROR, taskDetail);
                taskDetail[REJECT] = _rejectDone;
                _doCleanup(taskDetail);
                onTaskResolve = null;
                onTaskReject && onTaskReject(reason);
                onTaskReject = null;
            };
            let taskId = taskDetail.id;
            if (taskDetail.rj) {
                _promiseReject(taskDetail.rj);
            }
            else {
                taskDetail[REJECT] = _promiseReject;
                try {
                    let startResult = startAction(taskId);
                    if (taskDetail.to && isPromiseLike(startResult)) {
                        taskDetail.t = scheduleTimeout(() => {
                            _promiseReject(_createError("Timeout", taskDetail));
                        }, taskDetail.to);
                    }
                    doAwait(startResult, (theResult) => {
                        _doCleanup(taskDetail);
                        try {
                            onTaskResolve && onTaskResolve(theResult);
                        }
                        catch (e) {
                            onTaskReject && onTaskReject(e);
                        }
                        onTaskReject = null;
                        onTaskResolve = null;
                    }, _promiseReject);
                }
                catch (e) {
                    _promiseReject(e);
                }
            }
        };
    };
    const _waitForPreviousTask = (taskDetail, prevTask, startAction) => {
        _waiting.push(taskDetail);
        _startBlockedTimer();
        return newPromise((onWaitResolve, onWaitReject) => {
            doAwaitResponse(prevTask.p, () => {
                _removeTask(_waiting, taskDetail);
                _runTask(taskDetail, startAction)(onWaitResolve, onWaitReject);
            });
        });
    };
    const _doCleanup = (taskDetail) => {
        _removeTask(_running, taskDetail);
        taskDetail.t && taskDetail.t.cancel();
        taskDetail.t = null;
        if (_theTask && _theTask === taskDetail) {
            _theTask = null;
            if (getLength(_running) + getLength(_waiting) === 0) {
                _blockedTimer && _blockedTimer.cancel();
                _blockedTimer = null;
            }
        }
    };
    let theScheduler = {
        idle: true,
        queue: _queueTask,
        setStaleTimeout: (staleTimeout, staleCheckPeriod) => {
            _blockedTimer && _blockedTimer.cancel();
            _blockedTimer = null;
            _staleTimeoutPeriod = staleTimeout;
            _staleTimeoutCheckPeriod = staleCheckPeriod || staleTimeout / 10;
            _startBlockedTimer();
        }
    };
    objDefine(theScheduler, "idle", {
        g: () => {
            return getLength(_running) + getLength(_waiting) === 0;
        }
    });
    _addDebugState(theScheduler, () => _schedulerName, () => {
        return {
            l: _theTask,
            r: _running,
            w: _waiting
        };
    });
    return theScheduler;
}

const toStringTagSymbol = getKnownSymbol(11);
let PolyPromise = (function () {
    function PolyPromiseImpl(executor) {
        this._$ = createAsyncPromise(executor);
        if (toStringTagSymbol) {
            this[toStringTagSymbol] = "Promise";
        }
        objDefineProp(this, "state", {
            get: function () {
                return this._$.state;
            }
        });
    }
    PolyPromiseImpl.all = createAsyncAllPromise;
    PolyPromiseImpl.race = createAsyncRacePromise;
    PolyPromiseImpl.any = createAsyncAnyPromise;
    PolyPromiseImpl.reject = createAsyncRejectedPromise;
    PolyPromiseImpl.resolve = createAsyncResolvedPromise;
    PolyPromiseImpl.allSettled = createAsyncAllSettledPromise;
    let theProto = PolyPromiseImpl.prototype;
    theProto.then = function (onResolved, onRejected) {
        return this._$.then(onResolved, onRejected);
    };
    theProto.catch = function (onRejected) {
        return this._$.catch(onRejected);
    };
    theProto.finally = function (onfinally) {
        return this._$.finally(onfinally);
    };
    return PolyPromiseImpl;
}());

export { PolyPromise, arrForEachAsync, createAllPromise, createAllSettledPromise, createAnyPromise, createAsyncAllPromise, createAsyncAllSettledPromise, createAsyncAnyPromise, createAsyncPromise, createAsyncRacePromise, createAsyncRejectedPromise, createAsyncResolvedPromise, createIdleAllPromise, createIdleAllSettledPromise, createIdleAnyPromise, createIdlePromise, createIdleRacePromise, createIdleRejectedPromise, createIdleResolvedPromise, createNativeAllPromise, createNativeAllSettledPromise, createNativeAnyPromise, createNativePromise, createNativeRacePromise, createNativeRejectedPromise, createNativeResolvedPromise, createPromise, createRacePromise, createRejectedPromise, createResolvedPromise, createSyncAllPromise, createSyncAllSettledPromise, createSyncAnyPromise, createSyncPromise, createSyncRacePromise, createSyncRejectedPromise, createSyncResolvedPromise, createTaskScheduler, createTimeoutPromise, doAwait, doAwaitResponse, doFinally, doWhileAsync, iterForOfAsync, setCreatePromiseImpl, setDefaultIdlePromiseTimeout, setDefaultIdleTimeout, setPromiseDebugState };
//# sourceMappingURL=ts-async.js.map
