// 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/proxy/polling_proxy_config_service.h"

#include "base/bind.h"
#include "base/location.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/observer_list.h"
#include "base/profiler/scoped_tracker.h"
#include "base/synchronization/lock.h"
#include "base/threading/worker_pool.h"
#include "net/proxy/proxy_config.h"

namespace net {

// Reference-counted wrapper that does all the work (needs to be
// reference-counted since we post tasks between threads; may outlive
// the parent PollingProxyConfigService).
class PollingProxyConfigService::Core
    : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> {
 public:
  Core(base::TimeDelta poll_interval,
       GetConfigFunction get_config_func)
      : get_config_func_(get_config_func),
        poll_interval_(poll_interval),
        have_initialized_origin_loop_(false),
        has_config_(false),
        poll_task_outstanding_(false),
        poll_task_queued_(false) {
  }

  // Called when the parent PollingProxyConfigService is destroyed
  // (observers should not be called past this point).
  void Orphan() {
    base::AutoLock l(lock_);
    origin_loop_proxy_ = NULL;
  }

  bool GetLatestProxyConfig(ProxyConfig* config) {
    LazyInitializeOriginLoop();
    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());

    OnLazyPoll();

    // If we have already retrieved the proxy settings (on worker thread)
    // then return what we last saw.
    if (has_config_) {
      *config = last_config_;
      return true;
    }
    return false;
  }

  void AddObserver(Observer* observer) {
    LazyInitializeOriginLoop();
    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
    observers_.AddObserver(observer);
  }

  void RemoveObserver(Observer* observer) {
    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
    observers_.RemoveObserver(observer);
  }

  // Check for a new configuration if enough time has elapsed.
  void OnLazyPoll() {
    LazyInitializeOriginLoop();
    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());

    if (last_poll_time_.is_null() ||
        (base::TimeTicks::Now() - last_poll_time_) > poll_interval_) {
      CheckForChangesNow();
    }
  }

  void CheckForChangesNow() {
    LazyInitializeOriginLoop();
    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());

    if (poll_task_outstanding_) {
      // Only allow one task to be outstanding at a time. If we get a poll
      // request while we are busy, we will defer it until the current poll
      // completes.
      poll_task_queued_ = true;
      return;
    }

    last_poll_time_ = base::TimeTicks::Now();
    poll_task_outstanding_ = true;
    poll_task_queued_ = false;
    base::WorkerPool::PostTask(
        FROM_HERE,
        base::Bind(&Core::PollOnWorkerThread, this, get_config_func_),
        true);
  }

 private:
  friend class base::RefCountedThreadSafe<Core>;
  ~Core() {}

  void PollOnWorkerThread(GetConfigFunction func) {
    ProxyConfig config;
    func(&config);

    base::AutoLock l(lock_);
    if (origin_loop_proxy_.get()) {
      origin_loop_proxy_->PostTask(
          FROM_HERE, base::Bind(&Core::GetConfigCompleted, this, config));
    }
  }

  // Called after the worker thread has finished retrieving a configuration.
  void GetConfigCompleted(const ProxyConfig& config) {
    // TODO(pkasting): Remove ScopedTracker below once crbug.com/455942 is
    // fixed.
    tracked_objects::ScopedTracker tracking_profile(
        FROM_HERE_WITH_EXPLICIT_FUNCTION(
            "455942 PollingProxyConfigService::Core::GetConfigCompleted"));
    DCHECK(poll_task_outstanding_);
    poll_task_outstanding_ = false;

    if (!origin_loop_proxy_.get())
      return;  // Was orphaned (parent has already been destroyed).

    DCHECK(origin_loop_proxy_->BelongsToCurrentThread());

    if (!has_config_ || !last_config_.Equals(config)) {
      // If the configuration has changed, notify the observers.
      has_config_ = true;
      last_config_ = config;
      FOR_EACH_OBSERVER(Observer, observers_,
                        OnProxyConfigChanged(config,
                                             ProxyConfigService::CONFIG_VALID));
    }

    if (poll_task_queued_)
      CheckForChangesNow();
  }

  void LazyInitializeOriginLoop() {
    // TODO(eroman): Really this should be done in the constructor, but right
    //               now chrome is constructing the ProxyConfigService on the
    //               UI thread so we can't cache the IO thread for the purpose
    //               of DCHECKs until the first call is made.
    if (!have_initialized_origin_loop_) {
      origin_loop_proxy_ = base::MessageLoopProxy::current();
      have_initialized_origin_loop_ = true;
    }
  }

  GetConfigFunction get_config_func_;
  ObserverList<Observer> observers_;
  ProxyConfig last_config_;
  base::TimeTicks last_poll_time_;
  base::TimeDelta poll_interval_;

  base::Lock lock_;
  scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;

  bool have_initialized_origin_loop_;
  bool has_config_;
  bool poll_task_outstanding_;
  bool poll_task_queued_;
};

void PollingProxyConfigService::AddObserver(Observer* observer) {
  core_->AddObserver(observer);
}

void PollingProxyConfigService::RemoveObserver(Observer* observer) {
  core_->RemoveObserver(observer);
}

ProxyConfigService::ConfigAvailability
    PollingProxyConfigService::GetLatestProxyConfig(ProxyConfig* config) {
  return core_->GetLatestProxyConfig(config) ? CONFIG_VALID : CONFIG_PENDING;
}

void PollingProxyConfigService::OnLazyPoll() {
  core_->OnLazyPoll();
}

PollingProxyConfigService::PollingProxyConfigService(
    base::TimeDelta poll_interval,
    GetConfigFunction get_config_func)
    : core_(new Core(poll_interval, get_config_func)) {
}

PollingProxyConfigService::~PollingProxyConfigService() {
  core_->Orphan();
}

void PollingProxyConfigService::CheckForChangesNow() {
  core_->CheckForChangesNow();
}

}  // namespace net
