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

/**
 * An instance of the default implementation of the [Latin1Codec].
 *
 * This instance provides a convenient access to the most common ISO Latin 1
 * use cases.
 *
 * Examples:
 *
 *     var encoded = LATIN1.encode("blåbærgrød");
 *     var decoded = LATIN1.decode([0x62, 0x6c, 0xe5, 0x62, 0xe6,
 *                                  0x72, 0x67, 0x72, 0xf8, 0x64]);
 */
const Latin1Codec LATIN1 = const Latin1Codec();

const int _LATIN1_MASK = 0xFF;

/**
 * A [LatinCodec] encodes strings to ISO Latin-1 (aka ISO-8859-1) bytes
 * and decodes Latin-1 bytes to strings.
 */
class Latin1Codec extends Encoding {
  final bool _allowInvalid;
  /**
   * Instantiates a new [Latin1Codec].
   *
   * If [allowInvalid] is true, the [decode] method and the converter
   * returned by [decoder] will default to allowing invalid values. Invalid
   * values are decoded into the Unicode Replacement character (U+FFFD).
   * Calls to the [decode] method can override this default.
   *
   * Encoders will not accept invalid (non Latin-1) characters.
   */
  const Latin1Codec({bool allowInvalid: false}) : _allowInvalid = allowInvalid;

  String get name => "iso-8859-1";

  /**
   * Decodes the Latin-1 [bytes] (a list of unsigned 8-bit integers) to the
   * corresponding string.
   *
   * If [bytes] contains values that are not in the range 0 .. 255, the decoder
   * will eventually throw a [FormatException].
   *
   * If [allowInvalid] is not provided, it defaults to the value used to create
   * this [Latin1Codec].
   */
  String decode(List<int> bytes, { bool allowInvalid }) {
    if (allowInvalid == null) allowInvalid = _allowInvalid;
    if (allowInvalid) {
      return const Latin1Decoder(allowInvalid: true).convert(bytes);
    } else {
      return const Latin1Decoder(allowInvalid: false).convert(bytes);
    }
  }

  Latin1Encoder get encoder => const Latin1Encoder();

  Latin1Decoder get decoder =>
      _allowInvalid ? const Latin1Decoder(allowInvalid: true)
                    : const Latin1Decoder(allowInvalid: false);
}

/**
 * This class converts strings of only ISO Latin-1 characters to bytes.
 */
class Latin1Encoder extends _UnicodeSubsetEncoder {
  const Latin1Encoder() : super(_LATIN1_MASK);
}

/**
 * This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
 * to a string.
 */
class Latin1Decoder extends _UnicodeSubsetDecoder {
  /**
   * Instantiates a new [Latin1Decoder].
   *
   * The optional [allowInvalid] argument defines how [convert] deals
   * with invalid bytes.
   *
   * If it is `true`, [convert] replaces invalid bytes with the Unicode
   * Replacement character `U+FFFD` (�).
   * Otherwise it throws a [FormatException].
   */
  const Latin1Decoder({ bool allowInvalid: false })
      : super(allowInvalid, _LATIN1_MASK);

  /**
   * Starts a chunked conversion.
   *
   * The converter works more efficiently if the given [sink] is a
   * [StringConversionSink].
   */
  ByteConversionSink startChunkedConversion(Sink<String> sink) {
    StringConversionSink stringSink;
    if (sink is StringConversionSink) {
      stringSink = sink;
    } else {
      stringSink = new StringConversionSink.from(sink);
    }
    // TODO(lrn): Use stringSink.asUtf16Sink() if it becomes available.
    if (!_allowInvalid) return new _Latin1DecoderSink(stringSink);
    return new _Latin1AllowInvalidDecoderSink(stringSink);
  }
}

class _Latin1DecoderSink extends ByteConversionSinkBase {
  StringConversionSink _sink;
  _Latin1DecoderSink(this._sink);

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

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

  void _addSliceToSink(List<int> source, int start, int end, bool isLast) {
    // If _sink was a UTF-16 conversion sink, just add the slice directly with
    // _sink.addSlice(source, start, end, isLast).
    // The code below is an moderately stupid workaround until a real
    // solution can be made.
    _sink.add(new String.fromCharCodes(source, start, end));
    if (isLast) close();
  }

  void addSlice(List<int> source, int start, int end, bool isLast) {
    end = RangeError.checkValidRange(start, end, source.length);
    if (start == end) return;
    if (source is! Uint8List) {
      // List may contain value outside of the 0..255 range. If so, throw.
      // Technically, we could excuse Uint8ClampedList as well, but it unlikely
      // to be relevant.
      _checkValidLatin1(source, start, end);
    }
    _addSliceToSink(source, start, end, isLast);
  }

  static void _checkValidLatin1(List<int> source, int start, int end) {
    int mask = 0;
    for (int i = start; i < end; i++) {
      mask |= source[i];
    }
    if (mask >= 0 && mask <= _LATIN1_MASK) {
      return;
    }
    _reportInvalidLatin1(source, start, end);  // Always throws.
  }


  static void _reportInvalidLatin1(List<int> source, int start, int end) {
    // Find the index of the first non-Latin-1 character code.
    for (int i = start; i < end; i++) {
      int char = source[i];
      if (char < 0 || char > _LATIN1_MASK) {
        throw new FormatException("Source contains non-Latin-1 characters.",
                                  source, i);
      }
    }
    // Unreachable - we only call the function if the loop above throws.
    assert(false);
  }
}

class _Latin1AllowInvalidDecoderSink extends _Latin1DecoderSink {
  _Latin1AllowInvalidDecoderSink(StringConversionSink sink): super(sink);

  void addSlice(List<int> source, int start, int end, bool isLast) {
    RangeError.checkValidRange(start, end, source.length);
    for (int i = start; i < end; i++) {
      int char = source[i];
      if (char > _LATIN1_MASK || char < 0) {
        if (i > start) _addSliceToSink(source, start, i, false);
        // Add UTF-8 encoding of U+FFFD.
        _addSliceToSink(const[0xFFFD], 0, 1, false);
        start = i + 1;
      }
    }
    if (start < end) {
      _addSliceToSink(source, start, end, isLast);
    }
    if (isLast) {
      close();
    }
  }
}
