// 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.

part of "dart:convert";

/// A sink for converters to efficiently transmit String data.
///
/// Instead of limiting the interface to one non-chunked [String] it accepts
/// partial strings or can be transformed into a byte sink that
/// accepts UTF-8 code units.
///
/// The [StringConversionSink] class provides a default implementation of
/// [add], [asUtf8Sink] and [asStringSink].
abstract mixin class StringConversionSink
    implements ChunkedConversionSink<String> {
  const StringConversionSink();

  factory StringConversionSink.withCallback(void callback(String accumulated)) =
      _StringCallbackSink;
  factory StringConversionSink.from(Sink<String> sink) = _StringAdapterSink;

  /// Creates a new instance wrapping the given [sink].
  ///
  /// Every string that is added to the returned instance is forwarded to
  /// the [sink]. The instance is allowed to buffer and is not required to
  /// forward immediately.
  factory StringConversionSink.fromStringSink(StringSink sink) =
      _StringSinkConversionSink<StringSink>;

  /// Adds the next [chunk] to `this`.
  ///
  /// Adds the substring defined by [start] and [end]-exclusive to `this`.
  ///
  /// If [isLast] is `true` closes `this`.
  void addSlice(String chunk, int start, int end, bool isLast);

  void add(String str) {
    addSlice(str, 0, str.length, false);
  }

  /// Returns `this` as a sink that accepts UTF-8 input.
  ///
  /// If used, this method must be the first and only call to `this`. It
  /// invalidates `this`. All further operations must be performed on the result.
  ByteConversionSink asUtf8Sink(bool allowMalformed) {
    return _Utf8ConversionSink(this, allowMalformed);
  }

  /// Returns `this` as a [ClosableStringSink].
  ///
  /// If used, this method must be the first and only call to `this`. It
  /// invalidates `this`. All further operations must be performed on the result.
  ClosableStringSink asStringSink() {
    return _StringConversionSinkAsStringSinkAdapter(this);
  }
}

/// A [ClosableStringSink] extends the [StringSink] interface by adding a
/// `close` method.
abstract interface class ClosableStringSink implements StringSink {
  /// Creates a new instance combining a [StringSink] [sink] and a callback
  /// [onClose] which is invoked when the returned instance is closed.
  factory ClosableStringSink.fromStringSink(StringSink sink, void onClose()) =
      _ClosableStringSink;

  /// Closes `this` and flushes any outstanding data.
  void close();
}

/// This class wraps an existing [StringSink] and invokes a
/// closure when [close] is invoked.
class _ClosableStringSink implements ClosableStringSink {
  final void Function() _callback;
  final StringSink _sink;

  _ClosableStringSink(this._sink, this._callback);

  void close() {
    _callback();
  }

  void writeCharCode(int charCode) {
    _sink.writeCharCode(charCode);
  }

  void write(Object? o) {
    _sink.write(o);
  }

  void writeln([Object? o = ""]) {
    _sink.writeln(o);
  }

  void writeAll(Iterable objects, [String separator = ""]) {
    _sink.writeAll(objects, separator);
  }
}

/// This class wraps an existing [StringConversionSink] and exposes a
/// [ClosableStringSink] interface. The wrapped sink only needs to implement
/// `add` and `close`.
// TODO(floitsch): make this class public?
class _StringConversionSinkAsStringSinkAdapter implements ClosableStringSink {
  static const _MIN_STRING_SIZE = 16;

  final StringBuffer _buffer;
  final StringConversionSink _chunkedSink;

  _StringConversionSinkAsStringSinkAdapter(this._chunkedSink)
    : _buffer = StringBuffer();

  void close() {
    if (_buffer.isNotEmpty) _flush();
    _chunkedSink.close();
  }

  void writeCharCode(int charCode) {
    _buffer.writeCharCode(charCode);
    if (_buffer.length > _MIN_STRING_SIZE) _flush();
  }

  void write(Object? o) {
    if (_buffer.isNotEmpty) _flush();
    _chunkedSink.add(o.toString());
  }

  void writeln([Object? o = ""]) {
    _buffer.writeln(o);
    if (_buffer.length > _MIN_STRING_SIZE) _flush();
  }

  void writeAll(Iterable objects, [String separator = ""]) {
    if (_buffer.isNotEmpty) _flush();
    var iterator = objects.iterator;
    if (!iterator.moveNext()) return;
    if (separator.isEmpty) {
      do {
        _chunkedSink.add(iterator.current.toString());
      } while (iterator.moveNext());
    } else {
      _chunkedSink.add(iterator.current.toString());
      while (iterator.moveNext()) {
        write(separator);
        _chunkedSink.add(iterator.current.toString());
      }
    }
  }

  void _flush() {
    var accumulated = _buffer.toString();
    _buffer.clear();
    _chunkedSink.add(accumulated);
  }
}

