import moment from 'moment';
export { default as moment } from 'moment';
import { select } from 'd3';
import RSVP__default from 'rsvp';
export { default as RSVP } from 'rsvp';

/*
 * Philip Crotwell
 * University of South Carolina, 2019
 * http://www.seis.sc.edu
 */
RSVP__default.on('error', function (reason) {
  // eslint-disable-next-line no-console
  console.assert(false, reason);
}); //reexport
const XML_MIME = "application/xml";
const JSON_MIME = "application/json";
const TEXT_MIME = "text/plain"; // flow predicate %check functions

function hasArgs(value) {
  return arguments.length !== 0 && typeof value !== 'undefined';
}
function hasNoArgs(value) {
  return arguments.length === 0 || typeof value === 'undefined';
}
function isStringArg(value) {
  return arguments.length !== 0 && typeof value === 'string';
}
function isNumArg(value) {
  return typeof value === 'number';
}
function isObject(obj) {
  return obj !== null && typeof obj === 'object';
}
function isDef(v) {
  return typeof v !== 'undefined' && v !== null;
}
function dataViewToString(dataView) {
  let out = "";

  for (let i = 0; i < dataView.byteLength; i++) {
    out += String.fromCharCode(dataView.getUint8(i));
  }

  return out;
}
function log(msg) {
  // eslint-disable-next-line no-console
  if (console) {
    console.log("".concat(stringify(msg)));
  }

  select("div#debug").append("p").text("".concat(stringify(msg)));
}
/** String representation of input. THis is kind of dumb but makes
 *  flow happier.
 */

function stringify(value) {
  if (typeof value === 'string') {
    return value;
  } else if (typeof value === 'number') {
    return value.toString();
  } else if (typeof value === 'boolean') {
    return value ? "true" : "false";
  } else if (typeof value === 'undefined') {
    return "undefined";
  } else if (typeof value === 'function') {
    return "function " + value.name;
  } else if (typeof value === 'object') {
    if (value) {
      if (value instanceof moment) {
        return value.toISOString();
      } else {
        return value.constructor.name + " " + value.toString();
      }
    } else {
      return "null";
    } // symbol not yet supported by flow
    //  } else if (typeof value === 'symbol') {
    //    return value.toString();

  } else {
    return "<unknown" + typeof value + "???>";
  }
}
function calcClockOffset(serverTimeUTC) {
  return moment.utc().diff(serverTimeUTC, 'seconds', true);
}
/**
Any two of startTime, endTime and duration can be specified, or just duration which
then assumes endTime is now.
startTime and endTime are moment objects, duration is in seconds.
clockOffset is the seconds that should be subtracted from the computer time
 to get real world time, ie computerUTC - UTC
 or moment.utc().diff(serverTimeUTC, 'seconds', true).
 default is zero.
*/

class StartEndDuration {
  constructor(startTime, endTime, duration = null, clockOffset = 0) {
    if (duration) {
      if (typeof duration === "string" || duration instanceof String) {
        if (duration.charAt(0) === 'P') {
          this._duration = moment.duration(duration);
        } else {
          this._duration = moment.duration(Number.parseFloat(duration), 'seconds');
        }
      } else if (typeof duration === "number" || duration instanceof Number) {
        this._duration = moment.duration(duration, 'seconds');
      } else if (moment.isDuration(duration)) {
        this._duration = moment.duration(duration);
      } else {
        throw new Error("Unknown type for duration: ".concat(typeof duration, "  ").concat(JSON.stringify(duration)));
      }
    }

    if (startTime && endTime) {
      this._startTime = checkStringOrDate(startTime);
      this._endTime = checkStringOrDate(endTime);
      this._duration = moment.duration(this.endTime.diff(this.startTime));
    } else if (startTime && this._duration) {
      this._startTime = checkStringOrDate(startTime);
      this._endTime = moment.utc(this.startTime).add(this.duration);
    } else if (endTime && this._duration) {
      this._endTime = checkStringOrDate(endTime);
      this._startTime = moment.utc(this.endTime).subtract(this.duration);
    } else if (this._duration) {
      if (clockOffset === undefined) {
        this._clockOffset = moment.duration(0, 'seconds');
      } else if (clockOffset instanceof Number) {
        this._clockOffset = moment.duration(clockOffset, 'seconds');
      } else {
        this._clockOffset = clockOffset;
      }

      this._endTime = moment.utc().subtract(clockOffset);
      this._startTime = moment.utc(this.endTime).subtract(this.duration);
    } else {
      throw "need some combination of startTime, endTime and duration";
    }
  }

