// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Patch file for dart:convert library.

import 'dart:_js_helper' show argumentErrorValue, patch;
import 'dart:_foreign_helper' show JS;
import 'dart:_interceptors' show JSArray, JSExtendableArray;
import 'dart:_internal' show MappedIterable, ListIterable;
import 'dart:collection' show LinkedHashMap, MapBase;
import 'dart:_native_typed_data' show NativeUint8List;

/// Parses [json] and builds the corresponding parsed JSON value.
///
/// Parsed JSON values Nare of the types [num], [String], [bool], [Null],
/// [List]s of parsed JSON values or [Map]s from [String] to parsed
/// JSON values.
///
/// The optional [reviver] function, if provided, is called once for each object
/// or list property parsed. The arguments are the property name ([String]) or
/// list index ([int]), and the value is the parsed value.  The return value of
/// the reviver will be used as the value of that property instead of the parsed
/// value.  The top level value is passed to the reviver with the empty string
/// as a key.
///
/// Throws [FormatException] if the input is not valid JSON text.
@patch
_parseJson(String source, reviver(key, value)?) {
  if (source is! String) throw argumentErrorValue(source);

  var parsed;
  try {
    parsed = JS('=Object|JSExtendableArray|Null|bool|num|String',
        'JSON.parse(#)', source);
  } catch (e) {
    throw FormatException(JS<String>('String', 'String(#)', e));
  }

  if (reviver == null) {
    return _convertJsonToDartLazy(parsed);
  } else {
    return _convertJsonToDart(parsed, reviver);
  }
}

/// Walks the raw JavaScript value [json], replacing JavaScript Objects with
/// Maps. [json] is expected to be freshly allocated so elements can be replaced
/// in-place.
_convertJsonToDart(json, reviver(Object? key, Object? value)) {
  walk(e) {
    // JavaScript null, string, number, bool are in the correct representation.
    if (JS<bool>('bool', '# == null', e) ||
        JS<bool>('bool', 'typeof # != "object"', e)) {
      return e;
    }

    // This test is needed to avoid identifying '{"__proto__":[]}' as an Array.
    // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
    // bug 621 below is fixed.
    if (JS<bool>('bool', 'Object.getPrototypeOf(#) === Array.prototype', e)) {
      // In-place update of the elements since JS Array is a Dart List.
      for (int i = 0; i < JS<int>('int', '#.length', e); i++) {
        // Use JS indexing to avoid range checks.  We know this is the only
        // reference to the list, but the compiler will likely never be able to
        // tell that this instance of the list cannot have its length changed by
        // the reviver even though it later will be passed to the reviver at the
        // outer level.
        var item = JS('', '#[#]', e, i);
        JS('', '#[#]=#', e, i, reviver(i, walk(item)));
      }
      return e;
    }

    // Otherwise it is a plain object, so copy to a JSON map, so we process
    // and revive all entries recursively.
    _JsonMap map = _JsonMap(e);
    var processed = map._processed;
    List<String> keys = map._computeKeys();
    for (int i = 0; i < keys.length; i++) {
      String key = keys[i];
      var revived = reviver(key, walk(JS('', '#[#]', e, key)));
      JS('', '#[#]=#', processed, key, revived);
    }

    // Update the JSON map structure so future access is cheaper.
    map._original = processed; // Don't keep two objects around.
    return map;
  }

  return reviver(null, walk(json));
}