/// This class provides a base-class for converters that need to accept String
/// inputs.
typedef StringConversionSinkBase = StringConversionSink;

/// This class provides a mixin for converters that need to accept String
/// inputs.
typedef StringConversionSinkMixin = StringConversionSink;

/// This class is a [StringConversionSink] that wraps a [StringSink].
class _StringSinkConversionSink<TStringSink extends StringSink>
    extends StringConversionSink {
  final TStringSink _stringSink;
  _StringSinkConversionSink(this._stringSink);

  void close() {}

  void addSlice(String str, int start, int end, bool isLast) {
    if (start != 0 || end != str.length) {
      for (var i = start; i < end; i++) {
        _stringSink.writeCharCode(str.codeUnitAt(i));
      }
    } else {
      _stringSink.write(str);
    }
    if (isLast) close();
  }

  void add(String str) {
    _stringSink.write(str);
  }

  ByteConversionSink asUtf8Sink(bool allowMalformed) {
    return _Utf8StringSinkAdapter(this, _stringSink, allowMalformed);
  }

  ClosableStringSink asStringSink() {
    return ClosableStringSink.fromStringSink(_stringSink, close);
  }
}

/// This class accumulates all chunks into one string
/// and invokes a callback when the sink is closed.
///
/// This class can be used to terminate a chunked conversion.
class _StringCallbackSink extends _StringSinkConversionSink<StringBuffer> {
  final void Function(String) _callback;

  _StringCallbackSink(this._callback) : super(StringBuffer());

  void close() {
    var accumulated = _stringSink.toString();
    _stringSink.clear();
    _callback(accumulated);
  }

  ByteConversionSink asUtf8Sink(bool allowMalformed) {
    return _Utf8StringSinkAdapter(this, _stringSink, allowMalformed);
  }
}

/// This class adapts a simple [ChunkedConversionSink] to a
/// [StringConversionSink].
///
/// All additional methods of the [StringConversionSink] (compared to the
/// ChunkedConversionSink) are redirected to the `add` method.
class _StringAdapterSink extends StringConversionSink {
  final Sink<String> _sink;

  _StringAdapterSink(this._sink);

  void add(String str) {
    _sink.add(str);
  }

  void addSlice(String str, int start, int end, bool isLast) {
    if (start == 0 && end == str.length) {
      add(str);
    } else {
      add(str.substring(start, end));
    }
    if (isLast) close();
  }

  void close() {
    _sink.close();
  }
}

/// Decodes UTF-8 code units and stores them in a [StringSink].
///
/// The `Sink` provided is closed when this sink is closed.
class _Utf8StringSinkAdapter extends ByteConversionSink {
  final _Utf8Decoder _decoder;
  final Sink<Object?> _sink;
  final StringSink _stringSink;

  _Utf8StringSinkAdapter(this._sink, this._stringSink, bool allowMalformed)
    : _decoder = _Utf8Decoder(allowMalformed);

  void close() {
    _decoder.flush(_stringSink);
    _sink.close();
  }

  void add(List<int> chunk) {
    addSlice(chunk, 0, chunk.length, false);
  }

  void addSlice(
    List<int> codeUnits,
    int startIndex,
    int endIndex,
    bool isLast,
  ) {
    _stringSink.write(_decoder.convertChunked(codeUnits, startIndex, endIndex));
    if (isLast) close();
  }
}

/// Decodes UTF-8 code units.
///
/// Forwards the decoded strings to the given [StringConversionSink].
// TODO(floitsch): make this class public?
class _Utf8ConversionSink extends ByteConversionSink {
  final _Utf8Decoder _decoder;
  final StringConversionSink _chunkedSink;
  final StringBuffer _buffer;
  _Utf8ConversionSink(StringConversionSink sink, bool allowMalformed)
    : this._(sink, StringBuffer(), allowMalformed);

  _Utf8ConversionSink._(
    this._chunkedSink,
    StringBuffer stringBuffer,
    bool allowMalformed,
  ) : _decoder = _Utf8Decoder(allowMalformed),
      _buffer = stringBuffer;

  void close() {
    _decoder.flush(_buffer);
    if (_buffer.isNotEmpty) {
      var accumulated = _buffer.toString();
      _buffer.clear();
      _chunkedSink.addSlice(accumulated, 0, accumulated.length, true);
    } else {
      _chunkedSink.close();
    }
  }

  void add(List<int> chunk) {
    addSlice(chunk, 0, chunk.length, false);
  }

  void addSlice(List<int> chunk, int startIndex, int endIndex, bool isLast) {
    _buffer.write(_decoder.convertChunked(chunk, startIndex, endIndex));
    if (_buffer.isNotEmpty) {
      var accumulated = _buffer.toString();
      _chunkedSink.addSlice(accumulated, 0, accumulated.length, isLast);
      _buffer.clear();
      return;
    }
    if (isLast) close();
  }
}