  get start() {
    return this._startTime;
  }

  get startTime() {
    return this._startTime;
  }

  get end() {
    return this._endTime;
  }

  get endTime() {
    return this._endTime;
  }

  get duration() {
    return this._duration;
  }

  get clockOffset() {
    return this._clockOffset;
  }

  contains(other) {
    if (this.startTime.isAfter(other) || this.endTime.isBefore(other)) {
      return false;
    }

    return true;
  }

  overlaps(other) {
    if (this.startTime.isAfter(other.endTime) || this.endTime.isBefore(other.startTime)) {
      return false;
    }

    return true;
  }

  toString() {
    return "StartEndDuration: ".concat(toIsoWoZ(this.startTime), " to ").concat(toIsoWoZ(this.endTime), " ").concat(this.duration);
  }

}
/** converts the input value is a moment, throws Error if not
 * a string, Date or moment. Zero length string or "now" return
 * current time.
 */

function checkStringOrDate(d) {
  if (moment.isMoment(d)) {
    return d;
  } else if (d instanceof Date) {
    return moment.utc(d);
  } else if (d instanceof Number || typeof d === "number") {
    return moment.utc(d);
  } else if (d instanceof String || typeof d === "string") {
    let lc = d.toLowerCase();

    if (d.length === 0 || lc === "now") {
      return moment.utc();
    } else {
      return moment.utc(d);
    }
  }

  throw new Error("unknown date type: " + d + " " + typeof d);
}
/** converts to ISO8601 but removes the trailing Z as FDSN web services
  do not allow that. */

function toIsoWoZ(date) {
  let out = date.toISOString();
  return out.substring(0, out.length - 1);
}
/** returns the protocol, http or https for the document if possible. */

function checkProtocol() {
  let _protocol = 'http:';

  if (typeof document !== 'undefined' && document.location && "https:" === document.location.protocol) {
    _protocol = 'https:';
  }

  return _protocol;
}
function defaultFetchInitObj(mimeType) {
  let headers = {};

  if (isStringArg(mimeType)) {
    headers.Accept = mimeType;
  }

  return {
    cache: 'no-cache',
    redirect: 'follow',
    // manual, *follow, error
    mode: "cors",
    referrer: "seisplotjs",
    headers: headers
  };
}
function doFetchWithTimeout(url, fetchInit, timeoutSec) {
  const controller = new AbortController();
  const signal = controller.signal;
  setTimeout(() => controller.abort(), timeoutSec * 1000);
  fetchInit.signal = signal;
  return fetch(url, fetchInit).catch(err => {
    log("fetch failed, possible CORS or PrivacyBadger or NoScript?");
    throw err;
  }).then(function (response) {
    if (response.ok) {
      return response;
    } // $FlowFixMe


    throw new Error("fetch response was not ok. ".concat(response.ok, " ").concat(response.status));
  });
}
/**
 * Recursively calculates the mean of a slice of an array. This helps with
 * very long seismograms to equally weight each sample point without overflowing.
 * @param   dataSlice slice of a seismogram
 * @param   totalPts  number of points in the original seismogram
 * @return            sum of slice data points divided by totalPts
 */

function meanOfSlice(dataSlice, totalPts) {
  if (dataSlice.length < 8) {
    return dataSlice.reduce(function (acc, val) {
      return acc + val;
    }, 0) / totalPts;
  } else {
    let byTwo = Math.floor(dataSlice.length / 2);
    return meanOfSlice(dataSlice.slice(0, byTwo), totalPts) + meanOfSlice(dataSlice.slice(byTwo, dataSlice.length), totalPts);
  }
}

export { JSON_MIME, StartEndDuration, TEXT_MIME, XML_MIME, calcClockOffset, checkProtocol, checkStringOrDate, dataViewToString, defaultFetchInitObj, doFetchWithTimeout, hasArgs, hasNoArgs, isDef, isNumArg, isObject, isStringArg, log, meanOfSlice, stringify, toIsoWoZ };
//# sourceMappingURL=util.js.map
