// Copyright 2014 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 COMPONENTS_DOMAIN_RELIABILITY_CONTEXT_H_
#define COMPONENTS_DOMAIN_RELIABILITY_CONTEXT_H_

#include <deque>
#include <vector>

#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "components/domain_reliability/config.h"
#include "components/domain_reliability/domain_reliability_export.h"
#include "components/domain_reliability/scheduler.h"

class GURL;

namespace domain_reliability {

struct DomainReliabilityBeacon;
class DomainReliabilityDispatcher;
class DomainReliabilityUploader;
class MockableTime;

// The per-domain context for the Domain Reliability client; includes the
// domain's config and per-resource beacon queues.
class DOMAIN_RELIABILITY_EXPORT DomainReliabilityContext {
 public:
  DomainReliabilityContext(
      MockableTime* time,
      const DomainReliabilityScheduler::Params& scheduler_params,
      const std::string& upload_reporter_string,
      DomainReliabilityDispatcher* dispatcher,
      DomainReliabilityUploader* uploader,
      scoped_ptr<const DomainReliabilityConfig> config);
  ~DomainReliabilityContext();

  // Notifies the context of a beacon on its domain(s); may or may not save the
  // actual beacon to be uploaded, depending on the sample rates in the config,
  // but will increment one of the request counters in any case.
  void OnBeacon(const GURL& url, const DomainReliabilityBeacon& beacon);

  // Called to clear browsing data, since beacons are like browsing history.
  void ClearBeacons();

  void GetQueuedDataForTesting(
      size_t resource_index,
      std::vector<DomainReliabilityBeacon>* beacons_out,
      uint32* successful_requests_out,
      uint32* failed_requests_out) const;

  const DomainReliabilityConfig& config() const { return *config_.get(); }

  // Maximum number of beacons queued per context; if more than this many are
  // queued; the oldest beacons will be removed.
  static const size_t kMaxQueuedBeacons;

 private:
  class ResourceState;

  typedef ScopedVector<ResourceState> ResourceStateVector;
  typedef ResourceStateVector::const_iterator ResourceStateIterator;

  void InitializeResourceStates();
  void ScheduleUpload(base::TimeDelta min_delay, base::TimeDelta max_delay);
  void StartUpload();
  void OnUploadComplete(bool success);

  scoped_ptr<const base::Value> CreateReport(base::TimeTicks upload_time) const;

  // Remembers the current state of the context when an upload starts. Can be
  // called multiple times in a row (without |CommitUpload|) if uploads fail
  // and are retried.
  void MarkUpload();

  // Uses the state remembered by |MarkUpload| to remove successfully uploaded
  // data but keep beacons and request counts added after the upload started.
  // N.B.: There is no equivalent "RollbackUpload" that needs to be called on a
  // failed upload.
  void CommitUpload();

  // Finds and removes the oldest beacon. DCHECKs if there is none. (Called
  // when there are too many beacons queued.)
  void RemoveOldestBeacon();

  scoped_ptr<const DomainReliabilityConfig> config_;
  MockableTime* time_;
  const std::string& upload_reporter_string_;
  DomainReliabilityScheduler scheduler_;
  DomainReliabilityDispatcher* dispatcher_;
  DomainReliabilityUploader* uploader_;

  // Each ResourceState in |states_| corresponds to the Resource of the same
  // index in the config.
  ResourceStateVector states_;
  size_t beacon_count_;
  size_t uploading_beacon_count_;
  base::TimeTicks upload_time_;
  base::TimeTicks last_upload_time_;

  base::WeakPtrFactory<DomainReliabilityContext> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(DomainReliabilityContext);
};

}  // namespace domain_reliability

#endif  // COMPONENTS_DOMAIN_RELIABILITY_CONTEXT_H_