import 'moment';
import 'rsvp';
import { checkProtocol, hasArgs, hasNoArgs, isStringArg, isNumArg, defaultFetchInitObj, doFetchWithTimeout, JSON_MIME, isDef, stringify, TEXT_MIME } from './util.js';
import './stationxml.js';
import './seismogram.js';
import { SERVICE_NAME as SERVICE_NAME$1, DataSelectQuery } from './fdsndataselect.js';
import { SERVICE_NAME, AvailabilityQuery } from './fdsnavailability.js';
import { SERVICE_NAME as SERVICE_NAME$2, EventQuery } from './fdsnevent.js';
import { SERVICE_NAME as SERVICE_NAME$3, StationQuery } from './fdsnstation.js';

/*
 * Philip Crotwell
 * University of South Carolina, 2019
 * http://www.seis.sc.edu
 */
/** const for fdsn web service host, www.fdsn.org */

const FDSN_HOST = "www.fdsn.org";
/**
 * Query to a FDSN Data Centers Registry web service.
 * @see http://www.fdsn.org/webservices/
*/

class DataCentersQuery {
  /** @private */

  /** @private */

  /** @private */

  /** @private */

  /** @private */

  /** @private */

  /** @private */

  /** @private */

  /** @private */
  constructor(host) {
    this._specVersion = 1;
    this._protocol = checkProtocol();

    if (host) {
      this._host = host;
    } else {
      this._host = FDSN_HOST;
    }

    this._port = 80;
    this._timeoutSec = 30;
  }
  /** Gets/Sets the version of the fdsnws spec, 1 is currently the only value.
   *  Setting this is probably a bad idea as the code may not be compatible with
   *  the web service.
   *
   * @return the query when setting, the current value os services if no arguments
  */


  specVersion(value) {
    if (hasArgs(value)) {
      this._specVersion = value;
      return this;
    } else if (hasNoArgs(value)) {
      return this._specVersion;
    } else {
      throw new Error('value argument is optional or number, but was ' + typeof value);
    }
  }
  /** Gets/Sets the protocol, http or https. This should match the protocol
   *  of the page loaded, but is autocalculated and generally need not be set.
   *
   * @return the query when setting, the current value os services if no arguments
  */


  protocol(value) {
    if (isStringArg(value)) {
      this._protocol = value;
      return this;
    } else if (hasNoArgs(value)) {
      return this._protocol;
    } else {
      throw new Error('value argument is optional or string, but was ' + typeof value);
    }
  }
  /** Gets/Sets the remote host to connect to. This defaults to
   * www.fdsn.org and generally should not be set.
   *
   * @return the query when setting, the current value os services if no arguments
  */


  host(value) {
    if (isStringArg(value)) {
      this._host = value;
      return this;
    } else if (hasNoArgs(value)) {
      return this._host;
    } else {
      throw new Error('value argument is optional or string, but was ' + typeof value);
    }
  }
  /** Gets/Sets the remote port to connect to. This defaults to
   * the standard port for the protocol and generally should not be set.
   *
   * @return the query when setting, the current value os services if no arguments
  */


  port(value) {
    if (hasNoArgs(value)) {
      return this._port;
    } else if (hasArgs(value)) {
      this._port = value;
      return this;
    } else {
      throw new Error('value argument is optional or number, but was ' + typeof value);
    }
  }
  /**
   * limits results to the named data center, default is all data centers
   * @param   value names to search for
   * @return the query when setting, the current value os services if no arguments
   */


  name(value) {
    if (isStringArg(value)) {
      this._name = value;
      return this;
    } else if (hasNoArgs(value)) {
      return this._name;
    } else {
      throw new Error('value argument is optional or string, but was ' + value);
    }
  }
  /**
   * limits results to services that match the glob style pattern
   * @param  value glob style pattern to match against
   * @return the query when setting, the current value os services if no arguments
   */


  services(value) {
    if (isStringArg(value)) {
      this._services = value;
      return this;
    } else if (hasNoArgs(value)) {
      return this._services;
    } else {
      throw new Error('value argument is optional or string, but was ' + value);
    }
  }
  /**
   * whether the results include detailed information about
   * the data sets offered by each center, default is false
   * @param  value true to include datasets
   * @return the query when setting, the current value os services if no arguments
   */


  includeDataSets(value) {
    if (hasNoArgs(value)) {
      return this._includedatasets;
    } else if (hasArgs(value)) {
      this._includedatasets = value;
      return this;
    } else {
      throw new Error('value argument is optional or boolean, but was ' + typeof value);
    }
  }
  /** Get/Set the timeout in seconds for the request. Default is 30.
  * @param  value timeout seconds
  * @return the query when setting, the current value os services if no arguments
  */


  timeout(value) {
    if (hasNoArgs(value)) {
      return this._timeoutSec;
    } else if (isNumArg(value)) {
      this._timeoutSec = value;
      return this;
    } else {
      throw new Error('value argument is optional or number, but was ' + typeof value);
    }
  }
  /**
   * queries the fdsn registry web service, returning the result as a parsed json object.
   * @return Promise to the json object.
   */


