// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/spdy/spdy_stream_test_util.h"

#include <cstddef>
#include <utility>

#include "base/stl_util.h"
#include "net/base/completion_callback.h"
#include "net/spdy/spdy_stream.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net {

namespace test {

ClosingDelegate::ClosingDelegate(
    const base::WeakPtr<SpdyStream>& stream) : stream_(stream) {
  DCHECK(stream_);
}

ClosingDelegate::~ClosingDelegate() {}

void ClosingDelegate::OnRequestHeadersSent() {}

SpdyResponseHeadersStatus ClosingDelegate::OnResponseHeadersUpdated(
    const SpdyHeaderBlock& response_headers) {
  return RESPONSE_HEADERS_ARE_COMPLETE;
}

void ClosingDelegate::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) {}

void ClosingDelegate::OnDataSent() {}

void ClosingDelegate::OnTrailers(const SpdyHeaderBlock& trailers) {}

void ClosingDelegate::OnClose(int status) {
  DCHECK(stream_);
  stream_->Close();
  // The |stream_| may still be alive (if it is our delegate).
}

StreamDelegateBase::StreamDelegateBase(
    const base::WeakPtr<SpdyStream>& stream)
    : stream_(stream),
      stream_id_(0),
      send_headers_completed_(false) {
}

StreamDelegateBase::~StreamDelegateBase() {
}

void StreamDelegateBase::OnRequestHeadersSent() {
  stream_id_ = stream_->stream_id();
  EXPECT_NE(stream_id_, 0u);
  send_headers_completed_ = true;
}

SpdyResponseHeadersStatus StreamDelegateBase::OnResponseHeadersUpdated(
    const SpdyHeaderBlock& response_headers) {
  EXPECT_EQ(stream_->type() != SPDY_PUSH_STREAM, send_headers_completed_);
  response_headers_ = response_headers;
  return RESPONSE_HEADERS_ARE_COMPLETE;
}

void StreamDelegateBase::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) {
  if (buffer)
    received_data_queue_.Enqueue(std::move(buffer));
}

void StreamDelegateBase::OnDataSent() {}

void StreamDelegateBase::OnTrailers(const SpdyHeaderBlock& trailers) {}

void StreamDelegateBase::OnClose(int status) {
  if (!stream_.get())
    return;
  stream_id_ = stream_->stream_id();
  stream_.reset();
  callback_.callback().Run(status);
}

int StreamDelegateBase::WaitForClose() {
  int result = callback_.WaitForResult();
  EXPECT_TRUE(!stream_.get());
  return result;
}

std::string StreamDelegateBase::TakeReceivedData() {
  size_t len = received_data_queue_.GetTotalSize();
  std::string received_data(len, '\0');
  if (len > 0) {
    EXPECT_EQ(
        len,
        received_data_queue_.Dequeue(string_as_array(&received_data), len));
  }
  return received_data;
}

std::string StreamDelegateBase::GetResponseHeaderValue(
    const std::string& name) const {
  SpdyHeaderBlock::const_iterator it = response_headers_.find(name);
  return (it == response_headers_.end()) ? std::string()
                                         : it->second.as_string();
}

StreamDelegateDoNothing::StreamDelegateDoNothing(
    const base::WeakPtr<SpdyStream>& stream)
    : StreamDelegateBase(stream) {}

StreamDelegateDoNothing::~StreamDelegateDoNothing() {
}

StreamDelegateSendImmediate::StreamDelegateSendImmediate(
    const base::WeakPtr<SpdyStream>& stream,
    base::StringPiece data)
    : StreamDelegateBase(stream),
      data_(data) {}

StreamDelegateSendImmediate::~StreamDelegateSendImmediate() {
}

SpdyResponseHeadersStatus StreamDelegateSendImmediate::OnResponseHeadersUpdated(
    const SpdyHeaderBlock& response_headers) {
  SpdyResponseHeadersStatus status =
      StreamDelegateBase::OnResponseHeadersUpdated(response_headers);
  if (data_.data()) {
    scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(data_.as_string()));
    stream()->SendData(buf.get(), buf->size(), MORE_DATA_TO_SEND);
  }
  return status;
}

StreamDelegateWithBody::StreamDelegateWithBody(
    const base::WeakPtr<SpdyStream>& stream,
    base::StringPiece data)
    : StreamDelegateBase(stream),
      buf_(new StringIOBuffer(data.as_string())) {}

StreamDelegateWithBody::~StreamDelegateWithBody() {
}

void StreamDelegateWithBody::OnRequestHeadersSent() {
  StreamDelegateBase::OnRequestHeadersSent();
  stream()->SendData(buf_.get(), buf_->size(), NO_MORE_DATA_TO_SEND);
}

StreamDelegateCloseOnHeaders::StreamDelegateCloseOnHeaders(
    const base::WeakPtr<SpdyStream>& stream)
    : StreamDelegateBase(stream) {
}

StreamDelegateCloseOnHeaders::~StreamDelegateCloseOnHeaders() {
}

SpdyResponseHeadersStatus
StreamDelegateCloseOnHeaders::OnResponseHeadersUpdated(
    const SpdyHeaderBlock& response_headers) {
  stream()->Cancel();
  return RESPONSE_HEADERS_ARE_COMPLETE;
}

} // namespace test

} // namespace net
