/*!
 * NevWare21 Solutions LLC - ts-async, 0.6.1
 * https://github.com/nevware21/ts-async
 * Copyright (c) NevWare21 Solutions LLC and contributors. All rights reserved.
 * Licensed under the MIT license.
 */
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@nevware21/ts-utils')) :
    typeof define === 'function' && define.amd ? define(['exports', '@nevware21/ts-utils'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.nevware21 = global.nevware21 || {}, global.nevware21["ts-async"] = {}), global.nevware21["ts-utils"]));
})(this, (function (exports, tsUtils) { 'use strict';

    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 (tsUtils.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 (tsUtils.isPromiseLike(value)) {
                if (value.finally) {
                    result = value.finally(finallyFn);
                }
                else {
                    result = value.then(function (value) {
                        return doAwait(finallyFn(), function () {
                            return value;
                        });
                    }, function (reason) {
                        return doAwait(finallyFn(), function () {
                            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 };
        tsUtils.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 = tsUtils.getDocument();
        !_hasInitEvent && (_hasInitEvent = tsUtils.createCachedValue(!!tsUtils.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 = tsUtils.getInst("console");
                theConsole && (theConsole["error"] || theConsole["log"])(evtName, tsUtils.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 (tsUtils.isFunction(value)) {
            return value.toString();
        }
        return tsUtils.dumpObj(value);
    }
    function _createAggregationError(values) {
        !_aggregationError && (_aggregationError = tsUtils.createCachedValue(tsUtils.safe(tsUtils.getInst, ["AggregationError"]).v || tsUtils.createCustomError("AggregationError", (self, args) => {
            self.errors = args[0];
        })));
        return new _aggregationError.v(values);
    }
    function _createPromise(newPromise, processor, executor) {
        let additionalArgs = tsUtils.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 = tsUtils.isFunction(handler) ? handler(_settledValue) : _settledValue;
                            if (tsUtils.isPromiseLike(value)) {
                                value.then(resolve, reject);
                            }
                            else if (tsUtils.isFunction(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 (tsUtils.isFunction(onFinally)) {
                thenFinally = function (value) {
                    return doAwait(onFinally && onFinally(), () => {
                        return value;
                    });
                };
                catchFinally = function (reason) {
                    return doAwait(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 && tsUtils.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 = tsUtils.scheduleTimeout(_notifyUnhandledRejection, _unhandledRejectionTimeout);
                    }
                }
            };
        }
        function _notifyUnhandledRejection() {
            if (!_handled) {
                _handled = true;
                if (tsUtils.isNode()) {
                    process.emit(NODE_UNHANDLED_REJECTION, _settledValue, _thePromise);
                }
                else {
                    let gbl = tsUtils.getWindow() || tsUtils.getGlobal();
                    !_hasPromiseRejectionEvent && (_hasPromiseRejectionEvent = tsUtils.createCachedValue(tsUtils.safe((tsUtils.getInst), [STR_PROMISE + "RejectionEvent"]).v));
                    emitEvent(gbl, UNHANDLED_REJECTION, (theEvt) => {
                        tsUtils.objDefine(theEvt, "promise", { g: () => _thePromise });
                        theEvt.reason = _settledValue;
                        return theEvt;
                    }, !!_hasPromiseRejectionEvent.v);
                }
            }
        }
        _thePromise = {
            then: _then,
            "catch": _catch,
            finally: _finally
        };
        tsUtils.objDefineProp(_thePromise, "state", {
            get: _strState
        });
        if (_promiseDebugEnabled) {
            _addDebugState$1(_thePromise, _strState, () => { return tsUtils.objToString(_settledValue); }, () => _handled);
        }
        if (tsUtils.hasSymbol()) {
            _thePromise[tsUtils.getKnownSymbol(11)] = "IPromise";
        }
        function _toString() {
            return "IPromise" + (_promiseDebugEnabled ? "[" + _id + (!tsUtils.isUndefined(_parentId) ? (":" + _parentId) : "") + "]" : "") + " " + _strState() + (_hasResolved ? (" - " + dumpFnObj(_settledValue)) : "") + ("");
        }
        _thePromise.toString = _toString;
        (function _initialize() {
            if (!tsUtils.isFunction(executor)) {
                tsUtils.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 = tsUtils.arrSlice(arguments, 1);
            return newPromise((resolve, reject) => {
                try {
                    let values = [];
                    let pending = 1;
                    tsUtils.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 = tsUtils.arrSlice(arguments, 1);
            if (tsUtils.isPromiseLike(value)) {
                return value;
            }
            return newPromise((resolve) => {
                resolve(value);
            }, additionalArgs);
        };
    }
    function _createRejectedPromise(newPromise) {
        return function (reason) {
            let additionalArgs = tsUtils.arrSlice(arguments, 1);
            return newPromise((_resolve, reject) => {
                reject(reason);
            }, additionalArgs);
        };
    }
    function _createAllSettledPromise(newPromise, ..._args) {
        return tsUtils.createCachedValue(function (input, ..._args) {
            let additionalArgs = tsUtils.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 (tsUtils.isArray(input)) {
                        tsUtils.arrForEach(input, processItem);
                    }
                    else if (tsUtils.isIterable(input)) {
                        tsUtils.iterForOf(input, processItem);
                    }
                    else {
                        tsUtils.throwTypeError("Input is not an iterable");
                    }
                    pending--;
                    if (pending === 0) {
                        resolve(values);
                    }
                }
                catch (e) {
                    reject(e);
                }
            }, additionalArgs);
        });
    }
    function _createRacePromise(newPromise, ..._args) {
        return tsUtils.createCachedValue(function (input, ..._args) {
            let additionalArgs = tsUtils.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 (tsUtils.isArray(input)) {
                        tsUtils.arrForEach(input, processItem);
                    }
                    else if (tsUtils.isIterable(input)) {
                        tsUtils.iterForOf(input, processItem);
                    }
                    else {
                        tsUtils.throwTypeError("Input is not an iterable");
                    }
                }
                catch (e) {
                    reject(e);
                }
            }, additionalArgs);
        });
    }
    function _createAnyPromise(newPromise, ..._args) {
        return tsUtils.createCachedValue(function (input, ..._args) {
            let additionalArgs = tsUtils.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 (tsUtils.isArray(input)) {
                        tsUtils.arrForEach(input, processItem);
                    }
                    else if (tsUtils.isIterable(input)) {
                        tsUtils.iterForOf(input, processItem);
                    }
                    else {
                        tsUtils.throwTypeError("Input is not an iterable");
                    }
                    pending--;
                    if (pending === 0 && !isDone) {
                        reject(_createAggregationError(theErros));
                    }
                }
                catch (e) {
                    reject(e);
                }
            }, additionalArgs);
        });
    }

    function _normalizeTimeoutValue(timeout, defaultTimeout) {
        let result = defaultTimeout;
        if (!tsUtils.isUndefined(timeout)) {
            if (tsUtils.isNumber(timeout)) {
                result = timeout;
            }
            else {
                while (!tsUtils.isUndefined(timeout) && tsUtils.isArray(timeout) && timeout.length > 0) {
                    timeout = timeout[0];
                    if (tsUtils.isNumber(timeout)) {
                        result = timeout;
                        break;
                    }
                }
            }
        }
        return result;
    }

    function _isFakeTimersEnabled() {
        let setTimeoutFn = setTimeout;
        return !!(setTimeoutFn && setTimeoutFn.clock);
    }
    function syncItemProcessor(pending) {
        tsUtils.arrForEach(pending, (fn) => {
            try {
                fn();
            }
            catch (e) {
            }
        });
    }
    function timeoutItemProcessor(timeout) {
        let timeoutValue = _normalizeTimeoutValue(timeout);
        let hasTimeout = tsUtils.isNumber(timeoutValue);
        let callbackTimeout = hasTimeout ? timeoutValue : 0;
        return (pending) => {
            function _processPending() {
                syncItemProcessor(pending);
            }
            if (hasTimeout && callbackTimeout > 0) {
                tsUtils.scheduleTimeout(_processPending, callbackTimeout);
            }
            else if (_isFakeTimersEnabled()) {
                tsUtils.scheduleTimeout(_processPending, 0);
            }
            else {
                tsUtils.scheduleMicrotask(_processPending);
            }
        };
    }

    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 = tsUtils.createCachedValue((tsUtils.safe(tsUtils.getInst, [STR_PROMISE]).v) || null));
        if (_promiseCls.v && _promiseCls.v[name]) {
            return tsUtils.createCachedValue(function (input, timeout) {
                return createNativePromise((resolve, reject) => {
                    _promiseCls.v[name](input).then(resolve, reject);
                });
            });
        }
        return func();
    }
    function createNativePromise(executor, timeout) {
        !_promiseCls && (_promiseCls = tsUtils.createCachedValue((tsUtils.safe(tsUtils.getInst, [STR_PROMISE]).v) || null));
        const PrmCls = _promiseCls.v;
        if (!PrmCls) {
            return createAsyncPromise(executor);
        }
        if (!tsUtils.isFunction(executor)) {
            tsUtils.throwTypeError(STR_PROMISE + ": executor is not a function - " + tsUtils.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);
        });
        tsUtils.objDefineProp(thePromise, "state", {
            get: _strState
        });
        return thePromise;
    }
    function createNativeAllPromise(input, timeout) {
        !_allCreator && (_allCreator = _createNativePromiseHelper("all", () => tsUtils.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 options;
        let theTimeout = _normalizeTimeoutValue(timeout, _defaultIdleTimeout);
        if (tsUtils.isNumber(theTimeout) && theTimeout >= 0) {
            options = {
                timeout: theTimeout
            };
        }
        let processor = (pending) => {
            tsUtils.scheduleIdleCallback((deadline) => {
                syncItemProcessor(pending);
            }, options);
        };
        return _createPromise(createIdlePromise, processor, 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 ? tsUtils.createCachedValue(creator) : null;
    }
    function createPromise(executor, timeout) {
        !_promiseCreator && (_promiseCreator = tsUtils.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) => {
            tsUtils.scheduleTimeout(() => {
                (resolveReject ? resolve : reject)(!tsUtils.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 && tsUtils.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: tsUtils.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 (tsUtils.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 (tsUtils.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 = tsUtils.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 (!tsUtils.isIterator(iter)) {
                !_iterAsyncSymbol && (_iterAsyncSymbol = tsUtils.createCachedValue(tsUtils.getKnownSymbol(0)));
                theIter = iter[_iterAsyncSymbol.v] ? iter[_iterAsyncSymbol.v]() : null;
                if (!theIter) {
                    !_iterSymbol && (_iterSymbol = tsUtils.createCachedValue(tsUtils.getKnownSymbol(3)));
                    theIter = iter[_iterSymbol.v] ? iter[_iterSymbol.v]() : null;
                }
            }
            if (theIter && tsUtils.isIterator(theIter)) {
                let result;
                try {
                    result = doWhileAsync((state) => {
                        return doAwait(theIter.next(), (res) => {
                            iterResult = res;
                            if (!res[DONE]) {
                                return tsUtils.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 (tsUtils.isPromiseLike(result)) {
                        result = doFinally(result.catch(onFailed), onFinally);
                    }
                    return result;
                }
                catch (failed) {
                    onFailed(failed);
                }
                finally {
                    if (result && !tsUtils.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] = tsUtils.createCustomError(type));
        let now = tsUtils.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 = tsUtils.utcNow();
        let expired = now - staleTimeoutPeriod;
        tsUtils.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 = tsUtils.arrIndexOf(queue, taskDetail);
        if (idx !== -1) {
            queue.splice(idx, 1);
        }
    }
    function _addDebugState(theScheduler, nameFn, stateFn) {
        _debugName = _debugName || { toString: () => "[[SchedulerName]]" };
        _debugIntState = _debugIntState || { toString: () => "[[SchedulerState]]" };
        tsUtils.objDefineProp(theScheduler, _debugName, { get: nameFn });
        tsUtils.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 = (tsUtils.getLength(_running) + tsUtils.getLength(_waiting)) > 0;
            if (_staleTimeoutPeriod > 0) {
                if (!_blockedTimer) {
                    _blockedTimer = tsUtils.scheduleTimeout(() => {
                        _abortStaleTasks(_running, _staleTimeoutPeriod);
                        _abortStaleTasks(_waiting, _staleTimeoutPeriod);
                        _blockedTimer && (_blockedTimer.enabled = ((tsUtils.getLength(_running) + tsUtils.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: tsUtils.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 = tsUtils.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 && tsUtils.isPromiseLike(startResult)) {
                            taskDetail.t = tsUtils.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);
            _removeTask(_waiting, taskDetail);
            taskDetail.t && taskDetail.t.cancel();
            taskDetail.t = null;
            if (_theTask && _theTask === taskDetail) {
                _theTask = null;
                if (tsUtils.getLength(_running) + tsUtils.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();
            }
        };
        tsUtils.objDefine(theScheduler, "idle", {
            g: () => {
                return tsUtils.getLength(_running) + tsUtils.getLength(_waiting) === 0;
            }
        });
        _addDebugState(theScheduler, () => _schedulerName, () => {
            return {
                l: _theTask,
                r: _running,
                w: _waiting
            };
        });
        return theScheduler;
    }

    const toStringTagSymbol = tsUtils.getKnownSymbol(11);
    let PolyPromise = ((function () {
        function PolyPromiseImpl(executor) {
            this._$ = createAsyncPromise(executor);
            if (toStringTagSymbol) {
                this[toStringTagSymbol] = "Promise";
            }
            tsUtils.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;
    }()));

    exports.PolyPromise = PolyPromise;
    exports.arrForEachAsync = arrForEachAsync;
    exports.createAllPromise = createAllPromise;
    exports.createAllSettledPromise = createAllSettledPromise;
    exports.createAnyPromise = createAnyPromise;
    exports.createAsyncAllPromise = createAsyncAllPromise;
    exports.createAsyncAllSettledPromise = createAsyncAllSettledPromise;
    exports.createAsyncAnyPromise = createAsyncAnyPromise;
    exports.createAsyncPromise = createAsyncPromise;
    exports.createAsyncRacePromise = createAsyncRacePromise;
    exports.createAsyncRejectedPromise = createAsyncRejectedPromise;
    exports.createAsyncResolvedPromise = createAsyncResolvedPromise;
    exports.createIdleAllPromise = createIdleAllPromise;
    exports.createIdleAllSettledPromise = createIdleAllSettledPromise;
    exports.createIdleAnyPromise = createIdleAnyPromise;
    exports.createIdlePromise = createIdlePromise;
    exports.createIdleRacePromise = createIdleRacePromise;
    exports.createIdleRejectedPromise = createIdleRejectedPromise;
    exports.createIdleResolvedPromise = createIdleResolvedPromise;
    exports.createNativeAllPromise = createNativeAllPromise;
    exports.createNativeAllSettledPromise = createNativeAllSettledPromise;
    exports.createNativeAnyPromise = createNativeAnyPromise;
    exports.createNativePromise = createNativePromise;
    exports.createNativeRacePromise = createNativeRacePromise;
    exports.createNativeRejectedPromise = createNativeRejectedPromise;
    exports.createNativeResolvedPromise = createNativeResolvedPromise;
    exports.createPromise = createPromise;
    exports.createRacePromise = createRacePromise;
    exports.createRejectedPromise = createRejectedPromise;
    exports.createResolvedPromise = createResolvedPromise;
    exports.createSyncAllPromise = createSyncAllPromise;
    exports.createSyncAllSettledPromise = createSyncAllSettledPromise;
    exports.createSyncAnyPromise = createSyncAnyPromise;
    exports.createSyncPromise = createSyncPromise;
    exports.createSyncRacePromise = createSyncRacePromise;
    exports.createSyncRejectedPromise = createSyncRejectedPromise;
    exports.createSyncResolvedPromise = createSyncResolvedPromise;
    exports.createTaskScheduler = createTaskScheduler;
    exports.createTimeoutPromise = createTimeoutPromise;
    exports.doAwait = doAwait;
    exports.doAwaitResponse = doAwaitResponse;
    exports.doFinally = doFinally;
    exports.doWhileAsync = doWhileAsync;
    exports.iterForOfAsync = iterForOfAsync;
    exports.setCreatePromiseImpl = setCreatePromiseImpl;
    exports.setDefaultIdlePromiseTimeout = setDefaultIdlePromiseTimeout;
    exports.setDefaultIdleTimeout = setDefaultIdleTimeout;
    exports.setPromiseDebugState = setPromiseDebugState;

}));
//# sourceMappingURL=ts-async.js.map
