// Copyright (c) 2014, 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:io';

/// A class that delegates header access and setting to many [HttpHeaders]
/// instances.
class MultiHeaders implements HttpHeaders {
  /// The wrapped headers.
  final Set<HttpHeaders> _headers;

  @override
  bool get chunkedTransferEncoding => _headers.first.chunkedTransferEncoding;
  @override
  set chunkedTransferEncoding(bool value) {
    for (var headers in _headers) {
      headers.chunkedTransferEncoding = value;
    }
  }

  @override
  int get contentLength => _headers.first.contentLength;
  @override
  set contentLength(int value) {
    for (var headers in _headers) {
      headers.contentLength = value;
    }
  }

  @override
  ContentType get contentType => _headers.first.contentType;
  @override
  set contentType(ContentType value) {
    for (var headers in _headers) {
      headers.contentType = value;
    }
  }

  @override
  DateTime get date => _headers.first.date;
  @override
  set date(DateTime value) {
    for (var headers in _headers) {
      headers.date = value;
    }
  }

  @override
  DateTime get expires => _headers.first.expires;
  @override
  set expires(DateTime value) {
    for (var headers in _headers) {
      headers.expires = value;
    }
  }

  @override
  String get host => _headers.first.host;
  @override
  set host(String value) {
    for (var headers in _headers) {
      headers.host = value;
    }
  }

  @override
  DateTime get ifModifiedSince => _headers.first.ifModifiedSince;
  @override
  set ifModifiedSince(DateTime value) {
    for (var headers in _headers) {
      headers.ifModifiedSince = value;
    }
  }

  @override
  bool get persistentConnection => _headers.first.persistentConnection;
  @override
  set persistentConnection(bool value) {
    for (var headers in _headers) {
      headers.persistentConnection = value;
    }
  }

  @override
  int get port => _headers.first.port;
  @override
  set port(int value) {
    for (var headers in _headers) {
      headers.port = value;
    }
  }

  MultiHeaders(Iterable<HttpHeaders> headers) : _headers = headers.toSet();

  @override
  void add(String name, Object value) {
    for (var headers in _headers) {
      headers.add(name, value);
    }
  }

  @override
  void forEach(void Function(String name, List<String> values) f) =>
      _headers.first.forEach(f);

  @override
  void noFolding(String name) {
    for (var headers in _headers) {
      headers.noFolding(name);
    }
  }

  @override
  void remove(String name, Object value) {
    for (var headers in _headers) {
      headers.remove(name, value);
    }
  }

  @override
  void removeAll(String name) {
    for (var headers in _headers) {
      headers.removeAll(name);
    }
  }

  @override
  void set(String name, Object value) {
    for (var headers in _headers) {
      headers.set(name, value);
    }
  }

  @override
  String value(String name) => _headers.first.value(name);

  @override
  List<String> operator [](String name) => _headers.first[name];

  @override
  void clear() {
    for (var headers in _headers) {
      headers.clear();
    }
  }
}
