import “../core/array”; import “../core/document”; import “../core/identity”; import “../core/rebind”; import “../event/dispatch”;

d3.xhr = d3_xhrType(d3_identity);

function d3_xhrType(response) {

return function(url, mimeType, callback) {
  if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, mimeType = null;
  return d3_xhr(url, mimeType, response, callback);
};

}

function d3_xhr(url, mimeType, response, callback) {

var xhr = {},
    dispatch = d3.dispatch("progress", "load", "error"),
    headers = {},
    request = new XMLHttpRequest,
    responseType = null;

// If IE does not support CORS, use XDomainRequest.
if (d3_window.XDomainRequest
    && !("withCredentials" in request)
    && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest;

"onload" in request
    ? request.onload = request.onerror = respond
    : request.onreadystatechange = function() { request.readyState > 3 && respond(); };

function respond() {
  var status = request.status, result;
  if (!status && request.responseText || status >= 200 && status < 300 || status === 304) {
    try {
      result = response.call(xhr, request);
    } catch (e) {
      dispatch.error.call(xhr, e);
      return;
    }
    dispatch.load.call(xhr, result);
  } else {
    dispatch.error.call(xhr, request);
  }
}

request.onprogress = function(event) {
  var o = d3.event;
  d3.event = event;
  try { dispatch.progress.call(xhr, request); }
  finally { d3.event = o; }
};

xhr.header = function(name, value) {
  name = (name + "").toLowerCase();
  if (arguments.length < 2) return headers[name];
  if (value == null) delete headers[name];
  else headers[name] = value + "";
  return xhr;
};

// If mimeType is non-null and no Accept header is set, a default is used.
xhr.mimeType = function(value) {
  if (!arguments.length) return mimeType;
  mimeType = value == null ? null : value + "";
  return xhr;
};

// Specifies what type the response value should take;
// for instance, arraybuffer, blob, document, or text.
xhr.responseType = function(value) {
  if (!arguments.length) return responseType;
  responseType = value;
  return xhr;
};

// Specify how to convert the response content to a specific type;
// changes the callback value on "load" events.
xhr.response = function(value) {
  response = value;
  return xhr;
};

// Convenience methods.
["get", "post"].forEach(function(method) {
  xhr[method] = function() {
    return xhr.send.apply(xhr, [method].concat(d3_array(arguments)));
  };
});

// If callback is non-null, it will be used for error and load events.
xhr.send = function(method, data, callback) {
  if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
  request.open(method, url, true);
  if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
  if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
  if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
  if (responseType != null) request.responseType = responseType;
  if (callback != null) xhr.on("error", callback).on("load", function(request) { callback(null, request); });
  request.send(data == null ? null : data);
  return xhr;
};

xhr.abort = function() {
  request.abort();
  return xhr;
};

d3.rebind(xhr, dispatch, "on");

return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));

};

function d3_xhr_fixCallback(callback) {

return callback.length === 1
    ? function(error, request) { callback(error == null ? request : null); }
    : callback;

}