"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

exports.default = function (realm) {
  let func = new _index.NativeFunctionValue(realm, "Array", "Array", 1, (context, [...items], argCount, NewTarget) => {
    if (argCount === 0) {
      // 1. Let numberOfArgs be the number of arguments passed to this function call.
      let numberOfArgs = argCount;

      // 2. Assert: numberOfArgs = 0.
      (0, _invariant2.default)(numberOfArgs === 0, "numberOfArgs = 0");

      // 3. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
      let newTarget = NewTarget === undefined ? func : NewTarget;

      // 4. Let proto be ? GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%").
      let proto = (0, _index2.GetPrototypeFromConstructor)(realm, newTarget, "ArrayPrototype");

      // 5. Return ArrayCreate(0, proto).
      return _singletons.Create.ArrayCreate(realm, 0, proto);
    } else if (argCount === 1) {
      // 1. Let numberOfArgs be the number of arguments passed to this function call.
      let numberOfArgs = argCount;

      // 2. Assert: numberOfArgs = 1.
      (0, _invariant2.default)(numberOfArgs === 1, "numberOfArgs = 1");

      // 3. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
      let newTarget = NewTarget === undefined ? func : NewTarget;

      // 4. Let proto be ? GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%").
      let proto = (0, _index2.GetPrototypeFromConstructor)(realm, newTarget, "ArrayPrototype");

      // 5. Let array be ArrayCreate(0, proto).
      let array = _singletons.Create.ArrayCreate(realm, 0, proto);

      // 6. If Type(len) is not Number, then
      let len = items[0];
      (0, _invariant2.default)(len !== undefined);
      let intLen;
      if (!len.mightBeNumber()) {
        // a. Let defineStatus be CreateDataProperty(array, "0", len).
        let defineStatus = _singletons.Create.CreateDataProperty(realm, array, "0", len);

        // b. Assert: defineStatus is true.
        (0, _invariant2.default)(defineStatus, "defineStatus is true");

        // c. Let intLen be 1.
        intLen = 1;
      } else {
        // 7. Else,

        // a. Let intLen be ToUint32(len).
        intLen = _singletons.To.ToUint32(realm, len.throwIfNotConcreteNumber());
        (0, _invariant2.default)(len instanceof _index.NumberValue);

        // b If intLen ≠ len, throw a RangeError exception.
        if (intLen !== len.value) {
          throw realm.createErrorThrowCompletion(realm.intrinsics.RangeError, "intLen ≠ len");
        }
      }

      // 8. Perform ! Set(array, "length", intLen, true).
      _singletons.Properties.Set(realm, array, "length", new _index.NumberValue(realm, intLen), true);

      // 9. Return array.
      return array;
    } else {
      // 1. Let numberOfArgs be the number of arguments passed to this function call.
      let numberOfArgs = argCount;

      // 2. Assert: numberOfArgs ≥ 2.
      (0, _invariant2.default)(numberOfArgs >= 2, "numberOfArgs >= 2");

      // 3. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
      let newTarget = NewTarget === undefined ? func : NewTarget;

      // 4. Let proto be ? GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%").
      let proto = (0, _index2.GetPrototypeFromConstructor)(realm, newTarget, "ArrayPrototype");

      // 5. Let array be ? ArrayCreate(numberOfArgs, proto).
      let array = _singletons.Create.ArrayCreate(realm, numberOfArgs, proto);

      // 6. Let k be 0.
      let k = 0;

      // 7. Let items be a zero-origined List containing the argument items in order.
      items;

      // 8. Repeat, while k < numberOfArgs
      while (k < numberOfArgs) {
        // a. Let Pk be ! ToString(k).
        let Pk = _singletons.To.ToString(realm, new _index.NumberValue(realm, k));

        // b. Let itemK be items[k].
        let itemK = items[k];
        (0, _invariant2.default)(itemK !== undefined);

        // c. Let defineStatus be CreateDataProperty(array, Pk, itemK).
        let defineStatus = _singletons.Create.CreateDataProperty(realm, array, Pk, itemK);

        // d. Assert: defineStatus is true.
        (0, _invariant2.default)(defineStatus, "defineStatus is true");

        // e. Increase k by 1.
        k += 1;
      }

      // 9. Assert: the value of array's length property is numberOfArgs.
      let length = (0, _index2.Get)(realm, array, "length").throwIfNotConcrete();
      (0, _invariant2.default)(length instanceof _index.NumberValue);
      (0, _invariant2.default)(length.value === numberOfArgs, "the value of array's length property is numberOfArgs");

      // 10. Return array.
      return array;
    }
  });

  // ECMA262 22.1.2.2
  func.defineNativeMethod("isArray", 1, (context, [arg]) => {
    // 1. Return ? IsArray(arg).
    return new _index.BooleanValue(realm, (0, _index2.IsArray)(realm, arg));
  });

  // ECMA262 22.1.2.3
  if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION) && !realm.isCompatibleWith("mobile")) func.defineNativeMethod("of", 0, (context, [...items], argCount) => {
    // 1. Let len be the actual number of arguments passed to this function.
    let len = argCount;

    // 2. Let items be the List of arguments passed to this function.
    items;

    // 3. Let C be the this value.
    let C = context;

    // 4. If IsConstructor(C) is true, then
    let A;
    if ((0, _index2.IsConstructor)(realm, C)) {
      (0, _invariant2.default)(C instanceof _index.ObjectValue);
      // a. Let A be ? Construct(C, « len »).
      A = (0, _index2.Construct)(realm, C, [new _index.NumberValue(realm, len)]);
    } else {
      // 5. Else,
      // a. Let A be ? ArrayCreate(len).
      A = _singletons.Create.ArrayCreate(realm, len);
    }

    // 6. Let k be 0.
    let k = 0;

    // 7. Repeat, while k < len
    while (k < len) {
      // a. Let kValue be items[k].
      let kValue = items[k];

      // b. Let Pk be ! To.ToString(k).
      let Pk = _singletons.To.ToString(realm, new _index.NumberValue(realm, k));

      // c. Perform ? CreateDataPropertyOrThrow(A, Pk, kValue).
      _singletons.Create.CreateDataPropertyOrThrow(realm, A, Pk, kValue);

      // d. Increase k by 1.
      k += 1;
    }

    // 8. Perform ? Set(A, "length", len, true).
    _singletons.Properties.Set(realm, A, "length", new _index.NumberValue(realm, len), true);

    // 9. Return A.
    return A;
  });

  // ECMA262 22.1.2.1
  if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION) && !realm.isCompatibleWith("mobile")) func.defineNativeMethod("from", 1, (context, [items, mapfn, thisArg], argCount) => {
    // 1. Let C be the this value.
    let C = context;

    let mapping, T;
    // 2. If mapfn is undefined, let mapping be false.
    if (!mapfn || mapfn instanceof _index.UndefinedValue) {
      mapping = false;
    } else if (mapfn.mightBeUndefined()) {
      (0, _invariant2.default)(mapfn instanceof _index.AbstractValue);
      mapfn.throwIfNotConcrete();
    } else {
      // 3. Else,
      // a. If IsCallable(mapfn) is false, throw a TypeError exception.
      if ((0, _index2.IsCallable)(realm, mapfn) === false) {
        mapfn.throwIfNotConcrete();
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "IsCallable(mapfn) is false");
      }

      // b. If thisArg was supplied, let T be thisArg; else let T be undefined.
      T = thisArg !== undefined ? thisArg : realm.intrinsics.undefined;

      // c. Let mapping be true.
      mapping = true;
    }

    // 4. Let usingIterator be ? GetMethod(items, @@iterator).
    let usingIterator = (0, _index2.GetMethod)(realm, items, realm.intrinsics.SymbolIterator);

    // 5. If usingIterator is not undefined, then
    if (!usingIterator.mightBeUndefined()) {
      let A;
      // a. If IsConstructor(C) is true, then
      if ((0, _index2.IsConstructor)(realm, C)) {
        (0, _invariant2.default)(C instanceof _index.ObjectValue);
        // i. Let A be ? Construct(C).
        A = (0, _index2.Construct)(realm, C);
      } else {
        // b. Else,
        // i. Let A be ArrayCreate(0).
        A = _singletons.Create.ArrayCreate(realm, 0);
      }

      // c. Let iterator be ? GetIterator(items, usingIterator).
      let iterator = (0, _iterator.GetIterator)(realm, items, usingIterator);

      // d. Let k be 0.
      let k = 0;

      // e. Repeat
      while (true) {
        // i. If k ≥ 2^53-1, then
        if (k >= Math.pow(2, 53) - 1) {
          // 1. Let error be Completion{[[Type]]: throw, [[Value]]: a newly created TypeError object, [[Target]]: empty}.
          let error = realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "k >= 2^53 - 1");

          // 2. Return ? IteratorClose(iterator, error).
          throw (0, _iterator.IteratorClose)(realm, iterator, error);
        }

        // ii. Let Pk be ! ToString(k).
        let Pk = _singletons.To.ToString(realm, new _index.NumberValue(realm, k));

        // iii. Let next be ? IteratorStep(iterator).
        let next = (0, _iterator.IteratorStep)(realm, iterator);

        // iv. If next is false, then
        if (next === false) {
          // 1. Perform ? Set(A, "length", k, true).
          _singletons.Properties.Set(realm, A, "length", new _index.NumberValue(realm, k), true);

          // 2. Return A.
          return A;
        }

        // v. Let nextValue be ? IteratorValue(next).
        let nextValue = (0, _iterator.IteratorValue)(realm, next);

        let mappedValue;
        // vi. If mapping is true, then
        if (mapping === true) {
          // 1. Let mappedValue be Call(mapfn, T, « nextValue, k »).
          try {
            (0, _invariant2.default)(T !== undefined);
            mappedValue = (0, _index2.Call)(realm, mapfn, T, [nextValue, new _index.NumberValue(realm, k)]);
          } catch (mappedValueCompletion) {
            if (mappedValueCompletion instanceof _completions.AbruptCompletion) {
              // 2. If mappedValue is an abrupt completion, return ? IteratorClose(iterator, mappedValue).
              throw (0, _iterator.IteratorClose)(realm, iterator, mappedValueCompletion);
            } else {
              throw mappedValueCompletion;
            }
          }
          // 3. Let mappedValue be mappedValue.[[Value]].
        } else {
          // vii. Else, let mappedValue be nextValue.
          mappedValue = nextValue;
        }

        // viii. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
        try {
          _singletons.Create.CreateDataPropertyOrThrow(realm, A, Pk, mappedValue);
        } catch (completion) {
          if (completion instanceof _completions.AbruptCompletion) {
            // ix. If defineStatus is an abrupt completion, return ? IteratorClose(iterator, defineStatus).
            throw (0, _iterator.IteratorClose)(realm, iterator, completion);
          } else throw completion;
        }

        // x. Increase k by 1.
        k = k + 1;
      }
    } else {
      usingIterator.throwIfNotConcrete();
    }

    // 6. NOTE: items is not an Iterable so assume it is an array-like object.
    items = items.throwIfNotConcrete();
    (0, _invariant2.default)(items instanceof _index.ObjectValue);

    // 7. Let arrayLike be ! ToObject(items).
    let arrayLike = _singletons.To.ToObject(realm, items);

    // 8. Let len be ? ToLength(? Get(arrayLike, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, arrayLike, "length"));

    let A;
    // 9. If IsConstructor(C) is true, then
    if ((0, _index2.IsConstructor)(realm, C)) {
      (0, _invariant2.default)(C instanceof _index.ObjectValue);
      // a. Let A be ? Construct(C, « len »).
      A = (0, _index2.Construct)(realm, C, [new _index.NumberValue(realm, len)]);
    } else {
      // 10. Else,
      // a. Let A be ? ArrayCreate(len).
      A = _singletons.Create.ArrayCreate(realm, len);
    }

    // 11. Let k be 0.
    let k = 0;

    // 12. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! ToString(k).
      let Pk = _singletons.To.ToString(realm, new _index.NumberValue(realm, k));

      // b. Let kValue be ? Get(arrayLike, Pk).
      let kValue = (0, _index2.Get)(realm, arrayLike, Pk);

      let mappedValue;
      // c. If mapping is true, then
      if (mapping === true) {
        // i. Let mappedValue be ? Call(mapfn, T, « kValue, k »).
        (0, _invariant2.default)(T !== undefined);
        mappedValue = (0, _index2.Call)(realm, mapfn, T, [kValue, new _index.NumberValue(realm, k)]);
      } else {
        // d. Else, let mappedValue be kValue.
        mappedValue = kValue;
      }

      // e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
      _singletons.Create.CreateDataPropertyOrThrow(realm, A, new _index.StringValue(realm, Pk), mappedValue);

      // f. Increase k by 1.
      k = k + 1;
    }

    // 13. Perform ? Set(A, "length", len, true).
    _singletons.Properties.Set(realm, A, "length", new _index.NumberValue(realm, len), true);

    // 14. Return A.
    return A;
  });

  // ECMA262 22.1.2.5
  func.defineNativeGetter(realm.intrinsics.SymbolSpecies, context => {
    // 1. Return the this value
    return context;
  });

  return func;
};

var _index = require("../../values/index.js");

var _completions = require("../../completions.js");

var _index2 = require("../../methods/index.js");

var _iterator = require("../../methods/iterator.js");

var _singletons = require("../../singletons.js");

var _invariant = require("../../invariant.js");

var _invariant2 = _interopRequireDefault(_invariant);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
//# sourceMappingURL=Array.js.map