(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = global || self, global.i18nextXHRBackend = factory());
}(this, (function () { 'use strict';

  function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
      throw new TypeError("Cannot call a class as a function");
    }
  }

  function _defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
  }

  function _defineProperty(obj, key, value) {
    if (key in obj) {
      Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
      });
    } else {
      obj[key] = value;
    }

    return obj;
  }

  var arr = [];
  var each = arr.forEach;
  var slice = arr.slice;
  function defaults(obj) {
    each.call(slice.call(arguments, 1), function (source) {
      if (source) {
        for (var prop in source) {
          if (obj[prop] === undefined) obj[prop] = source[prop];
        }
      }
    });
    return obj;
  }

  function _typeof2(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof2(obj); }

  function _typeof(obj) {
    if (typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol") {
      _typeof = function _typeof(obj) {
        return _typeof2(obj);
      };
    } else {
      _typeof = function _typeof(obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : _typeof2(obj);
      };
    }

    return _typeof(obj);
  }

  function addQueryString(url, params) {
    if (params && _typeof(params) === 'object') {
      var queryString = '',
          e = encodeURIComponent; // Must encode data

      for (var paramName in params) {
        queryString += '&' + e(paramName) + '=' + e(params[paramName]);
      }

      if (!queryString) {
        return url;
      }

      url = url + (url.indexOf('?') !== -1 ? '&' : '?') + queryString.slice(1);
    }

    return url;
  } // https://gist.github.com/Xeoncross/7663273


  function ajax(url, options, callback, data, cache) {
    if (data && _typeof(data) === 'object') {
      if (!cache) {
        data['_t'] = new Date();
      } // URL encoded form data must be in querystring format


      data = addQueryString('', data).slice(1);
    }

    if (options.queryStringParams) {
      url = addQueryString(url, options.queryStringParams);
    }

    try {
      var x;

      if (XMLHttpRequest) {
        x = new XMLHttpRequest();
      } else {
        x = new ActiveXObject('MSXML2.XMLHTTP.3.0');
      }

      x.open(data ? 'POST' : 'GET', url, 1);

      if (!options.crossDomain) {
        x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
      }

      x.withCredentials = !!options.withCredentials;

      if (data) {
        x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
      }

      if (x.overrideMimeType) {
        x.overrideMimeType("application/json");
      }

      var h = options.customHeaders;
      h = typeof h === 'function' ? h() : h;

      if (h) {
        for (var i in h) {
          x.setRequestHeader(i, h[i]);
        }
      }

      x.onreadystatechange = function () {
        x.readyState > 3 && callback && callback(x.responseText, x);
      };

      x.send(data);
    } catch (e) {
      console && console.log(e);
    }
  }

  function getDefaults() {
    return {
      loadPath: '/locales/{{lng}}/{{ns}}.json',
      addPath: '/locales/add/{{lng}}/{{ns}}',
      allowMultiLoading: false,
      parse: JSON.parse,
      parsePayload: function parsePayload(namespace, key, fallbackValue) {
        return _defineProperty({}, key, fallbackValue || '');
      },
      crossDomain: false,
      ajax: ajax
    };
  }

  var Backend =
  /*#__PURE__*/
  function () {
    function Backend(services) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      _classCallCheck(this, Backend);

      this.init(services, options);
      this.type = 'backend';
    }

    _createClass(Backend, [{
      key: "init",
      value: function init(services) {
        var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
        this.services = services;
        this.options = defaults(options, this.options || {}, getDefaults());
      }
    }, {
      key: "readMulti",
      value: function readMulti(languages, namespaces, callback) {
        var loadPath = this.options.loadPath;

        if (typeof this.options.loadPath === 'function') {
          loadPath = this.options.loadPath(languages, namespaces);
        }

        var url = this.services.interpolator.interpolate(loadPath, {
          lng: languages.join('+'),
          ns: namespaces.join('+')
        });
        this.loadUrl(url, callback);
      }
    }, {
      key: "read",
      value: function read(language, namespace, callback) {
        var loadPath = this.options.loadPath;

        if (typeof this.options.loadPath === 'function') {
          loadPath = this.options.loadPath([language], [namespace]);
        }

        var url = this.services.interpolator.interpolate(loadPath, {
          lng: language,
          ns: namespace
        });
        this.loadUrl(url, callback);
      }
    }, {
      key: "loadUrl",
      value: function loadUrl(url, callback) {
        var _this = this;

        this.options.ajax(url, this.options, function (data, xhr) {
          if (xhr.status >= 500 && xhr.status < 600) return callback('failed loading ' + url, true
          /* retry */
          );
          if (xhr.status >= 400 && xhr.status < 500) return callback('failed loading ' + url, false
          /* no retry */
          );
          var ret, err;

          try {
            ret = _this.options.parse(data, url);
          } catch (e) {
            err = 'failed parsing ' + url + ' to json';
          }

          if (err) return callback(err, false);
          callback(null, ret);
        });
      }
    }, {
      key: "create",
      value: function create(languages, namespace, key, fallbackValue) {
        var _this2 = this;

        if (typeof languages === 'string') languages = [languages];
        var payload = this.options.parsePayload(namespace, key, fallbackValue);
        languages.forEach(function (lng) {
          var url = _this2.services.interpolator.interpolate(_this2.options.addPath, {
            lng: lng,
            ns: namespace
          });

          _this2.options.ajax(url, _this2.options, function (data, xhr) {//const statusCode = xhr.status.toString();
            // TODO: if statusCode === 4xx do log
          }, payload);
        });
      }
    }]);

    return Backend;
  }();

  Backend.type = 'backend';

  return Backend;

})));
