// Copyright (c) 2019, 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.

import 'dart:convert';
import 'dart:typed_data';

/// Interface for deserialization.
// TODO(sigmund): share this with pkg:compiler/src/serialization/*
abstract class DataSource {
  /// Reads a reference to an [E] value from this data source. If the value has
  /// not yet been deserialized, [f] is called to deserialize the value itself.
  E readCached<E>(E Function() f);

  /// Reads a potentially `null` [E] value from this data source, calling [f] to
  /// read the non-null value from the data source.
  ///
  /// This is a convenience method to be used together with
  /// [DataSink.writeValueOrNull].
  E? readValueOrNull<E>(E Function() f);

  /// Reads a list of [E] values from this data source.
  ///
  /// This is a convenience method to be used together with
  /// [DataSink.writeList].
  List<E>? readList<E>(E Function() f);

  /// Reads a boolean value from this data source.
  bool readBool();

  /// Reads a non-negative integer value from this data source.
  int readInt();

  /// Reads a potentially `null` non-negative integer value from this data
  /// source.
  ///
  /// This is a convenience method to be used together with
  /// [DataSink.writeIntOrNull].
  int? readIntOrNull();

  /// Reads a string value from this data source.
  String readString();

  /// Reads a potentially `null` string value from this data source.
  ///
  /// This is a convenience method to be used together with
  /// [DataSink.writeStringOrNull].
  String? readStringOrNull();

  /// Reads a list of string values from this data source. If [emptyAsNull] is
  /// `true`, `null` is returned instead of an empty list.
  ///
  /// This is a convenience method to be used together with
  /// [DataSink.writeStrings].
  List<String>? readStrings({bool emptyAsNull = false});

  /// Reads a map from string values to [V] values from this data source,
  /// calling [f] to read each value from the data source. If [emptyAsNull] is
  /// `true`, `null` is returned instead of an empty map.
  ///
  /// This is a convenience method to be used together with
  /// [DataSink.writeStringMap].
  Map<String, V>? readStringMap<V>(V Function() f, {bool emptyAsNull = false});

  /// Reads an enum value from the list of enum [values] from this data source.
  ///
  /// The [values] argument is intended to be the static `.values` field on
  /// enum classes, for instance:
  ///
  ///    enum Foo { bar, baz }
  ///    ...
  ///    Foo foo = source.readEnum(Foo.values);
  ///
  E readEnum<E>(List<E> values);

  /// Reads a URI value from this data source.
  Uri readUri();
}

/// Mixin that implements all convenience methods of [DataSource].
abstract class DataSourceMixin implements DataSource {
  @override
  E? readValueOrNull<E>(E Function() f) {
    bool hasValue = readBool();
    if (hasValue) {
      return f();
    }
    return null;
  }

  @override
  List<E> readList<E>(E Function() f) {
    int count = readInt();
    return List.generate(count, (i) => f());
  }

  @override
  int? readIntOrNull() {
    bool hasValue = readBool();
    if (hasValue) {
      return readInt();
    }
    return null;
  }

  @override
  String? readStringOrNull() {
    bool hasValue = readBool();
    if (hasValue) {
      return readString();
    }
    return null;
  }

  @override
  List<String>? readStrings({bool emptyAsNull = false}) {
    int count = readInt();
    if (count == 0 && emptyAsNull) return null;
    return List.generate(count, (index) => readString());
  }

  @override
  Map<String, V>? readStringMap<V>(V Function() f, {bool emptyAsNull = false}) {
    int count = readInt();
    if (count == 0 && emptyAsNull) return null;
    Map<String, V> map = {};
    for (int i = 0; i < count; i++) {
      String key = readString();
      V value = f();
      map[key] = value;
    }
    return map;
  }
}

/// Data source helper reads canonicalized [E] values through indices.
class IndexedSource<E> {
  final int Function() _readInt;
  final List<E?> _cache = [];
  final Set<int> _pending = {};

  IndexedSource(this._readInt);

  /// Reads a reference to an [E] value from the data source.
  ///
  /// If the value hasn't yet been read, [readValue] is called to deserialize
  /// the value itself.
  E read(E Function() readValue) {
    int index = _readInt();
    if (_pending.contains(index)) throw "serialization cycles not supported";
    if (index >= _cache.length) {
      _pending.add(index);
      _cache.add(null);
      E value = readValue();
      _pending.remove(index);
      _cache[index] = value;
      return value;
    } else {
      return _cache[index]!;
    }
  }
}

/// Base implementation of [DataSource] using [DataSourceMixin] to implement
/// convenience methods.
abstract class AbstractDataSource extends DataSourceMixin
    implements DataSource {
  late final IndexedSource<String> _stringIndex;
  late final IndexedSource<Uri> _uriIndex;
  final Map<Type, IndexedSource> _generalCaches = {};

  AbstractDataSource() {
    _stringIndex = IndexedSource<String>(_readIntInternal);
    _uriIndex = IndexedSource<Uri>(_readIntInternal);
  }

  @override
  E readCached<E>(E Function() f) {
    IndexedSource source =
        _generalCaches[E] ??= IndexedSource<E>(_readIntInternal);
    return source.read(f);
  }

  @override
  E readEnum<E>(List<E> values) {
    return _readEnumInternal(values);
  }

  @override
  Uri readUri() {
    return _readUri();
  }

  Uri _readUri() {
    return _uriIndex.read(_readUriInternal);
  }

  @override
  bool readBool() {
    int value = _readIntInternal();
    assert(value == 0 || value == 1);
    return value == 1;
  }

  @override
  String readString() {
    return _readString();
  }

  String _readString() {
    return _stringIndex.read(_readStringInternal);
  }

  @override
  int readInt() {
    return _readIntInternal();
  }

  /// Actual deserialization of a string value, implemented by subclasses.
  String _readStringInternal();

  /// Actual deserialization of a non-negative integer value, implemented by
  /// subclasses.
  int _readIntInternal();

  /// Actual deserialization of a URI value, implemented by subclasses.
  Uri _readUriInternal();

  /// Actual deserialization of an enum value in [values], implemented by
  /// subclasses.
  E _readEnumInternal<E>(List<E> values);
}

/// [DataSource] that reads data from a sequence of bytes.
///
/// This data source works together with [BinarySink].
class BinarySource extends AbstractDataSource {
  int _byteOffset = 0;
  final List<int> _bytes;

  BinarySource(this._bytes);
  int _readByte() => _bytes[_byteOffset++];

  @override
  String _readStringInternal() {
    int length = _readIntInternal();
    List<int> bytes = Uint8List(length);
    bytes.setRange(0, bytes.length, _bytes, _byteOffset);
    _byteOffset += bytes.length;
    return utf8.decode(bytes);
  }

  @override
  int _readIntInternal() {
    var byte = _readByte();
    if (byte & 0x80 == 0) {
      // 0xxxxxxx
      return byte;
    } else if (byte & 0x40 == 0) {
      // 10xxxxxx
      return ((byte & 0x3F) << 8) | _readByte();
    } else {
      // 11xxxxxx
      return ((byte & 0x3F) << 24) |
          (_readByte() << 16) |
          (_readByte() << 8) |
          _readByte();
    }
  }

  @override
  Uri _readUriInternal() {
    String text = _readString();
    return Uri.parse(text);
  }

  @override
  E _readEnumInternal<E>(List<E> values) {
    int index = _readIntInternal();
    assert(
        0 <= index && index < values.length,
        "Invalid data kind index. "
        "Expected one of $values, found index $index.");
    return values[index];
  }
}
