// Copyright (c) 2018, 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';
import 'data_source.dart';
import 'serialization_interfaces.dart' show StringInterner;

/// [DataSource] that reads data from a sequence of bytes.
///
/// This data source works together with [BinaryDataSink].
class BinaryDataSource implements DataSource {
  int _byteOffset = 0;
  final List<int> _bytes;
  final StringInterner? _stringInterner;
  late final Map<int, int> _deferredOffsetToSize;

  BinaryDataSource(this._bytes, {StringInterner? stringInterner})
      : _stringInterner = stringInterner {
    assert((_bytes as dynamic) != null); // TODO(48820): Remove when sound.
    final deferredDataStart = readAtOffset(_bytes.length - 4, _readUint32);
    _deferredOffsetToSize = readAtOffset(deferredDataStart, () {
      final deferredSizesCount = readInt();
      final result = <int, int>{};
      for (var i = 0; i < deferredSizesCount; i++) {
        final offset = readInt();
        final size = readInt();
        result[offset] = size;
      }
      return result;
    });
  }

  @override
  void begin(String tag) {}

  @override
  void end(String tag) {}

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

  @override
  String readString() {
    int length = readInt();
    List<int> bytes = Uint8List(length);
    bytes.setRange(0, bytes.length, _bytes, _byteOffset);
    _byteOffset += bytes.length;
    String string = utf8.decode(bytes);
    if (_stringInterner == null) return string;
    return _stringInterner!.internString(string);
  }

  @override
  int readInt() {
    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
  E readEnum<E>(List<E> values) {
    int index = readInt();
    assert(
        0 <= index && index < values.length,
        "Invalid data kind index. "
        "Expected one of $values, found index $index.");
    return values[index];
  }

  @override
  E readAtOffset<E>(int offset, E reader()) {
    final offsetBefore = _byteOffset;
    _byteOffset = offset;
    final value = reader();
    _byteOffset = offsetBefore;
    return value;
  }

  int _readUint32() {
    return (_readByte() << 24) |
        (_readByte() << 16) |
        (_readByte() << 8) |
        _readByte();
  }

  @override
  int readDeferred() {
    final indexOffset = _byteOffset;
    readInt(); // Read collision padding.
    final dataOffset = _byteOffset;
    final dataLength = _deferredOffsetToSize[indexOffset]!;
    _byteOffset += dataLength;
    return dataOffset;
  }

  @override
  E readDeferredAsEager<E>(E reader()) {
    readInt(); // Read collision padding.
    return reader();
  }

  @override
  int get length => _bytes.length;

  @override
  String get errorContext => ' Offset $_byteOffset in ${_bytes.length}.';
}
