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

#ifndef EXTENSIONS_BROWSER_UPDATER_REQUEST_QUEUE_IMPL_H_
#define EXTENSIONS_BROWSER_UPDATER_REQUEST_QUEUE_IMPL_H_

#include <stddef.h>

#include <algorithm>
#include <utility>

#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "extensions/browser/updater/request_queue.h"

namespace extensions {

template <typename T>
RequestQueue<T>::RequestQueue(
    const net::BackoffEntry::Policy* const backoff_policy,
    const base::Closure& start_request_callback)
    : backoff_policy_(backoff_policy),
      start_request_callback_(start_request_callback),
      timer_(false, false) {
}

template <typename T>
RequestQueue<T>::~RequestQueue() {
}

template <typename T>
T* RequestQueue<T>::active_request() {
  return active_request_.get();
}

template <typename T>
int RequestQueue<T>::active_request_failure_count() {
  return active_backoff_entry_->failure_count();
}

template <typename T>
scoped_ptr<T> RequestQueue<T>::reset_active_request() {
  active_backoff_entry_.reset();
  return std::move(active_request_);
}

template <typename T>
void RequestQueue<T>::ScheduleRequest(scoped_ptr<T> request) {
  PushImpl(std::move(request), scoped_ptr<net::BackoffEntry>(
                                   new net::BackoffEntry(backoff_policy_)));
  StartNextRequest();
}

template <typename T>
void RequestQueue<T>::PushImpl(scoped_ptr<T> request,
                               scoped_ptr<net::BackoffEntry> backoff_entry) {
  pending_requests_.push_back(
      Request(backoff_entry.release(), request.release()));
  std::push_heap(
      pending_requests_.begin(), pending_requests_.end(), CompareRequests);
}

template <typename T>
bool RequestQueue<T>::empty() const {
  return pending_requests_.empty();
}

template <typename T>
size_t RequestQueue<T>::size() const {
  return pending_requests_.size();
}

template <typename T>
base::TimeTicks RequestQueue<T>::NextReleaseTime() const {
  return pending_requests_.front().backoff_entry->GetReleaseTime();
}

template <typename T>
void RequestQueue<T>::StartNextRequest() {
  if (active_request_)
    // Already running a request, assume this method will be called again when
    // the request is done.
    return;

  if (empty())
    // No requests in the queue, so we're done.
    return;

  base::TimeTicks next_release = NextReleaseTime();
  base::TimeTicks now = base::TimeTicks::Now();
  if (next_release > now) {
    // Not ready for the next update check yet, call this method when it is
    // time.
    timer_.Start(
        FROM_HERE,
        next_release - now,
        base::Bind(&RequestQueue<T>::StartNextRequest, base::Unretained(this)));
    return;
  }

  // pop_heap swaps the first and last elements of pending_requests_, and after
  // that assures that the rest of pending_requests_ (excluding the
  // now last/formerly first element) forms a proper heap. After pop_heap
  // [begin, end-1) is a valid heap, and *(end - 1) contains the element that
  // used to be at the top of the heap. Since no elements are actually
  // removed from the container it is safe to read the entry being removed after
  // pop_heap is called (but before pop_back is called).
  std::pop_heap(
      pending_requests_.begin(), pending_requests_.end(), CompareRequests);

  active_backoff_entry_.reset(pending_requests_.back().backoff_entry.release());
  active_request_.reset(pending_requests_.back().request.release());

  pending_requests_.pop_back();

  start_request_callback_.Run();
}

template <typename T>
void RequestQueue<T>::RetryRequest(const base::TimeDelta& min_backoff_delay) {
  active_backoff_entry_->InformOfRequest(false);
  if (active_backoff_entry_->GetTimeUntilRelease() < min_backoff_delay) {
    active_backoff_entry_->SetCustomReleaseTime(base::TimeTicks::Now() +
                                                min_backoff_delay);
  }
  PushImpl(std::move(active_request_), std::move(active_backoff_entry_));
}

template <typename T>
typename RequestQueue<T>::iterator RequestQueue<T>::begin() {
  return iterator(pending_requests_.begin());
}

template <typename T>
typename RequestQueue<T>::iterator RequestQueue<T>::end() {
  return iterator(pending_requests_.end());
}

template <typename T>
void RequestQueue<T>::set_backoff_policy(
    const net::BackoffEntry::Policy* backoff_policy) {
  backoff_policy_ = backoff_policy;
}

// static
template <typename T>
bool RequestQueue<T>::CompareRequests(const Request& a, const Request& b) {
  return a.backoff_entry->GetReleaseTime() > b.backoff_entry->GetReleaseTime();
}

}  // namespace extensions

#endif  // EXTENSIONS_BROWSER_UPDATER_REQUEST_QUEUE_IMPL_H_
