// Copyright 2013 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 "content/browser/service_worker/embedded_worker_instance.h"

#include <algorithm>
#include <utility>

#include "base/bind_helpers.h"
#include "content/browser/devtools/embedded_worker_devtools_manager.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "ipc/ipc_message.h"
#include "url/gurl.h"

namespace content {

namespace {

// Functor to sort by the .second element of a struct.
struct SecondGreater {
  template <typename Value>
  bool operator()(const Value& lhs, const Value& rhs) {
    return lhs.second > rhs.second;
  }
};

void NotifyWorkerContextStarted(int worker_process_id, int worker_route_id) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        base::Bind(
            NotifyWorkerContextStarted, worker_process_id, worker_route_id));
    return;
  }
  EmbeddedWorkerDevToolsManager::GetInstance()->WorkerContextStarted(
      worker_process_id, worker_route_id);
}

void NotifyWorkerDestroyed(int worker_process_id, int worker_route_id) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        base::Bind(NotifyWorkerDestroyed, worker_process_id, worker_route_id));
    return;
  }
  EmbeddedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
      worker_process_id, worker_route_id);
}

void RegisterToWorkerDevToolsManager(
    int process_id,
    const ServiceWorkerContextCore* const service_worker_context,
    int64 service_worker_version_id,
    const base::Callback<void(int worker_devtools_agent_route_id,
                              bool wait_for_debugger)>& callback) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    BrowserThread::PostTask(BrowserThread::UI,
                            FROM_HERE,
                            base::Bind(RegisterToWorkerDevToolsManager,
                                       process_id,
                                       service_worker_context,
                                       service_worker_version_id,
                                       callback));
    return;
  }
  int worker_devtools_agent_route_id = MSG_ROUTING_NONE;
  bool wait_for_debugger = false;
  if (RenderProcessHost* rph = RenderProcessHost::FromID(process_id)) {
    // |rph| may be NULL in unit tests.
    worker_devtools_agent_route_id = rph->GetNextRoutingID();
    wait_for_debugger =
        EmbeddedWorkerDevToolsManager::GetInstance()->ServiceWorkerCreated(
            process_id,
            worker_devtools_agent_route_id,
            EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier(
                service_worker_context, service_worker_version_id));
  }
  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      base::Bind(callback, worker_devtools_agent_route_id, wait_for_debugger));
}

}  // namespace

EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
  if (status_ == STARTING || status_ == RUNNING)
    Stop();
  if (worker_devtools_agent_route_id_ != MSG_ROUTING_NONE)
    NotifyWorkerDestroyed(process_id_, worker_devtools_agent_route_id_);
  if (context_ && process_id_ != -1)
    context_->process_manager()->ReleaseWorkerProcess(embedded_worker_id_);
  registry_->RemoveWorker(process_id_, embedded_worker_id_);
}

void EmbeddedWorkerInstance::Start(int64 service_worker_version_id,
                                   const GURL& scope,
                                   const GURL& script_url,
                                   bool pause_after_download,
                                   const std::vector<int>& possible_process_ids,
                                   const StatusCallback& callback) {
  if (!context_) {
    callback.Run(SERVICE_WORKER_ERROR_ABORT);
    return;
  }
  DCHECK(status_ == STOPPED);
  status_ = STARTING;
  scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params(
      new EmbeddedWorkerMsg_StartWorker_Params());
  params->embedded_worker_id = embedded_worker_id_;
  params->service_worker_version_id = service_worker_version_id;
  params->scope = scope;
  params->script_url = script_url;
  params->worker_devtools_agent_route_id = MSG_ROUTING_NONE;
  params->pause_after_download = pause_after_download;
  params->wait_for_debugger = false;
  context_->process_manager()->AllocateWorkerProcess(
      embedded_worker_id_,
      SortProcesses(possible_process_ids),
      script_url,
      base::Bind(&EmbeddedWorkerInstance::RunProcessAllocated,
                 weak_factory_.GetWeakPtr(),
                 context_,
                 base::Passed(&params),
                 callback));
}