_convertJsonToDartLazy(object) {
  // JavaScript null and undefined are represented as null.
  if (object == null) return null;

  // JavaScript string, number, bool already has the correct representation.
  if (JS<bool>('bool', 'typeof # != "object"', object)) {
    return object;
  }

  // This test is needed to avoid identifying '{"__proto__":[]}' as an array.
  // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
  // bug https://code.google.com/p/v8/issues/detail?id=621 is fixed.
  if (JS<bool>(
      'bool', 'Object.getPrototypeOf(#) !== Array.prototype', object)) {
    return _JsonMap(object);
  }

  // Update the elements in place since JS arrays are Dart lists.
  for (int i = 0; i < JS<int>('int', '#.length', object); i++) {
    // Use JS indexing to avoid range checks.  We know this is the only
    // reference to the list, but the compiler will likely never be able to
    // tell that this instance of the list cannot have its length changed by
    // the reviver even though it later will be passed to the reviver at the
    // outer level.
    var item = JS('', '#[#]', object, i);
    JS('', '#[#]=#', object, i, _convertJsonToDartLazy(item));
  }
  return object;
}

class _JsonMap extends MapBase<String, dynamic> {
  // The original JavaScript object remains unchanged until
  // the map is eventually upgraded, in which case we null it
  // out to reclaim the memory used by it.
  var _original;

  // We keep track of the map entries that we have already
  // processed by adding them to a separate JavaScript object.
  var _processed = _newJavaScriptObject();

  // If the data slot isn't null, it represents either the list
  // of keys (for non-upgraded JSON maps) or the upgraded map.
  var _data = null;

  _JsonMap(this._original);

  operator [](key) {
    if (_isUpgraded) {
      return _upgradedMap[key];
    } else if (key is! String) {
      return null;
    } else {
      var result = _getProperty(_processed, key);
      if (_isUnprocessed(result)) result = _process(key);
      return result;
    }
  }

  int get length => _isUpgraded ? _upgradedMap.length : _computeKeys().length;

  bool get isEmpty => length == 0;
  bool get isNotEmpty => length > 0;

  Iterable<String> get keys {
    if (_isUpgraded) return _upgradedMap.keys;
    return _JsonMapKeyIterable(this);
  }

  Iterable get values {
    if (_isUpgraded) return _upgradedMap.values;
    return MappedIterable(_computeKeys(), (each) => this[each]);
  }

  operator []=(key, value) {
    if (_isUpgraded) {
      _upgradedMap[key] = value;
    } else if (containsKey(key)) {
      var processed = _processed;
      _setProperty(processed, key, value);
      var original = _original;
      if (!identical(original, processed)) {
        _setProperty(original, key, null); // Reclaim memory.
      }
    } else {
      _upgrade()[key] = value;
    }
  }

  void addAll(Map<String, dynamic> other) {
    other.forEach((key, value) {
      this[key] = value;
    });
  }

  bool containsValue(value) {
    if (_isUpgraded) return _upgradedMap.containsValue(value);
    List<String> keys = _computeKeys();
    for (int i = 0; i < keys.length; i++) {
      String key = keys[i];
      if (this[key] == value) return true;
    }
    return false;
  }

  bool containsKey(key) {
    if (_isUpgraded) return _upgradedMap.containsKey(key);
    if (key is! String) return false;
    return _hasProperty(_original, key);
  }

  putIfAbsent(key, ifAbsent()) {
    if (containsKey(key)) return this[key];
    var value = ifAbsent();
    this[key] = value;
    return value;
  }

  remove(Object? key) {
    if (!_isUpgraded && !containsKey(key)) return null;
    return _upgrade().remove(key);
  }

  void clear() {
    if (_isUpgraded) {
      _upgradedMap.clear();
    } else {
      if (_data != null) {
        // Clear the list of keys to make sure we force
        // a concurrent modification error if anyone is
        // currently iterating over it.
        _data.clear();
      }
      _original = _processed = null;
      _data = {};
    }
  }

  void forEach(void f(String key, value)) {
    if (_isUpgraded) return _upgradedMap.forEach(f);
    List<String> keys = _computeKeys();
    for (int i = 0; i < keys.length; i++) {
      String key = keys[i];

      // Compute the value under the assumption that the property
      // is present but potentially not processed.
      var value = _getProperty(_processed, key);
      if (_isUnprocessed(value)) {
        value = _convertJsonToDartLazy(_getProperty(_original, key));
        _setProperty(_processed, key, value);
      }

      // Do the callback.
      f(key, value);

      // Check if invoking the callback function changed
      // the key set. If so, throw an exception.
      if (!identical(keys, _data)) {
        throw ConcurrentModificationError(this);
      }
    }
  }

