// Copyright (c) 2011 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_resolution/mock_proxy_resolver.h"

#include <utility>

#include "base/logging.h"

namespace net {

MockAsyncProxyResolver::RequestImpl::RequestImpl(std::unique_ptr<Job> job)
    : job_(std::move(job)) {
  DCHECK(job_);
}

MockAsyncProxyResolver::RequestImpl::~RequestImpl() {
  MockAsyncProxyResolver* resolver = job_->Resolver();
  // AddCancelledJob will check if request is already cancelled
  resolver->AddCancelledJob(std::move(job_));
}

LoadState MockAsyncProxyResolver::RequestImpl::GetLoadState() {
  return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
}

MockAsyncProxyResolver::Job::Job(MockAsyncProxyResolver* resolver,
                                 const GURL& url,
                                 ProxyInfo* results,
                                 CompletionOnceCallback callback)
    : resolver_(resolver),
      url_(url),
      results_(results),
      callback_(std::move(callback)) {}

MockAsyncProxyResolver::Job::~Job() = default;

void MockAsyncProxyResolver::Job::CompleteNow(int rv) {
  CompletionOnceCallback callback = std::move(callback_);

  resolver_->RemovePendingJob(this);

  std::move(callback).Run(rv);
}

MockAsyncProxyResolver::~MockAsyncProxyResolver() = default;

int MockAsyncProxyResolver::GetProxyForURL(
    const GURL& url,
    const NetworkIsolationKey& network_isolation_key,
    ProxyInfo* results,
    CompletionOnceCallback callback,
    std::unique_ptr<Request>* request,
    const NetLogWithSource& /*net_log*/) {
  std::unique_ptr<Job> job(new Job(this, url, results, std::move(callback)));

  pending_jobs_.push_back(job.get());
  request->reset(new RequestImpl(std::move(job)));

  // Test code completes the request by calling job->CompleteNow().
  return ERR_IO_PENDING;
}

void MockAsyncProxyResolver::AddCancelledJob(std::unique_ptr<Job> job) {
  auto it = std::find(pending_jobs_.begin(), pending_jobs_.end(), job.get());
  // Because this is called always when RequestImpl is destructed,
  // we need to check if it is still in pending jobs.
  if (it != pending_jobs_.end()) {
    cancelled_jobs_.push_back(std::move(job));
    pending_jobs_.erase(it);
  }
}

void MockAsyncProxyResolver::RemovePendingJob(Job* job) {
  DCHECK(job);
  auto it = std::find(pending_jobs_.begin(), pending_jobs_.end(), job);
  DCHECK(it != pending_jobs_.end());
  pending_jobs_.erase(it);
}

MockAsyncProxyResolver::MockAsyncProxyResolver() = default;

MockAsyncProxyResolverFactory::Request::Request(
    MockAsyncProxyResolverFactory* factory,
    const scoped_refptr<PacFileData>& script_data,
    std::unique_ptr<ProxyResolver>* resolver,
    CompletionOnceCallback callback)
    : factory_(factory),
      script_data_(script_data),
      resolver_(resolver),
      callback_(std::move(callback)) {}

MockAsyncProxyResolverFactory::Request::~Request() = default;

void MockAsyncProxyResolverFactory::Request::CompleteNow(
    int rv,
    std::unique_ptr<ProxyResolver> resolver) {
  *resolver_ = std::move(resolver);

  // RemovePendingRequest may remove the last external reference to |this|.
  scoped_refptr<MockAsyncProxyResolverFactory::Request> keep_alive(this);
  factory_->RemovePendingRequest(this);
  factory_ = nullptr;
  std::move(callback_).Run(rv);
}

void MockAsyncProxyResolverFactory::Request::CompleteNowWithForwarder(
    int rv,
    ProxyResolver* resolver) {
  DCHECK(resolver);
  CompleteNow(rv, std::make_unique<ForwardingProxyResolver>(resolver));
}

void MockAsyncProxyResolverFactory::Request::FactoryDestroyed() {
  factory_ = nullptr;
}

class MockAsyncProxyResolverFactory::Job
    : public ProxyResolverFactory::Request {
 public:
  explicit Job(
      const scoped_refptr<MockAsyncProxyResolverFactory::Request>& request)
      : request_(request) {}
  ~Job() override {
    if (request_->factory_) {
      request_->factory_->cancelled_requests_.push_back(request_);
      request_->factory_->RemovePendingRequest(request_.get());
    }
  }

 private:
  scoped_refptr<MockAsyncProxyResolverFactory::Request> request_;
};

MockAsyncProxyResolverFactory::MockAsyncProxyResolverFactory(
    bool resolvers_expect_pac_bytes)
    : ProxyResolverFactory(resolvers_expect_pac_bytes) {
}

int MockAsyncProxyResolverFactory::CreateProxyResolver(
    const scoped_refptr<PacFileData>& pac_script,
    std::unique_ptr<ProxyResolver>* resolver,
    CompletionOnceCallback callback,
    std::unique_ptr<ProxyResolverFactory::Request>* request_handle) {
  scoped_refptr<Request> request =
      new Request(this, pac_script, resolver, std::move(callback));
  pending_requests_.push_back(request);

  request_handle->reset(new Job(request));

  // Test code completes the request by calling request->CompleteNow().
  return ERR_IO_PENDING;
}

void MockAsyncProxyResolverFactory::RemovePendingRequest(Request* request) {
  auto it =
      std::find(pending_requests_.begin(), pending_requests_.end(), request);
  DCHECK(it != pending_requests_.end());
  pending_requests_.erase(it);
}

MockAsyncProxyResolverFactory::~MockAsyncProxyResolverFactory() {
  for (auto& request : pending_requests_) {
    request->FactoryDestroyed();
  }
}

ForwardingProxyResolver::ForwardingProxyResolver(ProxyResolver* impl)
    : impl_(impl) {
}

int ForwardingProxyResolver::GetProxyForURL(
    const GURL& query_url,
    const NetworkIsolationKey& network_isolation_key,
    ProxyInfo* results,
    CompletionOnceCallback callback,
    std::unique_ptr<Request>* request,
    const NetLogWithSource& net_log) {
  return impl_->GetProxyForURL(query_url, network_isolation_key, results,
                               std::move(callback), request, net_log);
}

}  // namespace net
