define(['./_getLength', './_isArrayLike', './isArray', './isArguments'], function (_getLength, _isArrayLike, isArray, isArguments) {
  // Internal implementation of a recursive `flatten` function.
  function flatten(input, depth, strict, output) {
    output = output || [];

    if (!depth && depth !== 0) {
      depth = Infinity;
    } else if (depth <= 0) {
      return output.concat(input);
    }

    var idx = output.length;

    for (var i = 0, length = _getLength(input); i < length; i++) {
      var value = input[i];

      if (_isArrayLike(value) && (isArray(value) || isArguments(value))) {
        // Flatten current level of array or arguments object.
        if (depth > 1) {
          flatten(value, depth - 1, strict, output);
          idx = output.length;
        } else {
          var j = 0,
              len = value.length;

          while (j < len) output[idx++] = value[j++];
        }
      } else if (!strict) {
        output[idx++] = value;
      }
    }

    return output;
  }

  return flatten;
});