"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const cancellation = require("./cancellation.js");
const errors = require("./errors.js");
const event = require("./event.js");
const lifecycle = require("./lifecycle.js");
const platform = require("./platform.js");
var __awaiter = globalThis && globalThis.__awaiter || function(thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function(resolve) {
      resolve(value);
    });
  }
  return new (P || (P = Promise))(function(resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }
    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }
    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};
var __asyncValues = globalThis && globalThis.__asyncValues || function(o) {
  if (!Symbol.asyncIterator)
    throw new TypeError("Symbol.asyncIterator is not defined.");
  var m = o[Symbol.asyncIterator], i;
  return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
    return this;
  }, i);
  function verb(n) {
    i[n] = o[n] && function(v) {
      return new Promise(function(resolve, reject) {
        v = o[n](v), settle(resolve, reject, v.done, v.value);
      });
    };
  }
  function settle(resolve, reject, d, v) {
    Promise.resolve(v).then(function(v2) {
      resolve({ value: v2, done: d });
    }, reject);
  }
};
function isThenable(obj) {
  return !!obj && typeof obj.then === "function";
}
function createCancelablePromise(callback) {
  const source = new cancellation.CancellationTokenSource();
  const thenable = callback(source.token);
  const promise = new Promise((resolve, reject) => {
    const subscription = source.token.onCancellationRequested(() => {
      subscription.dispose();
      source.dispose();
      reject(new errors.CancellationError());
    });
    Promise.resolve(thenable).then((value) => {
      subscription.dispose();
      source.dispose();
      resolve(value);
    }, (err) => {
      subscription.dispose();
      source.dispose();
      reject(err);
    });
  });
  return new class {
    cancel() {
      source.cancel();
    }
    then(resolve, reject) {
      return promise.then(resolve, reject);
    }
    catch(reject) {
      return this.then(void 0, reject);
    }
    finally(onfinally) {
      return promise.finally(onfinally);
    }
  }();
}
function raceCancellation(promise, token, defaultValue) {
  return new Promise((resolve, reject) => {
    const ref = token.onCancellationRequested(() => {
      ref.dispose();
      resolve(defaultValue);
    });
    promise.then(resolve, reject).finally(() => ref.dispose());
  });
}
class Throttler {
  constructor() {
    this.activePromise = null;
    this.queuedPromise = null;
    this.queuedPromiseFactory = null;
  }
  queue(promiseFactory) {
    if (this.activePromise) {
      this.queuedPromiseFactory = promiseFactory;
      if (!this.queuedPromise) {
        const onComplete = () => {
          this.queuedPromise = null;
          const result = this.queue(this.queuedPromiseFactory);
          this.queuedPromiseFactory = null;
          return result;
        };
        this.queuedPromise = new Promise((resolve) => {
          this.activePromise.then(onComplete, onComplete).then(resolve);
        });
      }
      return new Promise((resolve, reject) => {
        this.queuedPromise.then(resolve, reject);
      });
    }
    this.activePromise = promiseFactory();
    return new Promise((resolve, reject) => {
      this.activePromise.then((result) => {
        this.activePromise = null;
        resolve(result);
      }, (err) => {
        this.activePromise = null;
        reject(err);
      });
    });
  }
}
const timeoutDeferred = (timeout2, fn) => {
  let scheduled = true;
  const handle = setTimeout(() => {
    scheduled = false;
    fn();
  }, timeout2);
  return {
    isTriggered: () => scheduled,
    dispose: () => {
      clearTimeout(handle);
      scheduled = false;
    }
  };
};
const microtaskDeferred = (fn) => {
  let scheduled = true;
  queueMicrotask(() => {
    if (scheduled) {
      scheduled = false;
      fn();
    }
  });
  return {
    isTriggered: () => scheduled,
    dispose: () => {
      scheduled = false;
    }
  };
};
const MicrotaskDelay = Symbol("MicrotaskDelay");
class Delayer {
  constructor(defaultDelay) {
    this.defaultDelay = defaultDelay;
    this.deferred = null;
    this.completionPromise = null;
    this.doResolve = null;
    this.doReject = null;
    this.task = null;
  }
  trigger(task, delay = this.defaultDelay) {
    this.task = task;
    this.cancelTimeout();
    if (!this.completionPromise) {
      this.completionPromise = new Promise((resolve, reject) => {
        this.doResolve = resolve;
        this.doReject = reject;
      }).then(() => {
        this.completionPromise = null;
        this.doResolve = null;
        if (this.task) {
          const task2 = this.task;
          this.task = null;
          return task2();
        }
        return void 0;
      });
    }
    const fn = () => {
      var _a;
      this.deferred = null;
      (_a = this.doResolve) === null || _a === void 0 ? void 0 : _a.call(this, null);
    };
    this.deferred = delay === MicrotaskDelay ? microtaskDeferred(fn) : timeoutDeferred(delay, fn);
    return this.completionPromise;
  }
  isTriggered() {
    var _a;
    return !!((_a = this.deferred) === null || _a === void 0 ? void 0 : _a.isTriggered());
  }
  cancel() {
    this.cancelTimeout();
    if (this.completionPromise) {
      if (this.doReject) {
        this.doReject(new errors.CancellationError());
      }
      this.completionPromise = null;
    }
  }
  cancelTimeout() {
    var _a;
    (_a = this.deferred) === null || _a === void 0 ? void 0 : _a.dispose();
    this.deferred = null;
  }
  dispose() {
    this.cancel();
  }
}
class ThrottledDelayer {
  constructor(defaultDelay) {
    this.delayer = new Delayer(defaultDelay);
    this.throttler = new Throttler();
  }
  trigger(promiseFactory, delay) {
    return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay);
  }
  dispose() {
    this.delayer.dispose();
  }
}
function timeout(millis, token) {
  if (!token) {
    return createCancelablePromise((token2) => timeout(millis, token2));
  }
  return new Promise((resolve, reject) => {
    const handle = setTimeout(() => {
      disposable.dispose();
      resolve();
    }, millis);
    const disposable = token.onCancellationRequested(() => {
      clearTimeout(handle);
      disposable.dispose();
      reject(new errors.CancellationError());
    });
  });
}
function disposableTimeout(handler, timeout2 = 0) {
  const timer = setTimeout(handler, timeout2);
  return lifecycle.toDisposable(() => clearTimeout(timer));
}
function first(promiseFactories, shouldStop = (t) => !!t, defaultValue = null) {
  let index = 0;
  const len = promiseFactories.length;
  const loop = () => {
    if (index >= len) {
      return Promise.resolve(defaultValue);
    }
    const factory = promiseFactories[index++];
    const promise = Promise.resolve(factory());
    return promise.then((result) => {
      if (shouldStop(result)) {
        return Promise.resolve(result);
      }
      return loop();
    });
  };
  return loop();
}
class TimeoutTimer {
  constructor(runner, timeout2) {
    this._token = -1;
    if (typeof runner === "function" && typeof timeout2 === "number") {
      this.setIfNotSet(runner, timeout2);
    }
  }
  dispose() {
    this.cancel();
  }
  cancel() {
    if (this._token !== -1) {
      clearTimeout(this._token);
      this._token = -1;
    }
  }
  cancelAndSet(runner, timeout2) {
    this.cancel();
    this._token = setTimeout(() => {
      this._token = -1;
      runner();
    }, timeout2);
  }
  setIfNotSet(runner, timeout2) {
    if (this._token !== -1) {
      return;
    }
    this._token = setTimeout(() => {
      this._token = -1;
      runner();
    }, timeout2);
  }
}
class IntervalTimer {
  constructor() {
    this._token = -1;
  }
  dispose() {
    this.cancel();
  }
  cancel() {
    if (this._token !== -1) {
      clearInterval(this._token);
      this._token = -1;
    }
  }
  cancelAndSet(runner, interval) {
    this.cancel();
    this._token = setInterval(() => {
      runner();
    }, interval);
  }
}
class RunOnceScheduler {
  constructor(runner, delay) {
    this.timeoutToken = -1;
    this.runner = runner;
    this.timeout = delay;
    this.timeoutHandler = this.onTimeout.bind(this);
  }
  /**
   * Dispose RunOnceScheduler
   */
  dispose() {
    this.cancel();
    this.runner = null;
  }
  /**
   * Cancel current scheduled runner (if any).
   */
  cancel() {
    if (this.isScheduled()) {
      clearTimeout(this.timeoutToken);
      this.timeoutToken = -1;
    }
  }
  /**
   * Cancel previous runner (if any) & schedule a new runner.
   */
  schedule(delay = this.timeout) {
    this.cancel();
    this.timeoutToken = setTimeout(this.timeoutHandler, delay);
  }
  get delay() {
    return this.timeout;
  }
  set delay(value) {
    this.timeout = value;
  }
  /**
   * Returns true if scheduled.
   */
  isScheduled() {
    return this.timeoutToken !== -1;
  }
  onTimeout() {
    this.timeoutToken = -1;
    if (this.runner) {
      this.doRun();
    }
  }
  doRun() {
    if (this.runner) {
      this.runner();
    }
  }
}
exports.runWhenIdle = void 0;
(function() {
  if (typeof requestIdleCallback !== "function" || typeof cancelIdleCallback !== "function") {
    exports.runWhenIdle = (runner) => {
      platform.setTimeout0(() => {
        if (disposed) {
          return;
        }
        const end = Date.now() + 15;
        runner(Object.freeze({
          didTimeout: true,
          timeRemaining() {
            return Math.max(0, end - Date.now());
          }
        }));
      });
      let disposed = false;
      return {
        dispose() {
          if (disposed) {
            return;
          }
          disposed = true;
        }
      };
    };
  } else {
    exports.runWhenIdle = (runner, timeout2) => {
      const handle = requestIdleCallback(runner, typeof timeout2 === "number" ? { timeout: timeout2 } : void 0);
      let disposed = false;
      return {
        dispose() {
          if (disposed) {
            return;
          }
          disposed = true;
          cancelIdleCallback(handle);
        }
      };
    };
  }
})();
class IdleValue {
  constructor(executor) {
    this._didRun = false;
    this._executor = () => {
      try {
        this._value = executor();
      } catch (err) {
        this._error = err;
      } finally {
        this._didRun = true;
      }
    };
    this._handle = exports.runWhenIdle(() => this._executor());
  }
  dispose() {
    this._handle.dispose();
  }
  get value() {
    if (!this._didRun) {
      this._handle.dispose();
      this._executor();
    }
    if (this._error) {
      throw this._error;
    }
    return this._value;
  }
  get isInitialized() {
    return this._didRun;
  }
}
class DeferredPromise {
  constructor() {
    this.rejected = false;
    this.resolved = false;
    this.p = new Promise((c, e) => {
      this.completeCallback = c;
      this.errorCallback = e;
    });
  }
  get isRejected() {
    return this.rejected;
  }
  get isSettled() {
    return this.rejected || this.resolved;
  }
  complete(value) {
    return new Promise((resolve) => {
      this.completeCallback(value);
      this.resolved = true;
      resolve();
    });
  }
  cancel() {
    new Promise((resolve) => {
      this.errorCallback(new errors.CancellationError());
      this.rejected = true;
      resolve();
    });
  }
}
exports.Promises = void 0;
(function(Promises) {
  function settled(promises) {
    return __awaiter(this, void 0, void 0, function* () {
      let firstError = void 0;
      const result = yield Promise.all(promises.map((promise) => promise.then((value) => value, (error) => {
        if (!firstError) {
          firstError = error;
        }
        return void 0;
      })));
      if (typeof firstError !== "undefined") {
        throw firstError;
      }
      return result;
    });
  }
  Promises.settled = settled;
  function withAsyncBody(bodyFn) {
    return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
      try {
        yield bodyFn(resolve, reject);
      } catch (error) {
        reject(error);
      }
    }));
  }
  Promises.withAsyncBody = withAsyncBody;
})(exports.Promises || (exports.Promises = {}));
class AsyncIterableObject {
  constructor(executor) {
    this._state = 0;
    this._results = [];
    this._error = null;
    this._onStateChanged = new event.Emitter();
    queueMicrotask(() => __awaiter(this, void 0, void 0, function* () {
      const writer = {
        emitOne: (item) => this.emitOne(item),
        emitMany: (items) => this.emitMany(items),
        reject: (error) => this.reject(error)
      };
      try {
        yield Promise.resolve(executor(writer));
        this.resolve();
      } catch (err) {
        this.reject(err);
      } finally {
        writer.emitOne = void 0;
        writer.emitMany = void 0;
        writer.reject = void 0;
      }
    }));
  }
  static fromArray(items) {
    return new AsyncIterableObject((writer) => {
      writer.emitMany(items);
    });
  }
  static fromPromise(promise) {
    return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () {
      emitter.emitMany(yield promise);
    }));
  }
  static fromPromises(promises) {
    return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () {
      yield Promise.all(promises.map((p) => __awaiter(this, void 0, void 0, function* () {
        return emitter.emitOne(yield p);
      })));
    }));
  }
  static merge(iterables) {
    return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () {
      yield Promise.all(iterables.map((iterable) => {
        var iterable_1, iterable_1_1;
        return __awaiter(this, void 0, void 0, function* () {
          var e_1, _a;
          try {
            for (iterable_1 = __asyncValues(iterable); iterable_1_1 = yield iterable_1.next(), !iterable_1_1.done; ) {
              const item = iterable_1_1.value;
              emitter.emitOne(item);
            }
          } catch (e_1_1) {
            e_1 = { error: e_1_1 };
          } finally {
            try {
              if (iterable_1_1 && !iterable_1_1.done && (_a = iterable_1.return))
                yield _a.call(iterable_1);
            } finally {
              if (e_1)
                throw e_1.error;
            }
          }
        });
      }));
    }));
  }
  [Symbol.asyncIterator]() {
    let i = 0;
    return {
      next: () => __awaiter(this, void 0, void 0, function* () {
        do {
          if (this._state === 2) {
            throw this._error;
          }
          if (i < this._results.length) {
            return { done: false, value: this._results[i++] };
          }
          if (this._state === 1) {
            return { done: true, value: void 0 };
          }
          yield event.Event.toPromise(this._onStateChanged.event);
        } while (true);
      })
    };
  }
  static map(iterable, mapFn) {
    return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () {
      var e_2, _a;
      try {
        for (var iterable_2 = __asyncValues(iterable), iterable_2_1; iterable_2_1 = yield iterable_2.next(), !iterable_2_1.done; ) {
          const item = iterable_2_1.value;
          emitter.emitOne(mapFn(item));
        }
      } catch (e_2_1) {
        e_2 = { error: e_2_1 };
      } finally {
        try {
          if (iterable_2_1 && !iterable_2_1.done && (_a = iterable_2.return))
            yield _a.call(iterable_2);
        } finally {
          if (e_2)
            throw e_2.error;
        }
      }
    }));
  }
  map(mapFn) {
    return AsyncIterableObject.map(this, mapFn);
  }
  static filter(iterable, filterFn) {
    return new AsyncIterableObject((emitter) => __awaiter(this, void 0, void 0, function* () {
      var e_3, _a;
      try {
        for (var iterable_3 = __asyncValues(iterable), iterable_3_1; iterable_3_1 = yield iterable_3.next(), !iterable_3_1.done; ) {
          const item = iterable_3_1.value;
          if (filterFn(item)) {
            emitter.emitOne(item);
          }
        }
      } catch (e_3_1) {
        e_3 = { error: e_3_1 };
      } finally {
        try {
          if (iterable_3_1 && !iterable_3_1.done && (_a = iterable_3.return))
            yield _a.call(iterable_3);
        } finally {
          if (e_3)
            throw e_3.error;
        }
      }
    }));
  }
  filter(filterFn) {
    return AsyncIterableObject.filter(this, filterFn);
  }
  static coalesce(iterable) {
    return AsyncIterableObject.filter(iterable, (item) => !!item);
  }
  coalesce() {
    return AsyncIterableObject.coalesce(this);
  }
  static toPromise(iterable) {
    var iterable_4, iterable_4_1;
    var e_4, _a;
    return __awaiter(this, void 0, void 0, function* () {
      const result = [];
      try {
        for (iterable_4 = __asyncValues(iterable); iterable_4_1 = yield iterable_4.next(), !iterable_4_1.done; ) {
          const item = iterable_4_1.value;
          result.push(item);
        }
      } catch (e_4_1) {
        e_4 = { error: e_4_1 };
      } finally {
        try {
          if (iterable_4_1 && !iterable_4_1.done && (_a = iterable_4.return))
            yield _a.call(iterable_4);
        } finally {
          if (e_4)
            throw e_4.error;
        }
      }
      return result;
    });
  }
  toPromise() {
    return AsyncIterableObject.toPromise(this);
  }
  /**
   * The value will be appended at the end.
   *
   * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
   */
  emitOne(value) {
    if (this._state !== 0) {
      return;
    }
    this._results.push(value);
    this._onStateChanged.fire();
  }
  /**
   * The values will be appended at the end.
   *
   * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
   */
  emitMany(values) {
    if (this._state !== 0) {
      return;
    }
    this._results = this._results.concat(values);
    this._onStateChanged.fire();
  }
  /**
   * Calling `resolve()` will mark the result array as complete.
   *
   * **NOTE** `resolve()` must be called, otherwise all consumers of this iterable will hang indefinitely, similar to a non-resolved promise.
   * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
   */
  resolve() {
    if (this._state !== 0) {
      return;
    }
    this._state = 1;
    this._onStateChanged.fire();
  }
  /**
   * Writing an error will permanently invalidate this iterable.
   * The current users will receive an error thrown, as will all future users.
   *
   * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.
   */
  reject(error) {
    if (this._state !== 0) {
      return;
    }
    this._state = 2;
    this._error = error;
    this._onStateChanged.fire();
  }
}
AsyncIterableObject.EMPTY = AsyncIterableObject.fromArray([]);
class CancelableAsyncIterableObject extends AsyncIterableObject {
  constructor(_source, executor) {
    super(executor);
    this._source = _source;
  }
  cancel() {
    this._source.cancel();
  }
}
function createCancelableAsyncIterable(callback) {
  const source = new cancellation.CancellationTokenSource();
  const innerIterable = callback(source.token);
  return new CancelableAsyncIterableObject(source, (emitter) => __awaiter(this, void 0, void 0, function* () {
    var e_5, _a;
    const subscription = source.token.onCancellationRequested(() => {
      subscription.dispose();
      source.dispose();
      emitter.reject(new errors.CancellationError());
    });
    try {
      try {
        for (var innerIterable_1 = __asyncValues(innerIterable), innerIterable_1_1; innerIterable_1_1 = yield innerIterable_1.next(), !innerIterable_1_1.done; ) {
          const item = innerIterable_1_1.value;
          if (source.token.isCancellationRequested) {
            return;
          }
          emitter.emitOne(item);
        }
      } catch (e_5_1) {
        e_5 = { error: e_5_1 };
      } finally {
        try {
          if (innerIterable_1_1 && !innerIterable_1_1.done && (_a = innerIterable_1.return))
            yield _a.call(innerIterable_1);
        } finally {
          if (e_5)
            throw e_5.error;
        }
      }
      subscription.dispose();
      source.dispose();
    } catch (err) {
      subscription.dispose();
      source.dispose();
      emitter.reject(err);
    }
  }));
}
exports.AsyncIterableObject = AsyncIterableObject;
exports.CancelableAsyncIterableObject = CancelableAsyncIterableObject;
exports.DeferredPromise = DeferredPromise;
exports.Delayer = Delayer;
exports.IdleValue = IdleValue;
exports.IntervalTimer = IntervalTimer;
exports.MicrotaskDelay = MicrotaskDelay;
exports.RunOnceScheduler = RunOnceScheduler;
exports.ThrottledDelayer = ThrottledDelayer;
exports.Throttler = Throttler;
exports.TimeoutTimer = TimeoutTimer;
exports.createCancelableAsyncIterable = createCancelableAsyncIterable;
exports.createCancelablePromise = createCancelablePromise;
exports.disposableTimeout = disposableTimeout;
exports.first = first;
exports.isThenable = isThenable;
exports.raceCancellation = raceCancellation;
exports.timeout = timeout;
