text: "use strict";
  // Copyright (c) Microsoft. All rights reserved.
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
      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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
          step((generator = generator.apply(thisArg, _arguments || [])).next());
      });
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  const httpm = require("./HttpClient");
  const util = require("./Util");
  class RestClient {
      /**
       * Creates an instance of the RestClient
       * @constructor
       * @param {string} userAgent - userAgent for requests
       * @param {string} baseUrl - (Optional) If not specified, use full urls per request.  If supplied and a function passes a relative url, it will be appended to this
       * @param {ifm.IRequestHandler[]} handlers - handlers are typically auth handlers (basic, bearer, ntlm supplied)
       * @param {ifm.IRequestOptions} requestOptions - options for each http requests (http proxy setting, socket timeout)
       */
      constructor(userAgent, baseUrl, handlers, requestOptions) {
          this.client = new httpm.HttpClient(userAgent, handlers, requestOptions);
          if (baseUrl) {
              this._baseUrl = baseUrl;
          }
      }
      /**
       * Gets a resource from an endpoint
       * Be aware that not found returns a null.  Other error conditions reject the promise
       * @param {string} requestUrl - fully qualified or relative url
       * @param {IRequestOptions} requestOptions - (optional) requestOptions object
       */
      options(requestUrl, options) {
          return __awaiter(this, void 0, void 0, function* () {
              let url = util.getUrl(requestUrl, this._baseUrl);
              let res = yield this.client.options(url, this._headersFromOptions(options));
              return this._processResponse(res, options);
          });
      }
      /**
       * Gets a resource from an endpoint
       * Be aware that not found returns a null.  Other error conditions reject the promise
       * @param {string} resource - fully qualified url or relative path
       * @param {IRequestOptions} requestOptions - (optional) requestOptions object
       */
      get(resource, options) {
          return __awaiter(this, void 0, void 0, function* () {
              let url = util.getUrl(resource, this._baseUrl, (options || {}).queryParameters);
              let res = yield this.client.get(url, this._headersFromOptions(options));
              return this._processResponse(res, options);
          });
      }
      /**
       * Deletes a resource from an endpoint
       * Be aware that not found returns a null.  Other error conditions reject the promise
       * @param {string} resource - fully qualified or relative url
       * @param {IRequestOptions} requestOptions - (optional) requestOptions object
       */
      del(resource, options) {
          return __awaiter(this, void 0, void 0, function* () {
              let url = util.getUrl(resource, this._baseUrl);
              let res = yield this.client.del(url, this._headersFromOptions(options));
              return this._processResponse(res, options);
          });
      }
      /**
       * Creates resource(s) from an endpoint
       * T type of object returned.
       * Be aware that not found returns a null.  Other error conditions reject the promise
       * @param {string} resource - fully qualified or relative url
       * @param {IRequestOptions} requestOptions - (optional) requestOptions object
       */
      create(resource, resources, options) {
          return __awaiter(this, void 0, void 0, function* () {
              let url = util.getUrl(resource, this._baseUrl);
              let headers = this._headersFromOptions(options, true);
              let data = JSON.stringify(resources, null, 2);
              let res = yield this.client.post(url, data, headers);
              return this._processResponse(res, options);
          });
      }
      /**
       * Updates resource(s) from an endpoint
       * T type of object returned.
       * Be aware that not found returns a null.  Other error conditions reject the promise
       * @param {string} resource - fully qualified or relative url
       * @param {IRequestOptions} requestOptions - (optional) requestOptions object
       */
      update(resource, resources, options) {
          return __awaiter(this, void 0, void 0, function* () {
              let url = util.getUrl(resource, this._baseUrl);
              let headers = this._headersFromOptions(options, true);
              let data = JSON.stringify(resources, null, 2);
              let res = yield this.client.patch(url, data, headers);
              return this._processResponse(res, options);
          });
      }
      /**
       * Replaces resource(s) from an endpoint
       * T type of object returned.
       * Be aware that not found returns a null.  Other error conditions reject the promise
       * @param {string} resource - fully qualified or relative url
       * @param {IRequestOptions} requestOptions - (optional) requestOptions object
       */
      replace(resource, resources, options) {
          return __awaiter(this, void 0, void 0, function* () {
              let url = util.getUrl(resource, this._baseUrl);
              let headers = this._headersFromOptions(options, true);
              let data = JSON.stringify(resources, null, 2);
              let res = yield this.client.put(url, data, headers);
              return this._processResponse(res, options);
          });
      }
      uploadStream(verb, requestUrl, stream, options) {
          return __awaiter(this, void 0, void 0, function* () {
              let url = util.getUrl(requestUrl, this._baseUrl);
              let headers = this._headersFromOptions(options, true);
              let res = yield this.client.sendStream(verb, url, stream, headers);
              return this._processResponse(res, options);
          });
      }
      _headersFromOptions(options, contentType) {
          options = options || {};
          let headers = options.additionalHeaders || {};
          headers["Accept"] = options.acceptHeader || "application/json";
          if (contentType) {
              let found = false;
              for (let header in headers) {
                  if (header.toLowerCase() == "content-type") {
                      found = true;
                  }
              }
              if (!found) {
                  headers["Content-Type"] = 'application/json; charset=utf-8';
              }
          }
          return headers;
      }
      static dateTimeDeserializer(key, value) {
          if (typeof value === 'string') {
              let a = new Date(value);
              if (!isNaN(a.valueOf())) {
                  return a;
              }
          }
          return value;
      }
      _processResponse(res, options) {
          return __awaiter(this, void 0, void 0, function* () {
              return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
                  const statusCode = res.message.statusCode;
                  const response = {
                      statusCode: statusCode,
                      result: null,
                      headers: {}
                  };
                  // not found leads to null obj returned
                  if (statusCode == httpm.HttpCodes.NotFound) {
                      resolve(response);
                  }
                  let obj;
                  let contents;
                  // get the result from the body
                  try {
                      contents = yield res.readBody();
                      if (contents && contents.length > 0) {
                          if (options && options.deserializeDates) {
                              obj = JSON.parse(contents, RestClient.dateTimeDeserializer);
                          }
                          else {
                              obj = JSON.parse(contents);
                          }
                          if (options && options.responseProcessor) {
                              response.result = options.responseProcessor(obj);
                          }
                          else {
                              response.result = obj;
                          }
                      }
                      response.headers = res.message.headers;
                  }
                  catch (err) {
                      // Invalid resource (contents not json);  leaving result obj null
                  }
                  // note that 3xx redirects are handled by the http layer.
                  if (statusCode > 299) {
                      let msg;
                      // if exception/error in body, attempt to get better error
                      if (obj && obj.message) {
                          msg = obj.message;
                      }
                      else if (contents && contents.length > 0) {
                          // it may be the case that the exception is in the body message as string
                          msg = contents;
                      }
                      else {
                          msg = "Failed request: (" + statusCode + ")";
                      }
                      let err = new Error(msg);
                      // attach statusCode and body obj (if available) to the error object
                      err['statusCode'] = statusCode;
                      if (response.result) {
                          err['result'] = response.result;
                      }
                      reject(err);
                  }
                  else {
                      resolve(response);
                  }
              }));
          });
      }
  }
  exports.RestClient = RestClient;
  