  // ------------------------------------------
  // Private helper methods.
  // ------------------------------------------

  bool get _isUpgraded => _processed == null;

  Map<String, dynamic> get _upgradedMap {
    assert(_isUpgraded);
    // 'cast' the union type to LinkedHashMap.  It would be even better if we
    // could 'cast' to the implementation type, since LinkedHashMap includes
    // _JsonMap.
    return JS('LinkedHashMap', '#', _data);
  }

  List<String> _computeKeys() {
    assert(!_isUpgraded);
    List? keys = _data;
    if (keys == null) {
      keys = _data = new JSArray<String>.typed(_getPropertyNames(_original));
    }
    return JS('JSExtendableArray', '#', keys);
  }

  Map<String, dynamic> _upgrade() {
    if (_isUpgraded) return _upgradedMap;

    // Copy all the (key, value) pairs to a freshly allocated
    // linked hash map thus preserving the ordering.
    var result = <String, dynamic>{};
    List<String> keys = _computeKeys();
    for (int i = 0; i < keys.length; i++) {
      String key = keys[i];
      result[key] = this[key];
    }

    // We only upgrade when we need to extend the map, so we can
    // safely force a concurrent modification error in case
    // someone is iterating over the map here.
    if (keys.isEmpty) {
      keys.add("");
    } else {
      keys.clear();
    }

    // Clear out the associated JavaScript objects and mark the
    // map as having been upgraded.
    _original = _processed = null;
    _data = result;
    assert(_isUpgraded);
    return result;
  }

  _process(String key) {
    if (!_hasProperty(_original, key)) return null;
    var result = _convertJsonToDartLazy(_getProperty(_original, key));
    return _setProperty(_processed, key, result);
  }

  // ------------------------------------------
  // Private JavaScript helper methods.
  // ------------------------------------------

  static bool _hasProperty(object, String key) => JS<bool>(
      'bool', 'Object.prototype.hasOwnProperty.call(#,#)', object, key);
  static _getProperty(object, String key) => JS('', '#[#]', object, key);
  static _setProperty(object, String key, value) =>
      JS('', '#[#]=#', object, key, value);
  static List _getPropertyNames(object) =>
      JS('JSExtendableArray', 'Object.keys(#)', object);
  static bool _isUnprocessed(object) =>
      JS<bool>('bool', 'typeof(#)=="undefined"', object);
  static _newJavaScriptObject() => JS('=Object', 'Object.create(null)');
}

class _JsonMapKeyIterable extends ListIterable<String> {
  final _JsonMap _parent;

  _JsonMapKeyIterable(this._parent);

  int get length => _parent.length;

  String elementAt(int index) {
    return _parent._isUpgraded
        ? _parent.keys.elementAt(index)
        : _parent._computeKeys()[index];
  }

  /// Although [ListIterable] defines its own iterator, we return the iterator
  /// of the underlying list [_keys] in order to propagate
  /// [ConcurrentModificationError]s.
  Iterator<String> get iterator {
    return _parent._isUpgraded
        ? _parent.keys.iterator
        : _parent._computeKeys().iterator;
  }

  /// Delegate to [parent.containsKey] to ensure the performance expected
  /// from [Map.keys.containsKey].
  bool contains(Object? key) => _parent.containsKey(key);
}

@patch
class JsonDecoder {
  @patch
  StringConversionSink startChunkedConversion(Sink<Object?> sink) {
    return _JsonDecoderSink(_reviver, sink);
  }
}

/// Implements the chunked conversion from a JSON string to its corresponding
/// object.
///
/// The sink only creates one object, but its input can be chunked.
// TODO(floitsch): don't accumulate everything before starting to decode.
class _JsonDecoderSink extends _StringSinkConversionSink<StringBuffer> {
  final Object? Function(Object? key, Object? value)? _reviver;
  final Sink<Object?> _sink;

