// Copyright (c) 2023, 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:ffi';
import 'dart:typed_data';

import '../accessors.dart';
import '../jarray.dart';
import '../jni.dart';
import '../jreference.dart';
import '../jvalues.dart';
import '../third_party/generated_bindings.dart';
import '../types.dart';
import 'jbuffer.dart';

final class JByteBufferType extends JObjType<JByteBuffer> {
  const JByteBufferType();

  @override
  String get signature => r"Ljava/nio/ByteBuffer;";

  @override
  JByteBuffer fromRef(JObjectPtr ref) => JByteBuffer.fromRef(ref);

  @override
  JObjType get superType => const JBufferType();

  @override
  final superCount = 2;

  @override
  int get hashCode => (JByteBufferType).hashCode;

  @override
  bool operator ==(Object other) {
    return other.runtimeType == (JByteBufferType) && other is JByteBufferType;
  }
}

/// A byte [JBuffer].
///
/// The bindings for `java.nio.ByteBuffer`.
///
/// This enables fast memory copying between Java and Dart when directly
/// allocated (See [JByteBuffer.allocateDirect]).
///
/// To create a [JByteBuffer] from the content of a [Uint8List],
/// use [JByteBuffer.fromList]. This uses direct allocation to enable fast
/// copying.
///
/// [asUint8List] provides a direct access to the underlying [Uint8List] that
/// this buffer uses. This means any changes to it will change the content of
/// the buffer and vice versa. This can be used to access to [Uint8List] methods
/// such as [Uint8List.setRange].
///
/// Example:
/// ```dart
/// final directBuffer = JByteBuffer.allocateDirect(3);
/// directBuffer.asUint8List().setAll(0, [1, 2, 3]);
/// // The buffer is now 1, 2, 3.
/// ```
///
/// Both the original buffer and the [Uint8List] keep the underlying Java buffer
/// alive. Once all the instances of the original buffer and the lists produced
/// from [asUint8List] are inaccessible both in Java and Dart, Java will
/// correctly garbage collects the buffer and frees its underlying memory.
///
/// Example:
/// ```dart
/// final directBuffer = JByteBuffer.allocateDirect(3);
/// final data = directBuffer.asUint8List();
/// directBuffer.release(); // Releasing the original buffer.
/// data.setAll(0, [1, 2, 3]); // Works! [data] is still accessible.
/// ```
///
/// The original buffer can be [release]d when calling [asUint8List]
/// by setting the `releaseOriginal` parameter to `true`.
///
/// Example:
/// ```dart
/// final directBuffer = JByteBuffer.allocateDirect(3);
/// // [releaseOriginal] is `false` by default.
/// final data1 = directBuffer.asUint8List();
/// directBuffer.nextByte = 42; // No problem!
/// print(data1[0]); // prints 42!
/// final data2 = directBuffer.asUint8List(releaseOriginal: true);
/// // directBuffer.nextByte = 42; // throws [UseAfterReleaseException]!
/// ```
class JByteBuffer extends JBuffer {
  @override
  // ignore: overridden_fields
  late final JObjType<JByteBuffer> $type = type;

  JByteBuffer.fromRef(
    JObjectPtr ref,
  ) : super.fromRef(ref);

  static final _class = Jni.findJClass(r"java/nio/ByteBuffer");

  /// The type which includes information such as the signature of this class.
  static const type = JByteBufferType();

  static final _allocateDirectId = Jni.accessors.getStaticMethodIDOf(
      _class.reference.pointer, r"allocateDirect", r"(I)Ljava/nio/ByteBuffer;");

  /// Allocates a new direct byte buffer.
  ///
  /// Throws:
  /// * [IllegalArgumentException] - If the capacity is a negative integer
  factory JByteBuffer.allocateDirect(int capacity) {
    return JByteBuffer.fromRef(
      Jni.accessors.callStaticMethodWithArgs(
          _class.reference.pointer,
          _allocateDirectId,
          JniCallType.objectType,
          [JValueInt(capacity)]).object,
    );
  }

  static final _allocateId = Jni.accessors.getStaticMethodIDOf(
      _class.reference.pointer, r"allocate", r"(I)Ljava/nio/ByteBuffer;");

  /// Allocates a new byte buffer.
  ///
  /// Throws:
  /// * [IllegalArgumentException] - If the capacity is a negative integer
  factory JByteBuffer.allocate(int capacity) {
    return const JByteBufferType().fromRef(Jni.accessors
        .callStaticMethodWithArgs(_class.reference.pointer, _allocateId,
            JniCallType.objectType, [JValueInt(capacity)]).object);
  }

  static final _wrapWholeId = Jni.accessors.getStaticMethodIDOf(
      _class.reference.pointer, r"wrap", r"([B)Ljava/nio/ByteBuffer;");
  static final _wrapId = Jni.accessors.getStaticMethodIDOf(
      _class.reference.pointer, r"wrap", r"([BII)Ljava/nio/ByteBuffer;");

  /// Wraps a byte array into a buffer.
  ///
  /// The new buffer will be backed by the given byte array; that is,
  /// modifications to the buffer will cause the array to be modified
  /// and vice versa.
  static JByteBuffer wrap(
    JArray<jbyte> array, [
    int? offset,
    int? length,
  ]) {
    if (offset == null && length == null) {
      return const JByteBufferType().fromRef(
        Jni.accessors.callStaticMethodWithArgs(
          _class.reference.pointer,
          _wrapWholeId,
          JniCallType.objectType,
          [array.reference.pointer],
        ).object,
      );
    }
    offset ??= 0;
    length ??= array.length - offset;
    return const JByteBufferType().fromRef(
      Jni.accessors.callStaticMethodWithArgs(
        _class.reference.pointer,
        _wrapId,
        JniCallType.objectType,
        [array.reference.pointer, JValueInt(offset), JValueInt(length)],
      ).object,
    );
  }