ServiceWorkerStatusCode EmbeddedWorkerInstance::Stop() {
  DCHECK(status_ == STARTING || status_ == RUNNING);
  ServiceWorkerStatusCode status =
      registry_->StopWorker(process_id_, embedded_worker_id_);
  if (status == SERVICE_WORKER_OK)
    status_ = STOPPING;
  return status;
}

void EmbeddedWorkerInstance::ResumeAfterDownload() {
  DCHECK_EQ(STARTING, status_);
  registry_->Send(
      process_id_,
      new EmbeddedWorkerMsg_ResumeAfterDownload(embedded_worker_id_));
}

ServiceWorkerStatusCode EmbeddedWorkerInstance::SendMessage(
    const IPC::Message& message) {
  DCHECK(status_ == RUNNING);
  return registry_->Send(process_id_,
                         new EmbeddedWorkerContextMsg_MessageToWorker(
                             thread_id_, embedded_worker_id_, message));
}

void EmbeddedWorkerInstance::AddProcessReference(int process_id) {
  ProcessRefMap::iterator found = process_refs_.find(process_id);
  if (found == process_refs_.end())
    found = process_refs_.insert(std::make_pair(process_id, 0)).first;
  ++found->second;
}

void EmbeddedWorkerInstance::ReleaseProcessReference(int process_id) {
  ProcessRefMap::iterator found = process_refs_.find(process_id);
  if (found == process_refs_.end()) {
    NOTREACHED() << "Releasing unknown process ref " << process_id;
    return;
  }
  if (--found->second == 0)
    process_refs_.erase(found);
}

EmbeddedWorkerInstance::EmbeddedWorkerInstance(
    base::WeakPtr<ServiceWorkerContextCore> context,
    int embedded_worker_id)
    : context_(context),
      registry_(context->embedded_worker_registry()),
      embedded_worker_id_(embedded_worker_id),
      status_(STOPPED),
      process_id_(-1),
      thread_id_(-1),
      worker_devtools_agent_route_id_(MSG_ROUTING_NONE),
      weak_factory_(this) {
}

// static
void EmbeddedWorkerInstance::RunProcessAllocated(
    base::WeakPtr<EmbeddedWorkerInstance> instance,
    base::WeakPtr<ServiceWorkerContextCore> context,
    scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
    const EmbeddedWorkerInstance::StatusCallback& callback,
    ServiceWorkerStatusCode status,
    int process_id) {
  if (!context) {
    callback.Run(SERVICE_WORKER_ERROR_ABORT);
    return;
  }
  if (!instance) {
    if (status == SERVICE_WORKER_OK) {
      // We only have a process allocated if the status is OK.
      context->process_manager()->ReleaseWorkerProcess(
          params->embedded_worker_id);
    }
    callback.Run(SERVICE_WORKER_ERROR_ABORT);
    return;
  }
  instance->ProcessAllocated(params.Pass(), callback, process_id, status);
}

void EmbeddedWorkerInstance::ProcessAllocated(
    scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
    const StatusCallback& callback,
    int process_id,
    ServiceWorkerStatusCode status) {
  DCHECK_EQ(process_id_, -1);
  if (status != SERVICE_WORKER_OK) {
    status_ = STOPPED;
    callback.Run(status);
    return;
  }
  const int64 service_worker_version_id = params->service_worker_version_id;
  process_id_ = process_id;
  RegisterToWorkerDevToolsManager(
      process_id,
      context_.get(),
      service_worker_version_id,
      base::Bind(&EmbeddedWorkerInstance::SendStartWorker,
                 weak_factory_.GetWeakPtr(),
                 base::Passed(&params),
                 callback));
}

