text: // Copyright (c) Microsoft Corporation.
  // Licensed under the MIT license.
  import { __awaiter, __extends, __generator } from "tslib";
  /**
   * When a poller is manually stopped through the `stopPolling` method,
   * the poller will be rejected with an instance of the PollerStoppedError.
   */
  var PollerStoppedError = /** @class */ (function (_super) {
      __extends(PollerStoppedError, _super);
      function PollerStoppedError(message) {
          var _this = _super.call(this, message) || this;
          _this.name = "PollerStoppedError";
          Object.setPrototypeOf(_this, PollerStoppedError.prototype);
          return _this;
      }
      return PollerStoppedError;
  }(Error));
  export { PollerStoppedError };
  /**
   * When a poller is cancelled through the `cancelOperation` method,
   * the poller will be rejected with an instance of the PollerCancelledError.
   */
  var PollerCancelledError = /** @class */ (function (_super) {
      __extends(PollerCancelledError, _super);
      function PollerCancelledError(message) {
          var _this = _super.call(this, message) || this;
          _this.name = "PollerCancelledError";
          Object.setPrototypeOf(_this, PollerCancelledError.prototype);
          return _this;
      }
      return PollerCancelledError;
  }(Error));
  export { PollerCancelledError };
  /**
   * A class that represents the definition of a program that polls through consecutive requests
   * until it reaches a state of completion.
   *
   * A poller can be executed manually, by polling request by request by calling to the `poll()` method repeatedly, until its operation is completed.
   * It also provides a way to wait until the operation completes, by calling `pollUntilDone()` and waiting until the operation finishes.
   * Pollers can also request the cancellation of the ongoing process to whom is providing the underlying long running operation.
   *
   * ```ts
   * const poller = new MyPoller();
   *
   * // Polling just once:
   * await poller.poll();
   *
   * // We can try to cancel the request here, by calling:
   * //
   * //     await poller.cancelOperation();
   * //
   *
   * // Getting the final result:
   * const result = await poller.pollUntilDone();
   * ```
   *
   * The Poller is defined by two types, a type representing the state of the poller, which
   * must include a basic set of properties from `PollOperationState<TResult>`,
   * and a return type defined by `TResult`, which can be anything.
   *
   * The Poller class implements the `PollerLike` interface, which allows poller implementations to avoid having
   * to export the Poller's class directly, and instead only export the already instantiated poller with the PollerLike type.
   *
   * ```ts
   * class Client {
   *   public async makePoller: PollerLike<MyOperationState, MyResult> {
   *     const poller = new MyPoller({});
   *     // It might be preferred to return the poller after the first request is made,
   *     // so that some information can be obtained right away.
   *     await poller.poll();
   *     return poller;
   *   }
   * }
   *
   * const poller: PollerLike<MyOperationState, MyResult> = myClient.makePoller();
   * ```
   *
   * A poller can be created through its constructor, then it can be polled until it's completed.
   * At any point in time, the state of the poller can be obtained without delay through the getOperationState method.
   * At any point in time, the intermediate forms of the result type can be requested without delay.
   * Once the underlying operation is marked as completed, the poller will stop and the final value will be returned.
   *
   * ```ts
   * const poller = myClient.makePoller();
   * const state: MyOperationState = poller.getOperationState();
   *
   * // The intermediate result can be obtained at any time.
   * const result: MyResult | undefined = poller.getResult();
   *
   * // The final result can only be obtained after the poller finishes.
   * const result: MyResult = await poller.pollUntilDone();
   * ```
   *
   */
  // eslint-disable-next-line no-use-before-define
  var Poller = /** @class */ (function () {
      /**
       * A poller needs to be initialized by passing in at least the basic properties of the `PollOperation<TState, TResult>`.
       *
       * When writing an implementation of a Poller, this implementation needs to deal with the initialization
       * of any custom state beyond the basic definition of the poller. The basic poller assumes that the poller's
       * operation has already been defined, at least its basic properties. The code below shows how to approach
       * the definition of the constructor of a new custom poller.
       *
       * ```ts
       * export class MyPoller extends Poller<MyOperationState, string> {
       *   constructor({
       *     // Anything you might need outside of the basics
       *   }) {
       *     let state: MyOperationState = {
       *       privateProperty: private,
       *       publicProperty: public,
       *     };
       *
       *     const operation = {
       *       state,
       *       update,
       *       cancel,
       *       toString
       *     }
       *
       *     // Sending the operation to the parent's constructor.
       *     super(operation);
       *
       *     // You can assign more local properties here.
       *   }
       * }
       * ```
       *
       * Inside of this constructor, a new promise is created. This will be used to
       * tell the user when the poller finishes (see `pollUntilDone()`). The promise's
       * resolve and reject methods are also used internally to control when to resolve
       * or reject anyone waiting for the poller to finish.
       *
       * The constructor of a custom implementation of a poller is where any serialized version of
       * a previous poller's operation should be deserialized into the operation sent to the
       * base constructor. For example:
       *
       * ```ts
       * export class MyPoller extends Poller<MyOperationState, string> {
       *   constructor(
       *     baseOperation: string | undefined
       *   ) {
       *     let state: MyOperationState = {};
       *     if (baseOperation) {
       *       state = {
       *         ...JSON.parse(baseOperation).state,
       *         ...state
       *       };
       *     }
       *     const operation = {
       *       state,
       *       // ...
       *     }
       *     super(operation);
       *   }
       * }
       * ```
       *
       * @param operation - Must contain the basic properties of `PollOperation<State, TResult>`.
       */
      function Poller(operation) {
          var _this = this;
          this.stopped = true;
          this.pollProgressCallbacks = [];
          this.operation = operation;
          this.promise = new Promise(function (resolve, reject) {
              _this.resolve = resolve;
              _this.reject = reject;
          });
          // This prevents the UnhandledPromiseRejectionWarning in node.js from being thrown.
          // The above warning would get thrown if `poller.poll` is called, it returns an error,
          // and pullUntilDone did not have a .catch or await try/catch on it's return value.
          this.promise.catch(function () {
              /* intentionally blank */
          });
      }
      /**
       * @internal
       * @hidden
       * Starts a loop that will break only if the poller is done
       * or if the poller is stopped.
       */
      Poller.prototype.startPolling = function () {
          return __awaiter(this, void 0, void 0, function () {
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          if (this.stopped) {
                              this.stopped = false;
                          }
                          _a.label = 1;
                      case 1:
                          if (!(!this.isStopped() && !this.isDone())) return [3 /*break*/, 4];
                          return [4 /*yield*/, this.poll()];
                      case 2:
                          _a.sent();
                          return [4 /*yield*/, this.delay()];
                      case 3:
                          _a.sent();
                          return [3 /*break*/, 1];
                      case 4: return [2 /*return*/];
                  }
              });
          });
      };
      /**
       * @internal
       * @hidden
       * pollOnce does one polling, by calling to the update method of the underlying
       * poll operation to make any relevant change effective.
       *
       * It only optionally receives an object with an abortSignal property, from \@azure/abort-controller's AbortSignalLike.
       *
       * @param options - Optional properties passed to the operation's update method.
       */
      Poller.prototype.pollOnce = function (options) {
          if (options === void 0) { options = {}; }
          return __awaiter(this, void 0, void 0, function () {
              var state, _a, e_1;
              return __generator(this, function (_b) {
                  switch (_b.label) {
                      case 0:
                          state = this.operation.state;
                          _b.label = 1;
                      case 1:
                          _b.trys.push([1, 4, , 5]);
                          if (!!this.isDone()) return [3 /*break*/, 3];
                          _a = this;
                          return [4 /*yield*/, this.operation.update({
                                  abortSignal: options.abortSignal,
                                  fireProgress: this.fireProgress.bind(this)
                              })];
                      case 2:
                          _a.operation = _b.sent();
                          if (this.isDone() && this.resolve) {
                              // If the poller has finished polling, this means we now have a result.
                              // However, it can be the case that TResult is instantiated to void, so
                              // we are not expecting a result anyway. To assert that we might not
                              // have a result eventually after finishing polling, we cast the result
                              // to TResult.
                              this.resolve(state.result);
                          }
                          _b.label = 3;
                      case 3: return [3 /*break*/, 5];
                      case 4:
                          e_1 = _b.sent();
                          state.error = e_1;
                          if (this.reject) {
                              this.reject(e_1);
                          }
                          throw e_1;
                      case 5: return [2 /*return*/];
                  }
              });
          });
      };
      /**
       * @internal
       * @hidden
       * fireProgress calls the functions passed in via onProgress the method of the poller.
       *
       * It loops over all of the callbacks received from onProgress, and executes them, sending them
       * the current operation state.
       *
       * @param state - The current operation state.
       */
      Poller.prototype.fireProgress = function (state) {
          for (var _i = 0, _a = this.pollProgressCallbacks; _i < _a.length; _i++) {
              var callback = _a[_i];
              callback(state);
          }
      };
      /**
       * @internal
       * @hidden
       * Invokes the underlying operation's cancel method, and rejects the
       * pollUntilDone promise.
       */
      Poller.prototype.cancelOnce = function (options) {
          if (options === void 0) { options = {}; }
          return __awaiter(this, void 0, void 0, function () {
              var _a;
              return __generator(this, function (_b) {
                  switch (_b.label) {
                      case 0:
                          _a = this;
                          return [4 /*yield*/, this.operation.cancel(options)];
                      case 1:
                          _a.operation = _b.sent();
                          if (this.reject) {
                              this.reject(new PollerCancelledError("Poller cancelled"));
                          }
                          return [2 /*return*/];
                  }
              });
          });
      };
      /**
       * Returns a promise that will resolve once a single polling request finishes.
       * It does this by calling the update method of the Poller's operation.
       *
       * It only optionally receives an object with an abortSignal property, from \@azure/abort-controller's AbortSignalLike.
       *
       * @param options - Optional properties passed to the operation's update method.
       */
      Poller.prototype.poll = function (options) {
          var _this = this;
          if (options === void 0) { options = {}; }
          if (!this.pollOncePromise) {
              this.pollOncePromise = this.pollOnce(options);
              var clearPollOncePromise = function () {
                  _this.pollOncePromise = undefined;
              };
              this.pollOncePromise.then(clearPollOncePromise, clearPollOncePromise).catch(this.reject);
          }
          return this.pollOncePromise;
      };
      /**
       * Returns a promise that will resolve once the underlying operation is completed.
       */
      Poller.prototype.pollUntilDone = function () {
          return __awaiter(this, void 0, void 0, function () {
              return __generator(this, function (_a) {
                  if (this.stopped) {
                      this.startPolling().catch(this.reject);
                  }
                  return [2 /*return*/, this.promise];
              });
          });
      };
      /**
       * Invokes the provided callback after each polling is completed,
       * sending the current state of the poller's operation.
       *
       * It returns a method that can be used to stop receiving updates on the given callback function.
       */
      Poller.prototype.onProgress = function (callback) {
          var _this = this;
          this.pollProgressCallbacks.push(callback);
          return function () {
              _this.pollProgressCallbacks = _this.pollProgressCallbacks.filter(function (c) { return c !== callback; });
          };
      };
      /**
       * Returns true if the poller has finished polling.
       */
      Poller.prototype.isDone = function () {
          var state = this.operation.state;
          return Boolean(state.isCompleted || state.isCancelled || state.error);
      };
      /**
       * Stops the poller from continuing to poll.
       */
      Poller.prototype.stopPolling = function () {
          if (!this.stopped) {
              this.stopped = true;
              if (this.reject) {
                  this.reject(new PollerStoppedError("This poller is already stopped"));
              }
          }
      };
      /**
       * Returns true if the poller is stopped.
       */
      Poller.prototype.isStopped = function () {
          return this.stopped;
      };
      /**
       * Attempts to cancel the underlying operation.
       *
       * It only optionally receives an object with an abortSignal property, from \@azure/abort-controller's AbortSignalLike.
       *
       * If it's called again before it finishes, it will throw an error.
       *
       * @param options - Optional properties passed to the operation's update method.
       */
      Poller.prototype.cancelOperation = function (options) {
          if (options === void 0) { options = {}; }
          if (!this.stopped) {
              this.stopped = true;
          }
          if (!this.cancelPromise) {
              this.cancelPromise = this.cancelOnce(options);
          }
          else if (options.abortSignal) {
              throw new Error("A cancel request is currently pending");
          }
          return this.cancelPromise;
      };
      /**
       * Returns the state of the operation.
       *
       * Even though TState will be the same type inside any of the methods of any extension of the Poller class,
       * implementations of the pollers can customize what's shared with the public by writing their own
       * version of the `getOperationState` method, and by defining two types, one representing the internal state of the poller
       * and a public type representing a safe to share subset of the properties of the internal state.
       * Their definition of getOperationState can then return their public type.
       *
       * Example:
       *
       * ```ts
       * // Let's say we have our poller's operation state defined as:
       * interface MyOperationState extends PollOperationState<ResultType> {
       *   privateProperty?: string;
       *   publicProperty?: string;
       * }
       *
       * // To allow us to have a true separation of public and private state, we have to define another interface:
       * interface PublicState extends PollOperationState<ResultType> {
       *   publicProperty?: string;
       * }
       *
       * // Then, we define our Poller as follows:
       * export class MyPoller extends Poller<MyOperationState, ResultType> {
       *   // ... More content is needed here ...
       *
       *   public getOperationState(): PublicState {
       *     const state: PublicState = this.operation.state;
       *     return {
       *       // Properties from PollOperationState<TResult>
       *       isStarted: state.isStarted,
       *       isCompleted: state.isCompleted,
       *       isCancelled: state.isCancelled,
       *       error: state.error,
       *       result: state.result,
       *
       *       // The only other property needed by PublicState.
       *       publicProperty: state.publicProperty
       *     }
       *   }
       * }
       * ```
       *
       * You can see this in the tests of this repository, go to the file:
       * `../test/utils/testPoller.ts`
       * and look for the getOperationState implementation.
       */
      Poller.prototype.getOperationState = function () {
          return this.operation.state;
      };
      /**
       * Returns the result value of the operation,
       * regardless of the state of the poller.
       * It can return undefined or an incomplete form of the final TResult value
       * depending on the implementation.
       */
      Poller.prototype.getResult = function () {
          var state = this.operation.state;
          return state.result;
      };
      /**
       * Returns a serialized version of the poller's operation
       * by invoking the operation's toString method.
       */
      Poller.prototype.toString = function () {
          return this.operation.toString();
      };
      return Poller;
  }());
  export { Poller };
  //# sourceMappingURL=poller.js.map