// 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/base/elements_upload_data_stream.h"

#include "base/bind.h"
#include "base/logging.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_element_reader.h"

namespace net {

ElementsUploadDataStream::ElementsUploadDataStream(
    ScopedVector<UploadElementReader> element_readers,
    int64 identifier)
    : UploadDataStream(false, identifier),
      element_readers_(element_readers.Pass()),
      element_index_(0),
      read_failed_(false),
      weak_ptr_factory_(this) {
}

ElementsUploadDataStream::~ElementsUploadDataStream() {
}

scoped_ptr<UploadDataStream> ElementsUploadDataStream::CreateWithReader(
    scoped_ptr<UploadElementReader> reader,
    int64 identifier) {
  ScopedVector<UploadElementReader> readers;
  readers.push_back(reader.release());
  return scoped_ptr<UploadDataStream>(
      new ElementsUploadDataStream(readers.Pass(), identifier));
}

int ElementsUploadDataStream::InitInternal() {
  return InitElements(0);
}

int ElementsUploadDataStream::ReadInternal(
    IOBuffer* buf,
    int buf_len) {
  DCHECK_GT(buf_len, 0);
  return ReadElements(new DrainableIOBuffer(buf, buf_len));
}

bool ElementsUploadDataStream::IsInMemory() const {
  for (size_t i = 0; i < element_readers_.size(); ++i) {
    if (!element_readers_[i]->IsInMemory())
      return false;
  }
  return true;
}

const ScopedVector<UploadElementReader>*
ElementsUploadDataStream::GetElementReaders() const {
  return &element_readers_;
}

void ElementsUploadDataStream::ResetInternal() {
  weak_ptr_factory_.InvalidateWeakPtrs();
  read_failed_ = false;
  element_index_ = 0;
}

int ElementsUploadDataStream::InitElements(size_t start_index) {
  // Call Init() for all elements.
  for (size_t i = start_index; i < element_readers_.size(); ++i) {
    UploadElementReader* reader = element_readers_[i];
    // When new_result is ERR_IO_PENDING, InitInternal() will be called
    // with start_index == i + 1 when reader->Init() finishes.
    int result = reader->Init(
        base::Bind(&ElementsUploadDataStream::OnInitElementCompleted,
                   weak_ptr_factory_.GetWeakPtr(),
                   i));
    DCHECK(result != ERR_IO_PENDING || !reader->IsInMemory());
    DCHECK_LE(result, OK);
    if (result != OK)
      return result;
  }

  uint64 total_size = 0;
  for (size_t i = 0; i < element_readers_.size(); ++i) {
    total_size += element_readers_[i]->GetContentLength();
  }
  SetSize(total_size);
  return OK;
}

void ElementsUploadDataStream::OnInitElementCompleted(size_t index,
                                                      int result) {
  DCHECK_NE(ERR_IO_PENDING, result);

  // Check the last result.
  if (result == OK)
    result = InitElements(index + 1);

  if (result != ERR_IO_PENDING)
    OnInitCompleted(result);
}

int ElementsUploadDataStream::ReadElements(
    const scoped_refptr<DrainableIOBuffer>& buf) {
  while (!read_failed_ && element_index_ < element_readers_.size()) {
    UploadElementReader* reader = element_readers_[element_index_];

    if (reader->BytesRemaining() == 0) {
      ++element_index_;
      continue;
    }

    if (buf->BytesRemaining() == 0)
      break;

    int result = reader->Read(
        buf.get(),
        buf->BytesRemaining(),
        base::Bind(&ElementsUploadDataStream::OnReadElementCompleted,
                   weak_ptr_factory_.GetWeakPtr(),
                   buf));
    if (result == ERR_IO_PENDING)
      return ERR_IO_PENDING;
    ProcessReadResult(buf, result);
  }

  if (read_failed_) {
    // If an error occured during read operation, then pad with zero.
    // Otherwise the server will hang waiting for the rest of the data.
    int num_bytes_to_fill = static_cast<int>(std::min(
        static_cast<uint64>(buf->BytesRemaining()),
        size() - position() - buf->BytesConsumed()));
    DCHECK_GE(num_bytes_to_fill, 0);
    memset(buf->data(), 0, num_bytes_to_fill);
    buf->DidConsume(num_bytes_to_fill);
  }

  return buf->BytesConsumed();
}

void ElementsUploadDataStream::OnReadElementCompleted(
    const scoped_refptr<DrainableIOBuffer>& buf,
    int result) {
  ProcessReadResult(buf, result);

  result = ReadElements(buf);
  if (result != ERR_IO_PENDING)
    OnReadCompleted(result);
}

void ElementsUploadDataStream::ProcessReadResult(
    const scoped_refptr<DrainableIOBuffer>& buf,
    int result) {
  DCHECK_NE(ERR_IO_PENDING, result);
  DCHECK(!read_failed_);

  if (result >= 0) {
    buf->DidConsume(result);
  } else {
    read_failed_ = true;
  }
}

}  // namespace net