void EmbeddedWorkerInstance::SendStartWorker(
    scoped_ptr<EmbeddedWorkerMsg_StartWorker_Params> params,
    const StatusCallback& callback,
    int worker_devtools_agent_route_id,
    bool wait_for_debugger) {
  worker_devtools_agent_route_id_ = worker_devtools_agent_route_id;
  params->worker_devtools_agent_route_id = worker_devtools_agent_route_id;
  params->wait_for_debugger = wait_for_debugger;
  registry_->SendStartWorker(params.Pass(), callback, process_id_);
}

void EmbeddedWorkerInstance::OnScriptLoaded() {
  if (worker_devtools_agent_route_id_ != MSG_ROUTING_NONE)
    NotifyWorkerContextStarted(process_id_, worker_devtools_agent_route_id_);
}

void EmbeddedWorkerInstance::OnScriptLoadFailed() {
}

void EmbeddedWorkerInstance::OnStarted(int thread_id) {
  // Stop is requested before OnStarted is sent back from the worker.
  if (status_ == STOPPING)
    return;
  DCHECK(status_ == STARTING);
  status_ = RUNNING;
  thread_id_ = thread_id;
  FOR_EACH_OBSERVER(Listener, listener_list_, OnStarted());
}

void EmbeddedWorkerInstance::OnStopped() {
  if (worker_devtools_agent_route_id_ != MSG_ROUTING_NONE)
    NotifyWorkerDestroyed(process_id_, worker_devtools_agent_route_id_);
  if (context_)
    context_->process_manager()->ReleaseWorkerProcess(embedded_worker_id_);
  status_ = STOPPED;
  process_id_ = -1;
  thread_id_ = -1;
  worker_devtools_agent_route_id_ = MSG_ROUTING_NONE;
  FOR_EACH_OBSERVER(Listener, listener_list_, OnStopped());
}

void EmbeddedWorkerInstance::OnPausedAfterDownload() {
  // Stop can be requested before getting this far.
  if (status_ == STOPPING)
    return;
  DCHECK(status_ == STARTING);
  FOR_EACH_OBSERVER(Listener, listener_list_, OnPausedAfterDownload());
}

bool EmbeddedWorkerInstance::OnMessageReceived(const IPC::Message& message) {
  ListenerList::Iterator it(listener_list_);
  while (Listener* listener = it.GetNext()) {
    if (listener->OnMessageReceived(message))
      return true;
  }
  return false;
}

void EmbeddedWorkerInstance::OnReportException(
    const base::string16& error_message,
    int line_number,
    int column_number,
    const GURL& source_url) {
  FOR_EACH_OBSERVER(
      Listener,
      listener_list_,
      OnReportException(error_message, line_number, column_number, source_url));
}

void EmbeddedWorkerInstance::OnReportConsoleMessage(
    int source_identifier,
    int message_level,
    const base::string16& message,
    int line_number,
    const GURL& source_url) {
  FOR_EACH_OBSERVER(
      Listener,
      listener_list_,
      OnReportConsoleMessage(
          source_identifier, message_level, message, line_number, source_url));
}

void EmbeddedWorkerInstance::AddListener(Listener* listener) {
  listener_list_.AddObserver(listener);
}

void EmbeddedWorkerInstance::RemoveListener(Listener* listener) {
  listener_list_.RemoveObserver(listener);
}

std::vector<int> EmbeddedWorkerInstance::SortProcesses(
    const std::vector<int>& possible_process_ids) const {
  // Add the |possible_process_ids| to the existing process_refs_ since each one
  // is likely to take a reference once the SW starts up.
  ProcessRefMap refs_with_new_ids = process_refs_;
  for (std::vector<int>::const_iterator it = possible_process_ids.begin();
       it != possible_process_ids.end();
       ++it) {
    refs_with_new_ids[*it]++;
  }

  std::vector<std::pair<int, int> > counted(refs_with_new_ids.begin(),
                                            refs_with_new_ids.end());
  // Sort descending by the reference count.
  std::sort(counted.begin(), counted.end(), SecondGreater());

  std::vector<int> result(counted.size());
  for (size_t i = 0; i < counted.size(); ++i)
    result[i] = counted[i].first;
  return result;
}

}  // namespace content
