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

library request;

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

import 'base_request.dart';
import 'byte_stream.dart';
import 'utils.dart';

/// An HTTP request where the entire request body is known in advance.
class Request extends BaseRequest {
  /// The size of the request body, in bytes. This is calculated from
  /// [bodyBytes].
  ///
  /// The content length cannot be set for [Request], since it's automatically
  /// calculated from [bodyBytes].
  int get contentLength => bodyBytes.length;

  set contentLength(int value) {
    throw new UnsupportedError("Cannot set the contentLength property of "
        "non-streaming Request objects.");
  }

  /// The default encoding to use when converting between [bodyBytes] and
  /// [body]. This is only used if [encoding] hasn't been manually set and if
  /// the content-type header has no encoding information.
  Encoding _defaultEncoding;

  /// The encoding used for the request. This encoding is used when converting
  /// between [bodyBytes] and [body].
  ///
  /// If the request has a `Content-Type` header and that header has a `charset`
  /// parameter, that parameter's value is used as the encoding. Otherwise, if
  /// [encoding] has been set manually, that encoding is used. If that hasn't
  /// been set either, this defaults to [UTF8].
  ///
  /// If the `charset` parameter's value is not a known [Encoding], reading this
  /// will throw a [FormatException].
  ///
  /// If the request has a `Content-Type` header, setting this will set the
  /// charset parameter on that header.
  Encoding get encoding {
    if (_contentType == null || _contentType.charset == null) {
      return _defaultEncoding;
    }
    return requiredEncodingForCharset(_contentType.charset);
  }

  set encoding(Encoding value) {
    _checkFinalized();
    _defaultEncoding = value;
    var contentType = _contentType;
    if (contentType != null) {
      contentType = new ContentType(contentType.primaryType,
                                    contentType.subType,
                                    charset: value.name,
                                    parameters: contentType.parameters);
      _contentType = contentType;
    }
  }

  // TODO(nweiz): make this return a read-only view
  /// The bytes comprising the body of the request. This is converted to and
  /// from [body] using [encoding].
  ///
  /// This list should only be set, not be modified in place.
  Uint8List get bodyBytes => _bodyBytes;
  Uint8List _bodyBytes;

  set bodyBytes(List<int> value) {
    _checkFinalized();
    _bodyBytes = toUint8List(value);
  }

  /// The body of the request as a string. This is converted to and from
  /// [bodyBytes] using [encoding].
  ///
  /// When this is set, if the request does not yet have a `Content-Type`
  /// header, one will be added with the type `text/plain`. Then the `charset`
  /// parameter of the `Content-Type` header (whether new or pre-existing) will
  /// be set to [encoding] if it wasn't already set.
  String get body => encoding.decode(bodyBytes);

  set body(String value) {
    bodyBytes = encoding.encode(value);
    var contentType = _contentType;
    if (contentType == null) {
      contentType = new ContentType("text", "plain", charset: encoding.name);
    } else if (contentType.charset == null) {
      contentType = new ContentType(contentType.primaryType,
                                    contentType.subType,
                                    charset: encoding.name,
                                    parameters: contentType.parameters);
    }
    _contentType = contentType;
  }

  /// The form-encoded fields in the body of the request as a map from field
  /// names to values. The form-encoded body is converted to and from
  /// [bodyBytes] using [encoding] (in the same way as [body]).
  ///
  /// If the request doesn't have a `Content-Type` header of
  /// `application/x-www-form-urlencoded`, reading this will throw a
  /// [StateError].
  ///
  /// If the request has a `Content-Type` header with a type other than
  /// `application/x-www-form-urlencoded`, setting this will throw a
  /// [StateError]. Otherwise, the content type will be set to
  /// `application/x-www-form-urlencoded`.
  ///
  /// This map should only be set, not modified in place.
  Map<String, String> get bodyFields {
    if (_contentType == null ||
        _contentType.value != "application/x-www-form-urlencoded") {
      throw new StateError('Cannot access the body fields of a Request without '
          'content-type "application/x-www-form-urlencoded".');
    }

    return queryToMap(body, encoding: encoding);
  }

  set bodyFields(Map<String, String> fields) {
    if (_contentType == null) {
      _contentType = new ContentType("application", "x-www-form-urlencoded");
    } else if (_contentType.value != "application/x-www-form-urlencoded") {
      throw new StateError('Cannot set the body fields of a Request with '
          'content-type "${_contentType.value}".');
    }

    this.body = mapToQuery(fields, encoding: encoding);
  }

  /// Creates a new HTTP request.
  Request(String method, Uri url)
    : super(method, url),
      _defaultEncoding = UTF8,
      _bodyBytes = new Uint8List(0);

  /// Freezes all mutable fields and returns a single-subscription [ByteStream]
  /// containing the request body.
  ByteStream finalize() {
    super.finalize();
    return new ByteStream.fromBytes(bodyBytes);
  }

  /// The `Content-Type` header of the request (if it exists) as a
  /// [ContentType].
  ContentType get _contentType {
    var contentType = headers[HttpHeaders.CONTENT_TYPE];
    if (contentType == null) return null;
    return ContentType.parse(contentType);
  }

  set _contentType(ContentType value) {
    headers[HttpHeaders.CONTENT_TYPE] = value.toString();
  }

  /// Throw an error if this request has been finalized.
  void _checkFinalized() {
    if (!finalized) return;
    throw new StateError("Can't modify a finalized Request.");
  }
}