  queryJson() {
    const url = this.formURL();
    const fetchInit = defaultFetchInitObj(JSON_MIME);
    return doFetchWithTimeout(url, fetchInit, this._timeoutSec * 1000).then(function (response) {
      let contentType = response.headers.get('content-type');

      if (contentType && contentType.includes(JSON_MIME)) {
        return response.json();
      } // $FlowFixMe


      throw new TypeError("Oops, we did not get JSON! ".concat(contentType));
    });
  }
  /**
   * queries the registry to find fdsn availability compatible web services within
   * a datacenter of the given name, optionally within the repository with
   * the repo name.
    * @param   name     datacenter name
    * @param   repoName optional repository name
    * @return           Promise to Array of fdsnavailability.AvailabilityQuery objects
    */


  findFdsnAvailability(name, repoName) {
    if (name && name.length > 0) {
      this.name(name);
    }

    this.services(SERVICE_NAME);
    return this.queryJson().then(json => {
      let out = this.extractCompatibleServices(json, SERVICE_NAME, repoName);
      return out.map(service => {
        let url = new URL(service.url);
        let q = new AvailabilityQuery(url.hostname);

        if (url.port && url.port.length > 0) {
          q.port(Number.parseInt(url.port));
        }

        return q;
      });
    });
  }
  /**
   * queries the registry to find fdsn dataselect compatible web services within
   * a datacenter of the given name, optionally within the repository with
   * the repo name.
    * @param   name     datacenter name
    * @param   repoName optional repository name
    * @return           Promise to Array of fdsndataselect.DataSelectQuery objects
    */


  findFdsnDataSelect(name, repoName) {
    if (name && name.length > 0) {
      this.name(name);
    }

    this.services(SERVICE_NAME$1);
    return this.queryJson().then(json => {
      let out = this.extractCompatibleServices(json, SERVICE_NAME$1, repoName);
      return out.map(service => {
        let url = new URL(service.url);
        let q = new DataSelectQuery(url.hostname);

        if (url.port && url.port.length > 0) {
          q.port(Number.parseInt(url.port));
        }

        return q;
      });
    });
  }
  /**
   * queries the registry to find a fdsn event compatible web services within
   * a datacenter of the given name, optionally within the repository with
   * the repo name.
    * @param   name     datacenter name
    * @param   repoName optional repository name
    * @return           Promise to Array of fdsnevent.EventQuery objects
    */


  findFdsnEvent(dcname, repoName) {
    if (dcname && dcname.length > 0) {
      this.name(dcname);
    }

    this.services(SERVICE_NAME$2);
    return this.queryJson().then(json => {
      let out = this.extractCompatibleServices(json, SERVICE_NAME$2, repoName);
      return out.map(service => {
        let url = new URL(service.url);
        let q = new EventQuery(url.hostname);

        if (url.port && url.port.length > 0) {
          q.port(Number.parseInt(url.port));
        }

        return q;
      });
    });
  }
  /**
   * queries the registry to find a fdsn station compatible web services within
   * a datacenter of the given name, optionally within the repository with
   * the repo name.
    * @param   name     datacenter name
    * @param   repoName optional repository name
    * @return           Promise to Array of fdsnstation.StationQuery objects
    */


  findFdsnStation(dcname, repoName) {
    if (dcname && dcname.length > 0) {
      this.name(dcname);
    }

    this.services(SERVICE_NAME$3);
    return this.queryJson().then(json => {
      let out = this.extractCompatibleServices(json, SERVICE_NAME$3, repoName);
      return out.map(service => {
        let url = new URL(service.url);
        let q = new StationQuery(url.hostname);

        if (url.port && url.port.length > 0) {
          q.port(Number.parseInt(url.port));
        }

        return q;
      });
    });
  }

  extractCompatibleServices(json, compatibleName, repoName) {
    let out = [];
    json.datacenters.forEach(dc => {
      dc.repositories.forEach(repo => {
        if (!isDef(repoName) || repoName === repo.name) {
          repo.services.forEach(service => {
            if (service.name === compatibleName || isDef(service.compatibleWith) && service.compatibleWith.includes(compatibleName)) {
              out.push(service);
            }
          });
        }
      });
    });
    return out;
  }

  formBaseURL() {
    let colon = ":";

    if (this._protocol.endsWith(colon)) {
      colon = "";
    }

    return this._protocol + colon + "//" + this._host + (this._port === 80 ? "" : ":" + this._port) + "/ws/datacenters/" + this._specVersion;
  }

  formVersionURL() {
    return this.formBaseURL() + "/version";
  }
  /** Queries the remote web service to get its version
   * @return Promise to version string
  */


  queryVersion() {
    let url = this.formVersionURL();
    const fetchInit = defaultFetchInitObj(TEXT_MIME);
    return doFetchWithTimeout(url, fetchInit, this._timeoutSec * 1000).then(response => {
      if (response.status === 200) {
        return response.text();
      } else {
        throw new Error("Status not 200: ".concat(response.status));
      }
    });
  }

  makeParam(name, val) {
    return name + "=" + encodeURIComponent(stringify(val)) + "&";
  }
  /**
   * forms a url to the fdsn registry based on the configured parameters.
   * @return the url
   */


  formURL() {
    const method = "query";
    let url = this.formBaseURL() + "/".concat(method, "?");

    if (this._name) {
      url = url + this.makeParam("name", this.name());
    }

    if (this._services) {
      url = url + this.makeParam("services", this.services());
    }

    if (this._includedatasets) {
      url = url + this.makeParam("includedatasets", this.includeDataSets());
    }

    if (url.endsWith('&') || url.endsWith('?')) {
      url = url.substr(0, url.length - 1); // zap last & or ?
    }

    return url;
  }

}

export { DataCentersQuery, FDSN_HOST };
//# sourceMappingURL=fdsndatacenters.js.map
