text: /**
   * @file Helper API object that wraps asynchronous calls to our data APIs.
   */
  import $ from 'jquery';
  import _ from 'lodash';
  import {stringifyQueryParams} from '../../utils';
  
  /**
   * Standard callback form for asynchronous operations, popularized by Node.
   * @typedef {function} NodeStyleCallback
   * @param {Error|null} error - null if the async operation was successful.
   * @param {*} result - return value for async operation.
   */
  
  /**
   * NodeStyleCallback with additional jquery XHR object in the success case.
   * @typedef {function} AjaxNodeStyleCallback
   * @param {Error|null} error - null if the async operation was successful.
   * @param {*} result - return value for async operation.
   * @param {jqXHR} [jqXHR] - jquery XHR object, if the request was successful.
   */
  
  /**
   * @name ClientApi
   */
  var base = {
    /**
     * Base URL for target API.
     * @type {string}
     */
    api_base_url: "/v3/channels",
  
    /**
     * Request all collections.
     * @param {NodeStyleCallback} callback - Expected result is an array of
     *        collection objects.
     */
    all: function (callback) {
      $.ajax({
        url: this.api_base_url,
        type: "get",
        dataType: "json"
      }).done(function (data, text) {
        callback(null, data);
      }).fail(function (request, status, error) {
        var err = new Error('status: ' + status + '; error: ' + error);
        callback(err, null);
      });
    },
  
    /**
     * Insert a collection.
     * @param {Object} value - collection contents, must be JSON.stringify-able.
     * @param {NodeStyleCallback} callback - Expected result is the created
     *        collection object (which will include an assigned 'id' key).
     * @param {Object} queryParams Object representing params to append to the
     *        url as a query string.
     */
    create: function (value, callback, queryParams) {
      $.ajax({
        url: this.api_base_url + stringifyQueryParams(queryParams),
        type: "post",
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify(value)
      }).done(function (data, text) {
        callback(null, data);
      }).fail(function (request, status, error) {
        var err = new Error('status: ' + status + '; error: ' + error);
        callback(err, undefined);
      });
    },
  
    /**
     * Remove a collection.
     * @param {string} childPath The path underneath api_base_url
     * @param {NodeStyleCallback} callback - Expected result is TRUE.
     */
    delete: function (childPath, callback) {
      $.ajax({
        url: this.api_base_url + "/" + childPath + "/delete",
        type: "post",
        dataType: "json"
      }).done(function (data, text) {
        callback(null, true);
      }).fail(function (request, status, error) {
        var err = new Error('status: ' + status + '; error: ' + error);
        callback(err, false);
      });
    },
  
    /**
     * Retrieve a collection.
     * @param {string} childPath The path underneath api_base_url
     * @param {AjaxNodeStyleCallback} callback - Expected result is the requested
     *        collection object.
     */
    fetch: function (childPath, callback) {
      $.ajax({
        url: this.api_base_url + "/" + childPath,
        type: "get",
        dataType: "json",
      }).done(function (data, textStatus, jqXHR) {
        callback(null, data, jqXHR);
      }).fail(function (request, status, error) {
        var err = new Error('status: ' + status + '; error: ' + error);
        callback(err, undefined);
      });
    },
  
    /**
     * Change the contents of a collection.
     * @param {string} childPath The path underneath api_base_url
     * @param {Object} value - The new collection contents.
     * @param {NodeStyleCallback} callback - Expected result is the new collection
     *        object.
     */
    update: function (childPath, value, callback) {
      $.ajax({
        url: this.api_base_url + "/" + childPath,
        type: "post",
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify(value)
      }).done(function (data, text) {
        callback(null, data);
      }).fail(function (request, status, error) {
        var err = new Error('status: ' + status + '; error: ' + error);
        callback(err, false);
      });
    },
  
    /**
     * Copy to the destination collection, since we expect the destination
     * to be empty. A true rest API would replace the destination collection:
     * @see https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services
     * @param {*} src - Source collection identifier.
     * @param {*} dest - Destination collection identifier.
     * @param {NodeStyleCallback} callback
     */
    copyAll: function (src, dest, callback) {
      $.ajax({
        url: this.api_base_url + "/" + dest + '?src=' + src,
        type: "put"
      }).done(function (data, text) {
        callback(null, data);
      }).fail(function (request, status, error) {
        var err = new Error('status: ' + status + '; error: ' + error);
        callback(err, false);
      });
    },
  
    /**
     * Replace the contents of an asset or source file.
     * @param {number} id - The collection identifier.
     * @param {String} value - The new file contents.
     * @param {String} filename - The name of the file to create or update.
     * @param {NodeStyleCallback} callback - Expected result is the new collection
     *        object.
     */
    put: function (id, value, filename, callback) {
      $.ajax({
        url: this.api_base_url + "/" + id + "/" + filename,
        type: "put",
        contentType: "application/json; charset=utf-8",
        data: value
      }).done(function (data, text) {
        callback(null, data);
      }).fail(function (request, status, error) {
        var err = errorString(request, status, error);
        callback(err, false);
      });
    },
  
    /**
     * Modify the contents of a collection
     * @param {number} id - The collection identifier.
     * @param {String} queryParams - Any query parameters
     * @param {String} value - The request body
     * @param {NodeStyleCallback} callback - Expected result is the new collection
     *        object.
     */
    patchAll: function (id, queryParams, value, callback) {
      $.ajax({
        url: this.api_base_url + "/" + id + "/?" + queryParams,
        type: "patch",
        contentType: "application/json; charset=utf-8",
        data: value
      }).done(function (data, text) {
        callback(null, data);
      }).fail(function (request, status, error) {
        var err = new Error('status: ' + status + '; error: ' + error);
        callback(err, false);
      });
    }
  };
  
  function errorString(request, status, error) {
    return new Error(`httpStatusCode: ${request.status}; status: ${status}; error: ${error}`);
  }
  
  module.exports = {
    /**
     * Create a ClientApi instance with the given base URL.
     * @param {!string} url - Custom API base url (e.g. '/v3/netsim')
     * @returns {ClientApi}
     */
    create: function (url) {
      return _.assign({}, base, {
        api_base_url: url
      });
    }
  };
  