"use strict";
define(function (require) {

/**
 * A class which appears to act like the Date class with customizable timezone
 * offsets.
 * @param {String} iso8601String An ISO-8601 date/time string including a
 *                               timezone offset.
 */
function MockDate(iso8601String) {
  // Find the timezone offset (Z or ±hhmm) from the ISO-8601 date string, and
  // then convert that into a number of minutes.
  let parse = /\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(Z|[+-]\d{4})/.exec(iso8601String);
  let tzOffsetStr = parse[1];
  if (tzOffsetStr == 'Z')
    this._tzOffset = 0;
  else {
    this._tzOffset = parseInt(tzOffsetStr.substring(1, 3)) * 60 +
      parseInt(tzOffsetStr.substring(3));
    if (tzOffsetStr[0] == '-')
      this._tzOffset = -this._tzOffset;
  }

  // To store the offset, we store both the real time in _realDate and a time
  // that is offset by the tzOffset in _shiftedDate. Only the getUTC* methods
  // should be used on these properties, to avoid problems caused by daylight
  // savings time or other timezone effects. This shifting is always legal
  // because ES6 is specified to assume that leap seconds do not exist, so there
  // are always 60 seconds in a minute.
  this._realDate = new Date(iso8601String);
  this._shiftedDate = new Date(this._realDate.getTime() +
    this._tzOffset * 60 * 1000);
}
MockDate.prototype = {
  getTimezoneOffset: function () {
    // This property is reversed from how it's defined in ISO 8601, i.e.,
    // UTC +0100 needs to return -60.
    return -this._tzOffset;
  },
  getTime: function () {
    return this._realDate.getTime();
  }
};

// Provide an implementation of Date methods that will be need in JSMime. For
// the time being, we only need .get* methods.
for (let name of Object.getOwnPropertyNames(Date.prototype)) {
  // Only copy getters, not setters or x.toString.
  if (!name.startsWith('get'))
    continue;
  // No redefining any other names on MockDate.
  if (MockDate.prototype.hasOwnProperty(name))
    continue;

  if (name.includes('UTC')) {
    // 'name' is already supposed to be freshly bound per newest ES6 drafts, but
    // current ES6 implementations reuse the bindings. Until implementations
    // catch up, use a new let to bind it freshly.
    let boundName = name;
    Object.defineProperty(MockDate.prototype, name, { value: function () {
      return Date.prototype[boundName].call(this._realDate, arguments);
    }});
  } else {
    let newName = 'getUTC' + name.substr(3);
    Object.defineProperty(MockDate.prototype, name, { value: function () {
      return Date.prototype[newName].call(this._shiftedDate, arguments);
    }});
  }
}

return MockDate;
});
