// 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 "content/worker/websharedworkerclient_proxy.h"

#include "base/bind.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
#include "content/child/webmessageportchannel_impl.h"
#include "content/common/worker_messages.h"
#include "content/public/common/content_switches.h"
#include "content/worker/shared_worker_devtools_agent.h"
#include "content/worker/shared_worker_permission_client_proxy.h"
#include "content/worker/websharedworker_stub.h"
#include "content/worker/worker_thread.h"
#include "content/worker/worker_webapplicationcachehost_impl.h"
#include "ipc/ipc_logging.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"

using blink::WebApplicationCacheHost;
using blink::WebFrame;
using blink::WebMessagePortChannel;
using blink::WebMessagePortChannelArray;
using blink::WebSecurityOrigin;
using blink::WebString;
using blink::WebWorker;
using blink::WebSharedWorkerClient;

namespace content {

// How long to wait for worker to finish after it's been told to terminate.
#define kMaxTimeForRunawayWorkerSeconds 3

WebSharedWorkerClientProxy::WebSharedWorkerClientProxy(
    int route_id, WebSharedWorkerStub* stub)
    : route_id_(route_id),
      appcache_host_id_(0),
      stub_(stub),
      weak_factory_(this),
      devtools_agent_(NULL) {
}

WebSharedWorkerClientProxy::~WebSharedWorkerClientProxy() {
}

void WebSharedWorkerClientProxy::workerContextClosed() {
  Send(new WorkerHostMsg_WorkerContextClosed(route_id_));
}

void WebSharedWorkerClientProxy::workerContextDestroyed() {
  Send(new WorkerHostMsg_WorkerContextDestroyed(route_id_));
  // Tell the stub that the worker has shutdown - frees this object.
  if (stub_)
    stub_->Shutdown();
}

blink::WebNotificationPresenter*
WebSharedWorkerClientProxy::notificationPresenter() {
  // TODO(johnnyg): Notifications are not yet hooked up to workers.
  // Coming soon.
  NOTREACHED();
  return NULL;
}

WebApplicationCacheHost* WebSharedWorkerClientProxy::createApplicationCacheHost(
    blink::WebApplicationCacheHostClient* client) {
  WorkerWebApplicationCacheHostImpl* host =
      new WorkerWebApplicationCacheHostImpl(stub_->appcache_init_info(),
                                            client);
  // Remember the id of the instance we create so we have access to that
  // value when creating nested dedicated workers in createWorker.
  appcache_host_id_ = host->host_id();
  return host;
}

blink::WebWorkerPermissionClientProxy*
WebSharedWorkerClientProxy::createWorkerPermissionClientProxy(
    const blink::WebSecurityOrigin& origin) {
  return new SharedWorkerPermissionClientProxy(
      GURL(origin.toString()), origin.isUnique(), route_id_,
      ChildThread::current()->thread_safe_sender());
}

// TODO(kinuko): Deprecate these methods.
bool WebSharedWorkerClientProxy::allowDatabase(WebFrame* frame,
                                         const WebString& name,
                                         const WebString& display_name,
                                         unsigned long estimated_size) {
  return false;
}

bool WebSharedWorkerClientProxy::allowFileSystem() {
  return false;
}

bool WebSharedWorkerClientProxy::allowIndexedDB(const blink::WebString& name) {
  return false;
}

void WebSharedWorkerClientProxy::dispatchDevToolsMessage(
    const WebString& message) {
  if (devtools_agent_)
    devtools_agent_->SendDevToolsMessage(message);
}

void WebSharedWorkerClientProxy::saveDevToolsAgentState(
    const blink::WebString& state) {
  if (devtools_agent_)
    devtools_agent_->SaveDevToolsAgentState(state);
}

bool WebSharedWorkerClientProxy::Send(IPC::Message* message) {
  return WorkerThread::current()->Send(message);
}

void WebSharedWorkerClientProxy::EnsureWorkerContextTerminates() {
  // This shuts down the process cleanly from the perspective of the browser
  // process, and avoids the crashed worker infobar from appearing to the new
  // page. It's ok to post several of theese, because the first executed task
  // will exit the message loop and subsequent ones won't be executed.
  base::MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&WebSharedWorkerClientProxy::workerContextDestroyed,
                 weak_factory_.GetWeakPtr()),
      base::TimeDelta::FromSeconds(kMaxTimeForRunawayWorkerSeconds));
}

}  // namespace content