  _JsonDecoderSink(this._reviver, this._sink) : super(StringBuffer(''));

  void close() {
    super.close();
    String accumulated = _stringSink.toString();
    _stringSink.clear();
    Object? decoded = _parseJson(accumulated, _reviver);
    _sink.add(decoded);
    _sink.close();
  }
}

@patch
class Utf8Decoder {
  // Always fall back to the Dart implementation for strings shorter than this
  // threshold, as there is a large, constant overhead for using TextDecoder.
  static const int _shortInputThreshold = 15;

  @patch
  Converter<List<int>, T> fuse<T>(Converter<String, T> next) {
    return super.fuse(next);
  }

  @patch
  static String? _convertIntercepted(
      bool allowMalformed, List<int> codeUnits, int start, int? end) {
    // Test `codeUnits is NativeUint8List`. Dart's NativeUint8List is
    // implemented by JavaScript's Uint8Array.
    if (JS<bool>('bool', '# instanceof Uint8Array', codeUnits)) {
      // JS 'cast' to avoid a downcast equivalent to the is-check we hand-coded.
      NativeUint8List casted =
          JS<NativeUint8List>('NativeUint8List', '#', codeUnits);
      // Always use Dart implementation for short strings.
      end ??= casted.length;
      if (end - start < _shortInputThreshold) {
        return null;
      }
      String? result =
          _convertInterceptedUint8List(allowMalformed, casted, start, end);
      if (result != null && allowMalformed) {
        // In principle, TextDecoder should have provided the correct result
        // here, but some browsers deviate from the standard as to how many
        // replacement characters they produce. Thus, we fall back to the Dart
        // implementation if the result contains any replacement characters.
        if (JS<int>('int', r'#.indexOf(#)', result, '\uFFFD') >= 0) {
          return null;
        }
      }
      return result;
    }
    return null; // This call was not intercepted.
  }

  static String? _convertInterceptedUint8List(
      bool allowMalformed, NativeUint8List codeUnits, int start, int end) {
    final decoder = allowMalformed ? _decoderNonfatal : _decoder;
    if (decoder == null) return null;
    if (0 == start && end == codeUnits.length) {
      return _useTextDecoder(decoder, codeUnits);
    }

    int length = codeUnits.length;
    end = RangeError.checkValidRange(start, end, length);

    return _useTextDecoder(
        decoder,
        JS<NativeUint8List>(
            'NativeUint8List', '#.subarray(#, #)', codeUnits, start, end));
  }

  static String? _useTextDecoder(decoder, NativeUint8List codeUnits) {
    // If the input is malformed, catch the exception and return `null` to fall
    // back on unintercepted decoder. The fallback will either succeed in
    // decoding, or report the problem better than TextDecoder.
    try {
      return JS<String>('String', '#.decode(#)', decoder, codeUnits);
    } catch (e) {}
    return null;
  }

  // TextDecoder is not defined on some browsers and on the stand-alone d8 and
  // jsshell engines. Use a lazy initializer to do feature detection once.
  static final _decoder = () {
    try {
      return JS('', 'new TextDecoder("utf-8", {fatal: true})');
    } catch (e) {}
    return null;
  }();
  static final _decoderNonfatal = () {
    try {
      return JS('', 'new TextDecoder("utf-8", {fatal: false})');
    } catch (e) {}
    return null;
  }();
}

@patch
class _Utf8Decoder {
  @patch
  _Utf8Decoder(this.allowMalformed) : _state = beforeBom;

  @patch
  String convertSingle(List<int> codeUnits, int start, int? maybeEnd) {
    return convertGeneral(codeUnits, start, maybeEnd, true);
  }

  @patch
  String convertChunked(List<int> codeUnits, int start, int? maybeEnd) {
    return convertGeneral(codeUnits, start, maybeEnd, false);
  }
}