  /// Creates a [JByteBuffer] from the content of [list].
  ///
  /// The [JByteBuffer] will be allocated using [JByteBuffer.allocateDirect].
  factory JByteBuffer.fromList(Uint8List list) {
    final buffer = JByteBuffer.allocateDirect(list.length);
    buffer._asUint8ListUnsafe().setAll(0, list);
    return buffer;
  }

  static final _sliceId = Jni.accessors.getMethodIDOf(
      _class.reference.pointer, r"slice", r"()Ljava/nio/ByteBuffer;");

  /// Creates a new byte buffer whose content is a shared subsequence of this
  /// buffer's content.
  JByteBuffer slice() {
    return const JByteBufferType().fromRef(Jni.accessors.callMethodWithArgs(
        reference.pointer, _sliceId, JniCallType.objectType, []).object);
  }

  static final _duplicateId = Jni.accessors.getMethodIDOf(
      _class.reference.pointer, r"duplicate", r"()Ljava/nio/ByteBuffer;");

  /// Creates a new byte buffer that shares this buffer's content.
  JByteBuffer duplicate() {
    return const JByteBufferType().fromRef(Jni.accessors.callMethodWithArgs(
        reference.pointer, _duplicateId, JniCallType.objectType, []).object);
  }

  static final _asReadOnlyBufferId = Jni.accessors.getMethodIDOf(
      _class.reference.pointer,
      r"asReadOnlyBuffer",
      r"()Ljava/nio/ByteBuffer;");

  /// Creates a new, read-only byte buffer that shares this buffer's content.
  JByteBuffer asReadOnlyBuffer() {
    return const JByteBufferType().fromRef(Jni.accessors.callMethodWithArgs(
        reference.pointer,
        _asReadOnlyBufferId,
        JniCallType.objectType, []).object);
  }

  static final _getId =
      Jni.accessors.getMethodIDOf(_class.reference.pointer, r"get", r"()B");

  /// Reads the byte at this buffer's current [position], and then increments the
  /// [position].
  ///
  /// Throws:
  ///  * [BufferOverflowException] - If the buffer's current [position] is not
  ///    smaller than its [limit]
  int get nextByte {
    return Jni.accessors.callMethodWithArgs(
        reference.pointer, _getId, JniCallType.byteType, []).byte;
  }

  static final _putId = Jni.accessors.getMethodIDOf(
      _class.reference.pointer, r"put", r"(B)Ljava/nio/ByteBuffer;");

  /// Writes the given byte into this buffer at the current [position], and then
  /// increments the [position].
  ///
  /// Throws:
  /// * [BufferOverflowException] - If this buffer's current [position] is not
  ///   smaller than its [limit]
  /// * [ReadOnlyBufferException] - If this buffer is read-only
  set nextByte(int b) {
    Jni.env.DeleteGlobalRef(Jni.accessors.callMethodWithArgs(reference.pointer,
        _putId, JniCallType.objectType, [JValueByte(b)]).object);
  }

  static final _arrayId =
      Jni.accessors.getMethodIDOf(_class.reference.pointer, r"array", r"()[B");

  @override
  JArray<jbyte> get array {
    return const JArrayType(jbyteType()).fromRef(Jni.accessors
        .callMethodWithArgs(
            reference.pointer, _arrayId, JniCallType.objectType, []).object);
  }

  void _ensureIsDirect() {
    if (!isDirect) {
      throw StateError(
        'The buffer must be created with `JByteBuffer.allocateDirect`.',
      );
    }
  }

  Pointer<Void> _directBufferAddress() {
    final address = Jni.env.GetDirectBufferAddress(reference.pointer);
    if (address == nullptr) {
      throw StateError(
        'The memory region is undefined or '
        'direct buffer access is not supported by this JVM.',
      );
    }
    return address;
  }

  int _directBufferCapacity() {
    final capacity = Jni.env.GetDirectBufferCapacity(reference.pointer);
    if (capacity == -1) {
      throw StateError(
        'The object is an unaligned view buffer and the processor '
        'architecture does not support unaligned access.',
      );
    }
    return capacity;
  }

  Uint8List _asUint8ListUnsafe() {
    _ensureIsDirect();
    final address = _directBufferAddress();
    final capacity = _directBufferCapacity();
    return address.cast<Uint8>().asTypedList(capacity);
  }

  /// Returns this byte buffer as a [Uint8List].
  ///
  /// If [releaseOriginal] is `true`, this byte buffer will be released.
  ///
  /// Throws [StateError] if the buffer is not direct
  /// (see [JByteBuffer.allocateDirect]) or the JVM does not support the direct
  /// buffer operations or the object is an unaligned view buffer and
  /// the processor does not support unaligned access.
  Uint8List asUint8List({bool releaseOriginal = false}) {
    _ensureIsDirect();
    final address = _directBufferAddress();
    final capacity = _directBufferCapacity();
    final token = releaseOriginal
        ? reference.pointer
        : Jni.env.NewGlobalRef(reference.pointer);
    if (releaseOriginal) {
      reference.setAsReleased();
    }
    return address.cast<Uint8>().asTypedList(
          capacity,
          token: token,
          finalizer: Jni.env.ptr.ref.DeleteGlobalRef.cast(),
        );
  }
}

extension Uint8ListToJava on Uint8List {
  /// Creates a [JByteBuffer] from the content of this list.
  ///
  /// The [JByteBuffer] will be allocated using [JByteBuffer.allocateDirect].
  JByteBuffer toJByteBuffer() {
    return JByteBuffer.fromList(this);
  }
}
