text: /*!
   * Copyright 2015 Google Inc. All Rights Reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  'use strict';
  
  const common = require('@google-cloud/common');
  const {promisifyAll} = require('@google-cloud/promisify');
  
  /**
   * An Operation object allows you to interact with a Google Compute Engine
   * operation.
   *
   * An operation can be a
   * [GlobalOperation](https://cloud.google.com/compute/docs/reference/v1/globalOperations),
   * [RegionOperation](https://cloud.google.com/compute/docs/reference/v1/regionOperations),
   * or
   * [ZoneOperation](https://cloud.google.com/compute/docs/reference/v1/zoneOperations).
   *
   * @class
   * @param {Compute|Zone|Region} scope The scope of the operation: a `Compute`,
   *     `Zone`, or `Region` object.
   * @param {string} name Operation name.
   *
   * @example
   * const Compute = require('@google-cloud/compute');
   * const compute = new Compute();
   *
   * //-
   * // Reference a global operation.
   * //-
   * const operation = compute.operation('operation-id');
   *
   * //-
   * // Reference a region operation.
   * //-
   * const region = compute.region('us-central1');
   * const operation = region.operation('operation-id');
   *
   * //-
   * // Reference a zone operation.
   * //-
   * const zone = compute.zone('us-central1-a');
   * const operation = zone.operation('operation-id');
   *
   * //-
   * // All operations are event emitters. The status of each operation is polled
   * // continuously, starting only after you register a "complete" listener.
   * //-
   * operation.on('complete', function(metadata) {
   *   // The operation is complete.
   * });
   *
   * //-
   * // You can register a listener to monitor when the operation begins running.
   * //-
   * operation.on('running', function(metadata) {
   *   // The operation is running.
   * });
   *
   * //-
   * // Be sure to register an error handler as well to catch any issues which
   * // impeded the operation.
   * //-
   * operation.on('error', function(err) {
   *   // An error occurred during the operation.
   * });
   *
   * //-
   * // To force the Operation object to stop polling for updates, simply remove
   * // any "complete" listeners you've registered.
   * //
   * // The easiest way to do this is with `removeAllListeners()`.
   * //-
   * operation.removeAllListeners();
   */
  class Operation extends common.Operation {
    constructor(scope, name) {
      const isCompute = scope.constructor.name === 'Compute';
      const methods = {
        /**
         * Delete the operation.
         *
         * @see [GlobalOperations: delete API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/globalOperations/delete}
         * @see [RegionOperations: delete API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/regionOperations/delete}
         * @see [ZoneOperations: delete API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/zoneOperations/delete}
         *
         * @method Operation#delete
         * @param {function=} callback - The callback function.
         * @param {?error} callback.err - An error returned while making this
         *     request.
         * @param {object} callback.apiResponse - The full API response.
         *
         * @example
         * const Compute = require('@google-cloud/compute');
         * const compute = new Compute();
         * const operation = compute.operation('operation-id');
         *
         * operation.delete(function(err, apiResponse) {});
         *
         * //-
         * // If the callback is omitted, we'll return a Promise.
         * //-
         * operation.delete().then(function(data) {
         *   var apiResponse = data[0];
         * });
         */
        delete: true,
        /**
         * Check if the operation exists.
         *
         * @method Operation#exists
         * @param {function} callback - The callback function.
         * @param {?error} callback.err - An error returned while making this
         *     request.
         * @param {boolean} callback.exists - Whether the operation exists or not.
         *
         * @example
         * const Compute = require('@google-cloud/compute');
         * const compute = new Compute();
         * const operation = compute.operation('operation-id');
         *
         * operation.exists(function(err, exists) {});
         *
         * //-
         * // If the callback is omitted, we'll return a Promise.
         * //-
         * operation.exists().then(function(data) {
         *   var exists = data[0];
         * });
         */
        exists: true,
        /**
         * Get an operation if it exists.
         *
         * @method Operation#get
         * @example
         * const Compute = require('@google-cloud/compute');
         * const compute = new Compute();
         * const operation = compute.operation('operation-id');
         *
         * operation.get(function(err, operation, apiResponse) {
         *   // `operation` is an Operation object.
         * });
         *
         * //-
         * // If the callback is omitted, we'll return a Promise.
         * //-
         * operation.get().then(function(data) {
         *   var operation = data[0];
         *   var apiResponse = data[1];
         * });
         */
        get: true,
      };
      super({
        parent: scope,
        baseUrl: isCompute ? '/global/operations' : '/operations',
        /**
         * @name Operation#id
         * @type {string}
         */
        id: name,
        methods: methods,
        pollIntervalMs: isCompute
          ? scope.pollIntervalMs
          : scope.compute.pollIntervalMs,
      });
  
      /**
       * @name Operation#name
       * @type {string}
       */
      this.name = name;
    }
    /**
     * Get the operation's metadata. For a detailed description of metadata see
     * [Operation resource](https://goo.gl/sWm1rt).
     *
     * @see [GlobalOperations: get API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/globalOperations/get}
     * @see [RegionOperations: get API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/regionOperations/get}
     * @see [ZoneOperations: get API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/zoneOperations/get}
     *
     * @param {function=} callback - The callback function.
     * @param {?error} callback.err - An error returned while making this request
     * @param {object} callback.metadata - The disk's metadata.
     * @param {object} callback.apiResponse - The full API response.
     *
     * @example
     * const Compute = require('@google-cloud/compute');
     * const compute = new Compute();
     *
     * operation.getMetadata(function(err, metadata, apiResponse) {
     *   // `metadata.error`: Contains errors if the operation failed.
     *   // `metadata.warnings`: Contains warnings.
     * });
     *
     * //-
     * // If the callback is omitted, we'll return a Promise.
     * //-
     * operation.getMetadata().then(function(data) {
     *   const metadata = data[0];
     *   const apiResponse = data[1];
     * });
     */
    getMetadata(callback) {
      const self = this;
      callback = callback || common.util.noop;
      super.getMetadata((err, apiResponse) => {
        // An Operation entity contains a property named `error`. This makes
        // `request` think the operation failed, and will return an ApiError to
        // this callback. We have to make sure this isn't a false error by seeing if
        // the response body contains a property that wouldn't exist on a failed API
        // request (`name`).
        const requestFailed =
          err && (!apiResponse || apiResponse.name !== self.name);
        if (requestFailed) {
          callback(err, null, apiResponse);
          return;
        }
        self.metadata = apiResponse;
        callback(null, self.metadata, apiResponse);
      });
    }
    /**
     * Poll `getMetadata` to check the operation's status. This runs a loop to ping
     * the API on an interval.
     *
     * Note: This method is automatically called once a "complete" event handler is
     * registered on the operation.
     *
     * @private
     */
    poll_(callback) {
      const self = this;
      this.getMetadata(function(err, metadata, apiResponse) {
        // Parsing the response body will automatically create an ApiError object if
        // the operation failed.
        const parsedHttpRespBody = common.util.parseHttpRespBody(apiResponse);
        err = err || parsedHttpRespBody.err;
        if (err) {
          callback(err);
          return;
        }
        if (metadata.status === 'RUNNING' && !self.status) {
          self.status = metadata.status;
          self.emit('running', metadata);
        }
        if (metadata.status !== 'DONE') {
          callback();
          return;
        }
        self.status = metadata.status;
        callback(null, metadata);
      });
    }
  }
  
  /*! Developer Documentation
   *
   * All async methods (except for streams) will return a Promise in the event
   * that a callback is omitted.
   */
  promisifyAll(Operation);
  
  /**
   * Reference to the {@link Operation} class.
   * @name module:@google-cloud/compute.Operation
   * @see Operation
   */
  module.exports = Operation;
  