// 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 "chrome/browser/devtools/devtools_window.h"

#include <algorithm>

#include "base/command_line.h"
#include "base/json/json_writer.h"
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/debugger/debugger_api.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/infobars/confirm_infobar_delegate.h"
#include "chrome/browser/prefs/pref_service_syncable.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_iterator.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/webui/devtools_ui.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/manifest_url_handler.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/load_notification_details.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/content_client.h"
#include "content/public/common/page_transition_types.h"
#include "content/public/common/url_constants.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

using content::DevToolsAgentHost;


// DevToolsConfirmInfoBarDelegate ---------------------------------------------

class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
 public:
  // If |infobar_service| is NULL, runs |callback| with a single argument with
  // value "false".  Otherwise, creates a dev tools confirm infobar and delegate
  // and adds the inofbar to |infobar_service|.
  static void Create(InfoBarService* infobar_service,
                     const DevToolsWindow::InfoBarCallback& callback,
                     const string16& message);

 private:
  DevToolsConfirmInfoBarDelegate(
      InfoBarService* infobar_service,
      const DevToolsWindow::InfoBarCallback& callback,
      const string16& message);
  virtual ~DevToolsConfirmInfoBarDelegate();

  virtual string16 GetMessageText() const OVERRIDE;
  virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
  virtual bool Accept() OVERRIDE;
  virtual bool Cancel() OVERRIDE;

  DevToolsWindow::InfoBarCallback callback_;
  const string16 message_;

  DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate);
};

void DevToolsConfirmInfoBarDelegate::Create(
    InfoBarService* infobar_service,
    const DevToolsWindow::InfoBarCallback& callback,
    const string16& message) {
  if (!infobar_service) {
    callback.Run(false);
    return;
  }

  infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
      new DevToolsConfirmInfoBarDelegate(infobar_service, callback, message)));
}

DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
    InfoBarService* infobar_service,
    const DevToolsWindow::InfoBarCallback& callback,
    const string16& message)
    : ConfirmInfoBarDelegate(infobar_service),
      callback_(callback),
      message_(message) {
}

DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
  if (!callback_.is_null())
    callback_.Run(false);
}

string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const {
  return message_;
}

string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel(
    InfoBarButton button) const {
  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
      IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON);
}

bool DevToolsConfirmInfoBarDelegate::Accept() {
  callback_.Run(true);
  callback_.Reset();
  return true;
}

bool DevToolsConfirmInfoBarDelegate::Cancel() {
  callback_.Run(false);
  callback_.Reset();
  return true;
}


// DevToolsWindow::InspectedWebContentsObserver -------------------------------

class DevToolsWindow::InspectedWebContentsObserver
    : public content::WebContentsObserver {
 public:
  explicit InspectedWebContentsObserver(content::WebContents* web_contents);
  virtual ~InspectedWebContentsObserver();

  content::WebContents* web_contents() {
    return WebContentsObserver::web_contents();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(InspectedWebContentsObserver);
};

DevToolsWindow::InspectedWebContentsObserver::InspectedWebContentsObserver(
    content::WebContents* web_contents)
    : WebContentsObserver(web_contents) {
}

DevToolsWindow::InspectedWebContentsObserver::~InspectedWebContentsObserver() {
}


// DevToolsWindow::FrontendWebContentsObserver --------------------------------

class DevToolsWindow::FrontendWebContentsObserver
    : public content::WebContentsObserver {
 public:
  explicit FrontendWebContentsObserver(content::WebContents* web_contents);
  virtual ~FrontendWebContentsObserver();

 private:
  // contents::WebContentsObserver:
  virtual void AboutToNavigateRenderView(
      content::RenderViewHost* render_view_host) OVERRIDE;

  DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver);
};

DevToolsWindow::FrontendWebContentsObserver::FrontendWebContentsObserver(
    content::WebContents* web_contents)
    : WebContentsObserver(web_contents) {
}

DevToolsWindow::FrontendWebContentsObserver::~FrontendWebContentsObserver() {
}

void DevToolsWindow::FrontendWebContentsObserver::AboutToNavigateRenderView(
    content::RenderViewHost* render_view_host) {
  content::DevToolsClientHost::SetupDevToolsFrontendClient(render_view_host);
}


// DevToolsWindow -------------------------------------------------------------

namespace {

typedef std::vector<DevToolsWindow*> DevToolsWindows;
base::LazyInstance<DevToolsWindows>::Leaky g_instances =
    LAZY_INSTANCE_INITIALIZER;

const char kPrefBottom[] = "dock_bottom";
const char kPrefRight[] = "dock_right";
const char kPrefUndocked[] = "undocked";

const char kDockSideBottom[] = "bottom";
const char kDockSideRight[] = "right";
const char kDockSideUndocked[] = "undocked";
const char kDockSideMinimized[] = "minimized";

const int kMinContentsSize = 50;

std::string SkColorToRGBAString(SkColor color) {
  // We avoid StringPrintf because it will use locale specific formatters for
  // the double (e.g. ',' instead of '.' in German).
  return "rgba(" + base::IntToString(SkColorGetR(color)) + "," +
      base::IntToString(SkColorGetG(color)) + "," +
      base::IntToString(SkColorGetB(color)) + "," +
      base::DoubleToString(SkColorGetA(color) / 255.0) + ")";
}

DictionaryValue* CreateFileSystemValue(
    DevToolsFileHelper::FileSystem file_system) {
  DictionaryValue* file_system_value = new DictionaryValue();
  file_system_value->SetString("fileSystemName", file_system.file_system_name);
  file_system_value->SetString("rootURL", file_system.root_url);
  file_system_value->SetString("fileSystemPath", file_system.file_system_path);
  return file_system_value;
}

}  // namespace

const char DevToolsWindow::kDevToolsApp[] = "DevToolsApp";

DevToolsWindow::~DevToolsWindow() {
  DevToolsWindows* instances = &g_instances.Get();
  DevToolsWindows::iterator it(
      std::find(instances->begin(), instances->end(), this));
  DCHECK(it != instances->end());
  instances->erase(it);

  for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin());
       jobs_it != indexing_jobs_.end(); ++jobs_it) {
    jobs_it->second->Stop();
  }
  indexing_jobs_.clear();
}

// static
std::string DevToolsWindow::GetDevToolsWindowPlacementPrefKey() {
  return std::string(prefs::kBrowserWindowPlacement) + "_" +
      std::string(kDevToolsApp);
}

// static
void DevToolsWindow::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* registry) {
  registry->RegisterBooleanPref(
      prefs::kDevToolsOpenDocked, true,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  registry->RegisterStringPref(
      prefs::kDevToolsDockSide, kDockSideBottom,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  registry->RegisterDictionaryPref(
      prefs::kDevToolsEditedFiles,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  registry->RegisterDictionaryPref(
      prefs::kDevToolsFileSystemPaths,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  registry->RegisterStringPref(
      prefs::kDevToolsAdbKey, std::string(),
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);

  registry->RegisterDictionaryPref(
      GetDevToolsWindowPlacementPrefKey().c_str(),
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);

  registry->RegisterBooleanPref(
      prefs::kDevToolsPortForwardingEnabled,
      false,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  registry->RegisterDictionaryPref(
      prefs::kDevToolsPortForwardingConfig,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}

// static
DevToolsWindow* DevToolsWindow::GetDockedInstanceForInspectedTab(
    content::WebContents* inspected_web_contents) {
  if (!inspected_web_contents ||
      !DevToolsAgentHost::HasFor(inspected_web_contents->GetRenderViewHost()))
    return NULL;
  scoped_refptr<DevToolsAgentHost> agent(DevToolsAgentHost::GetOrCreateFor(
      inspected_web_contents->GetRenderViewHost()));
  DevToolsWindow* window = FindDevToolsWindow(agent.get());
  return (window && window->IsDocked()) ? window : NULL;
}

// static
bool DevToolsWindow::IsDevToolsWindow(content::RenderViewHost* window_rvh) {
  return AsDevToolsWindow(window_rvh) != NULL;
}

// static
DevToolsWindow* DevToolsWindow::OpenDevToolsWindowForWorker(
    Profile* profile,
    DevToolsAgentHost* worker_agent) {
  DevToolsWindow* window = FindDevToolsWindow(worker_agent);
  if (!window) {
    window = DevToolsWindow::CreateDevToolsWindowForWorker(profile);
    // Will disconnect the current client host if there is one.
    content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
        worker_agent, window->frontend_host_.get());
  }
  window->Show(DEVTOOLS_TOGGLE_ACTION_SHOW);
  return window;
}

// static
DevToolsWindow* DevToolsWindow::CreateDevToolsWindowForWorker(
    Profile* profile) {
  return Create(profile, GURL(), NULL, DEVTOOLS_DOCK_SIDE_UNDOCKED, true);
}

// static
DevToolsWindow* DevToolsWindow::OpenDevToolsWindow(
    content::RenderViewHost* inspected_rvh) {
  return ToggleDevToolsWindow(inspected_rvh, true,
                              DEVTOOLS_TOGGLE_ACTION_SHOW);
}

// static
DevToolsWindow* DevToolsWindow::ToggleDevToolsWindow(
    Browser* browser,
    DevToolsToggleAction action) {
  if (action == DEVTOOLS_TOGGLE_ACTION_TOGGLE && browser->is_devtools()) {
    browser->tab_strip_model()->CloseAllTabs();
    return NULL;
  }

  return ToggleDevToolsWindow(
      browser->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(),
      action == DEVTOOLS_TOGGLE_ACTION_INSPECT, action);
}

// static
void DevToolsWindow::OpenExternalFrontend(
    Profile* profile,
    const std::string& frontend_url,
    content::DevToolsAgentHost* agent_host) {
  DevToolsWindow* window = FindDevToolsWindow(agent_host);
  if (!window) {
    window = Create(profile, DevToolsUI::GetProxyURL(frontend_url), NULL,
                    DEVTOOLS_DOCK_SIDE_UNDOCKED, false);
    content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
        agent_host, window->frontend_host_.get());
  }
  window->Show(DEVTOOLS_TOGGLE_ACTION_SHOW);
}

// static
DevToolsWindow* DevToolsWindow::ToggleDevToolsWindow(
    content::RenderViewHost* inspected_rvh,
    bool force_open,
    DevToolsToggleAction action) {
  scoped_refptr<DevToolsAgentHost> agent(
      DevToolsAgentHost::GetOrCreateFor(inspected_rvh));
  content::DevToolsManager* manager = content::DevToolsManager::GetInstance();
  DevToolsWindow* window = FindDevToolsWindow(agent.get());
  bool do_open = force_open;
  if (!window) {
    Profile* profile = Profile::FromBrowserContext(
        inspected_rvh->GetProcess()->GetBrowserContext());
    DevToolsDockSide dock_side = GetDockSideFromPrefs(profile);
    window = Create(profile, GURL(), inspected_rvh, dock_side, false);
    manager->RegisterDevToolsClientHostFor(agent.get(),
                                           window->frontend_host_.get());
    do_open = true;
  }

  // Update toolbar to reflect DevTools changes.
  window->UpdateBrowserToolbar();

  // If window is docked and visible, we hide it on toggle. If window is
  // undocked, we show (activate) it. If window is minimized, we maximize it.
  if (window->dock_side_ == DEVTOOLS_DOCK_SIDE_MINIMIZED)
    window->Restore();
  else if (!window->IsDocked() || do_open)
    window->Show(action);
  else
    window->CloseWindow();

  return window;
}

// static
void DevToolsWindow::InspectElement(content::RenderViewHost* inspected_rvh,
                                    int x,
                                    int y) {
  scoped_refptr<DevToolsAgentHost> agent(
      DevToolsAgentHost::GetOrCreateFor(inspected_rvh));
  agent->InspectElement(x, y);
  // TODO(loislo): we should initiate DevTools window opening from within
  // renderer. Otherwise, we still can hit a race condition here.
  OpenDevToolsWindow(inspected_rvh);
}

// static
int DevToolsWindow::GetMinimumWidth() {
  const int kMinDevToolsWidth = 150;
  return kMinDevToolsWidth;
}

// static
int DevToolsWindow::GetMinimumHeight() {
  // Minimal height of devtools pane or content pane when devtools are docked
  // to the browser window.
  const int kMinDevToolsHeight = 50;
  return kMinDevToolsHeight;
}

// static
int DevToolsWindow::GetMinimizedHeight() {
  const int kMinimizedDevToolsHeight = 24;
  return kMinimizedDevToolsHeight;
}

void DevToolsWindow::InspectedContentsClosing() {
  Hide();
}

content::RenderViewHost* DevToolsWindow::GetRenderViewHost() {
  return web_contents_->GetRenderViewHost();
}

content::DevToolsClientHost* DevToolsWindow::GetDevToolsClientHostForTest() {
  return frontend_host_.get();
}

int DevToolsWindow::GetWidth(int container_width) {
  if (width_ == -1) {
    width_ = profile_->GetPrefs()->
        GetInteger(prefs::kDevToolsVSplitLocation);
  }

  // By default, size devtools as 1/3 of the browser window.
  if (width_ == -1)
    width_ = container_width / 3;

  // Respect the minimum devtools width preset.
  width_ = std::max(GetMinimumWidth(), width_);

  // But it should never compromise the content window size unless the entire
  // window is tiny.
  width_ = std::min(container_width - kMinContentsSize, width_);
  return width_;
}

int DevToolsWindow::GetHeight(int container_height) {
  if (height_ == -1) {
    height_ = profile_->GetPrefs()->
        GetInteger(prefs::kDevToolsHSplitLocation);
  }

  // By default, size devtools as 1/3 of the browser window.
  if (height_ == -1)
    height_ = container_height / 3;

  // Respect the minimum devtools width preset.
  height_ = std::max(GetMinimumHeight(), height_);

  // But it should never compromise the content window size.
  height_ = std::min(container_height - kMinContentsSize, height_);
  return height_;
}

void DevToolsWindow::SetWidth(int width) {
  width_ = width;
  profile_->GetPrefs()->SetInteger(prefs::kDevToolsVSplitLocation, width);
}

void DevToolsWindow::SetHeight(int height) {
  height_ = height;
  profile_->GetPrefs()->SetInteger(prefs::kDevToolsHSplitLocation, height);
}

void DevToolsWindow::Show(DevToolsToggleAction action) {
  if (IsDocked()) {
    Browser* inspected_browser = NULL;
    int inspected_tab_index = -1;
    // Tell inspected browser to update splitter and switch to inspected panel.
    if (!IsInspectedBrowserPopup() &&
        FindInspectedBrowserAndTabIndex(&inspected_browser,
                                        &inspected_tab_index)) {
      BrowserWindow* inspected_window = inspected_browser->window();
      web_contents_->SetDelegate(this);
      inspected_window->UpdateDevTools();
      web_contents_->GetView()->SetInitialFocus();
      inspected_window->Show();
      TabStripModel* tab_strip_model = inspected_browser->tab_strip_model();
      tab_strip_model->ActivateTabAt(inspected_tab_index, true);
      PrefsTabHelper::CreateForWebContents(web_contents_);
      GetRenderViewHost()->SyncRendererPrefs();
      ScheduleAction(action);
      return;
    }

    // Sometimes we don't know where to dock. Stay undocked.
    dock_side_ = DEVTOOLS_DOCK_SIDE_UNDOCKED;
  }

  // Avoid consecutive window switching if the devtools window has been opened
  // and the Inspect Element shortcut is pressed in the inspected tab.
  bool should_show_window =
      !browser_ || (action != DEVTOOLS_TOGGLE_ACTION_INSPECT);

  if (!browser_)
    CreateDevToolsBrowser();

  if (should_show_window) {
    browser_->window()->Show();
    web_contents_->GetView()->SetInitialFocus();
  }

  ScheduleAction(action);
}

DevToolsWindow::DevToolsWindow(Profile* profile,
                               const GURL& url,
                               content::RenderViewHost* inspected_rvh,
                               DevToolsDockSide dock_side)
    : profile_(profile),
      browser_(NULL),
      dock_side_(dock_side),
      is_loaded_(false),
      action_on_load_(DEVTOOLS_TOGGLE_ACTION_SHOW),
      weak_factory_(this),
      width_(-1),
      height_(-1),
      dock_side_before_minimized_(dock_side) {
  web_contents_ =
      content::WebContents::Create(content::WebContents::CreateParams(profile));
  frontend_contents_observer_.reset(
      new FrontendWebContentsObserver(web_contents_));

  web_contents_->GetController().LoadURL(url, content::Referrer(),
      content::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());

  frontend_host_.reset(content::DevToolsClientHost::CreateDevToolsFrontendHost(
      web_contents_, this));
  file_helper_.reset(new DevToolsFileHelper(web_contents_, profile));
  file_system_indexer_ = new DevToolsFileSystemIndexer();

  g_instances.Get().push_back(this);

  // Wipe out page icon so that the default application icon is used.
  content::NavigationEntry* entry =
      web_contents_->GetController().GetActiveEntry();
  entry->GetFavicon().image = gfx::Image();
  entry->GetFavicon().valid = true;

  // Register on-load actions.
  content::Source<content::NavigationController> nav_controller_source(
      &web_contents_->GetController());
  registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, nav_controller_source);
  registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING, nav_controller_source);
  registrar_.Add(
      this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
      content::Source<ThemeService>(
          ThemeServiceFactory::GetForProfile(profile_)));

  // There is no inspected_rvh in case of shared workers.
  if (inspected_rvh)
    inspected_contents_observer_.reset(new InspectedWebContentsObserver(
        content::WebContents::FromRenderViewHost(inspected_rvh)));
}

// static
DevToolsWindow* DevToolsWindow::Create(
    Profile* profile,
    const GURL& frontend_url,
    content::RenderViewHost* inspected_rvh,
    DevToolsDockSide dock_side,
    bool shared_worker_frontend) {
  // Create WebContents with devtools.
  GURL url(GetDevToolsURL(profile, frontend_url, dock_side,
                          shared_worker_frontend));
  return new DevToolsWindow(profile, url, inspected_rvh, dock_side);
}

// static
GURL DevToolsWindow::GetDevToolsURL(Profile* profile,
                                    const GURL& base_url,
                                    DevToolsDockSide dock_side,
                                    bool shared_worker_frontend) {
  std::string frontend_url(
      base_url.is_empty() ? chrome::kChromeUIDevToolsURL : base_url.spec());
  ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
  DCHECK(tp);
  std::string url_string(
      frontend_url +
      ((frontend_url.find("?") == std::string::npos) ? "?" : "&") +
      "dockSide=" + SideToString(dock_side) +
      "&toolbarColor=" +
      SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
      "&textColor=" +
      SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)));
  if (shared_worker_frontend)
    url_string += "&isSharedWorker=true";
  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kEnableDevToolsExperiments))
    url_string += "&experiments=true";
  return GURL(url_string);
}

// static
DevToolsWindow* DevToolsWindow::FindDevToolsWindow(
    DevToolsAgentHost* agent_host) {
  DevToolsWindows* instances = &g_instances.Get();
  content::DevToolsManager* manager = content::DevToolsManager::GetInstance();
  for (DevToolsWindows::iterator it(instances->begin()); it != instances->end();
       ++it) {
    if (manager->GetDevToolsAgentHostFor((*it)->frontend_host_.get()) ==
        agent_host)
      return *it;
  }
  return NULL;
}

// static
DevToolsWindow* DevToolsWindow::AsDevToolsWindow(
    content::RenderViewHost* window_rvh) {
  if (g_instances == NULL)
    return NULL;
  DevToolsWindows* instances = &g_instances.Get();
  for (DevToolsWindows::iterator it(instances->begin()); it != instances->end();
       ++it) {
    if ((*it)->web_contents_->GetRenderViewHost() == window_rvh)
      return *it;
  }
  return NULL;
}

// static
DevToolsDockSide DevToolsWindow::GetDockSideFromPrefs(Profile* profile) {
  std::string dock_side =
      profile->GetPrefs()->GetString(prefs::kDevToolsDockSide);

  // Migrate prefs.
  const char kOldPrefBottom[] = "bottom";
  const char kOldPrefRight[] = "right";
  if ((dock_side == kOldPrefBottom) || (dock_side == kOldPrefRight)) {
    if (!profile->GetPrefs()->GetBoolean(prefs::kDevToolsOpenDocked))
      return DEVTOOLS_DOCK_SIDE_UNDOCKED;
    return (dock_side == kOldPrefBottom) ?
        DEVTOOLS_DOCK_SIDE_BOTTOM : DEVTOOLS_DOCK_SIDE_RIGHT;
  }

  if (dock_side == kPrefUndocked)
    return DEVTOOLS_DOCK_SIDE_UNDOCKED;
  if (dock_side == kPrefRight)
    return DEVTOOLS_DOCK_SIDE_RIGHT;
  // Default to docked to bottom.
  return DEVTOOLS_DOCK_SIDE_BOTTOM;
}

// static
std::string DevToolsWindow::SideToString(DevToolsDockSide dock_side) {
  switch (dock_side) {
    case DEVTOOLS_DOCK_SIDE_UNDOCKED:  return kDockSideUndocked;
    case DEVTOOLS_DOCK_SIDE_RIGHT:     return kDockSideRight;
    case DEVTOOLS_DOCK_SIDE_BOTTOM:    return kDockSideBottom;
    case DEVTOOLS_DOCK_SIDE_MINIMIZED: return kDockSideMinimized;
    default:                           return kDockSideUndocked;
  }
}

// static
DevToolsDockSide DevToolsWindow::SideFromString(
    const std::string& dock_side) {
  if (dock_side == kDockSideRight)
    return DEVTOOLS_DOCK_SIDE_RIGHT;
  if (dock_side == kDockSideBottom)
    return DEVTOOLS_DOCK_SIDE_BOTTOM;
  return (dock_side == kDockSideMinimized) ?
      DEVTOOLS_DOCK_SIDE_MINIMIZED : DEVTOOLS_DOCK_SIDE_UNDOCKED;
}

void DevToolsWindow::Observe(int type,
                             const content::NotificationSource& source,
                             const content::NotificationDetails& details) {
  if (type == content::NOTIFICATION_LOAD_STOP) {
    if (!is_loaded_) {
      is_loaded_ = true;
      UpdateTheme();
      DoAction();
      AddDevToolsExtensionsToClient();
    }
  } else if (type == chrome::NOTIFICATION_TAB_CLOSING) {
    if (content::Source<content::NavigationController>(source).ptr() ==
        &web_contents_->GetController()) {
      // This happens when browser closes all of its tabs as a result
      // of window.Close event.
      // Notify manager that this DevToolsClientHost no longer exists and
      // initiate self-destuct here.
      content::DevToolsManager::GetInstance()->ClientHostClosing(
          frontend_host_.get());
      UpdateBrowserToolbar();
      delete this;
    }
  } else {
    DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type);
    UpdateTheme();
  }
}

content::WebContents* DevToolsWindow::OpenURLFromTab(
    content::WebContents* source,
    const content::OpenURLParams& params) {
  if (!params.url.SchemeIs(chrome::kChromeDevToolsScheme)) {
    content::WebContents* inspected_web_contents = GetInspectedWebContents();
    return inspected_web_contents ?
        inspected_web_contents->OpenURL(params) : NULL;
  }

  content::DevToolsManager* manager = content::DevToolsManager::GetInstance();
  scoped_refptr<DevToolsAgentHost> agent_host(
      manager->GetDevToolsAgentHostFor(frontend_host_.get()));
  if (!agent_host.get())
    return NULL;
  manager->ClientHostClosing(frontend_host_.get());
  manager->RegisterDevToolsClientHostFor(agent_host.get(),
                                         frontend_host_.get());

  chrome::NavigateParams nav_params(profile_, params.url, params.transition);
  FillNavigateParamsFromOpenURLParams(&nav_params, params);
  nav_params.source_contents = source;
  nav_params.tabstrip_add_types = TabStripModel::ADD_NONE;
  nav_params.window_action = chrome::NavigateParams::SHOW_WINDOW;
  nav_params.user_gesture = params.user_gesture;
  chrome::Navigate(&nav_params);
  return nav_params.target_contents;
}

void DevToolsWindow::AddNewContents(content::WebContents* source,
                                    content::WebContents* new_contents,
                                    WindowOpenDisposition disposition,
                                    const gfx::Rect& initial_pos,
                                    bool user_gesture,
                                    bool* was_blocked) {
  content::WebContents* inspected_web_contents = GetInspectedWebContents();
  if (inspected_web_contents) {
    inspected_web_contents->GetDelegate()->AddNewContents(
        source, new_contents, disposition, initial_pos, user_gesture,
        was_blocked);
  }
}

void DevToolsWindow::CloseContents(content::WebContents* source) {
}

bool DevToolsWindow::PreHandleKeyboardEvent(
    content::WebContents* source,
    const content::NativeWebKeyboardEvent& event,
    bool* is_keyboard_shortcut) {
  if (IsDocked()) {
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window) {
      return inspected_window->PreHandleKeyboardEvent(event,
                                                      is_keyboard_shortcut);
    }
  }
  return false;
}

void DevToolsWindow::HandleKeyboardEvent(
    content::WebContents* source,
    const content::NativeWebKeyboardEvent& event) {
  if (IsDocked()) {
    if (event.windowsKeyCode == 0x08) {
      // Do not navigate back in history on Windows (http://crbug.com/74156).
      return;
    }
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->HandleKeyboardEvent(event);
  }
}

content::JavaScriptDialogManager* DevToolsWindow::GetJavaScriptDialogManager() {
  content::WebContents* inspected_web_contents = GetInspectedWebContents();
  return (inspected_web_contents && inspected_web_contents->GetDelegate()) ?
      inspected_web_contents->GetDelegate()->GetJavaScriptDialogManager() :
      content::WebContentsDelegate::GetJavaScriptDialogManager();
}

content::ColorChooser* DevToolsWindow::OpenColorChooser(
    content::WebContents* web_contents,
    SkColor initial_color) {
  return chrome::ShowColorChooser(web_contents, initial_color);
}

void DevToolsWindow::RunFileChooser(content::WebContents* web_contents,
                                    const content::FileChooserParams& params) {
  FileSelectHelper::RunFileChooser(web_contents, params);
}

void DevToolsWindow::WebContentsFocused(content::WebContents* contents) {
  Browser* inspected_browser = NULL;
  int inspected_tab_index = -1;
  if (IsDocked() && FindInspectedBrowserAndTabIndex(&inspected_browser,
                                                    &inspected_tab_index))
    inspected_browser->window()->WebContentsFocused(contents);
}

void DevToolsWindow::ActivateWindow() {
  if (IsDocked() && GetInspectedBrowserWindow())
    web_contents_->GetView()->Focus();
  else if (!IsDocked() && !browser_->window()->IsActive())
    browser_->window()->Activate();
}

void DevToolsWindow::ChangeAttachedWindowHeight(unsigned height) {
  NOTREACHED();  // TODO(dgozman): This is not used anymore, remove.
}

void DevToolsWindow::CloseWindow() {
  DCHECK(IsDocked());
  content::DevToolsManager::GetInstance()->ClientHostClosing(
      frontend_host_.get());
  Hide();
}

void DevToolsWindow::MoveWindow(int x, int y) {
  if (!IsDocked()) {
    gfx::Rect bounds = browser_->window()->GetBounds();
    bounds.Offset(x, y);
    browser_->window()->SetBounds(bounds);
  }
}

void DevToolsWindow::SetDockSide(const std::string& side) {
  DevToolsDockSide requested_side = SideFromString(side);
  bool dock_requested = requested_side != DEVTOOLS_DOCK_SIDE_UNDOCKED;
  bool is_docked = IsDocked();

  if (dock_requested &&
      (!GetInspectedWebContents() || !GetInspectedBrowserWindow() ||
       IsInspectedBrowserPopup())) {
      // Cannot dock, avoid window flashing due to close-reopen cycle.
    return;
  }

  if ((dock_side_ != DEVTOOLS_DOCK_SIDE_MINIMIZED) &&
      (requested_side == DEVTOOLS_DOCK_SIDE_MINIMIZED))
    dock_side_before_minimized_ = dock_side_;

  dock_side_ = requested_side;
  if (dock_requested && !is_docked) {
    // Detach window from the external devtools browser. It will lead to
    // the browser object's close and delete. Remove observer first.
    TabStripModel* tab_strip_model = browser_->tab_strip_model();
    tab_strip_model->DetachWebContentsAt(
        tab_strip_model->GetIndexOfWebContents(web_contents_));
    browser_ = NULL;
  } else if (!dock_requested && is_docked) {
    // Update inspected window to hide split and reset it.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->UpdateDevTools();
  }

  if (dock_side_ != DEVTOOLS_DOCK_SIDE_MINIMIZED) {
    std::string pref_value = kPrefBottom;
    switch (dock_side_) {
      case DEVTOOLS_DOCK_SIDE_UNDOCKED:
          pref_value = kPrefUndocked;
          break;
      case DEVTOOLS_DOCK_SIDE_RIGHT:
          pref_value = kPrefRight;
          break;
      case DEVTOOLS_DOCK_SIDE_BOTTOM:
          pref_value = kPrefBottom;
          break;
      case DEVTOOLS_DOCK_SIDE_MINIMIZED:
          // We don't persist minimized state.
          break;
    }
    profile_->GetPrefs()->SetString(prefs::kDevToolsDockSide, pref_value);
  }

  Show(DEVTOOLS_TOGGLE_ACTION_SHOW);
}

void DevToolsWindow::OpenInNewTab(const std::string& url) {
  content::OpenURLParams params(
      GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
      content::PAGE_TRANSITION_LINK, false);
  content::WebContents* inspected_web_contents = GetInspectedWebContents();
  if (inspected_web_contents) {
    inspected_web_contents->OpenURL(params);
  } else {
    chrome::HostDesktopType host_desktop_type;
    if (browser_) {
      host_desktop_type = browser_->host_desktop_type();
    } else {
      // There should always be a browser when there are no inspected web
      // contents.
      NOTREACHED();
      host_desktop_type = chrome::GetActiveDesktop();
    }

    const BrowserList* browser_list =
        BrowserList::GetInstance(host_desktop_type);
    for (BrowserList::const_iterator it = browser_list->begin();
         it != browser_list->end(); ++it) {
      if ((*it)->type() == Browser::TYPE_TABBED) {
        (*it)->OpenURL(params);
        break;
      }
    }
  }
}

void DevToolsWindow::SaveToFile(const std::string& url,
                                const std::string& content,
                                bool save_as) {
  file_helper_->Save(url, content, save_as,
                     base::Bind(&DevToolsWindow::FileSavedAs,
                                weak_factory_.GetWeakPtr(), url));
}

void DevToolsWindow::AppendToFile(const std::string& url,
                                  const std::string& content) {
  file_helper_->Append(url, content,
                       base::Bind(&DevToolsWindow::AppendedTo,
                                  weak_factory_.GetWeakPtr(), url));
}

void DevToolsWindow::RequestFileSystems() {
  CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme));
  file_helper_->RequestFileSystems(base::Bind(
      &DevToolsWindow::FileSystemsLoaded, weak_factory_.GetWeakPtr()));
}

void DevToolsWindow::AddFileSystem() {
  CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme));
  file_helper_->AddFileSystem(
      base::Bind(&DevToolsWindow::FileSystemAdded, weak_factory_.GetWeakPtr()),
      base::Bind(&DevToolsWindow::ShowDevToolsConfirmInfoBar,
                 weak_factory_.GetWeakPtr()));
}

void DevToolsWindow::RemoveFileSystem(const std::string& file_system_path) {
  CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme));
  file_helper_->RemoveFileSystem(file_system_path);
  StringValue file_system_path_value(file_system_path);
  CallClientFunction("InspectorFrontendAPI.fileSystemRemoved",
                     &file_system_path_value, NULL, NULL);
}

void DevToolsWindow::IndexPath(int request_id,
                               const std::string& file_system_path) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme));
  if (!file_helper_->IsFileSystemAdded(file_system_path)) {
    IndexingDone(request_id, file_system_path);
    return;
  }
  indexing_jobs_[request_id] =
      scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>(
          file_system_indexer_->IndexPath(
              file_system_path,
              Bind(&DevToolsWindow::IndexingTotalWorkCalculated,
                   weak_factory_.GetWeakPtr(),
                   request_id,
                   file_system_path),
              Bind(&DevToolsWindow::IndexingWorked,
                   weak_factory_.GetWeakPtr(),
                   request_id,
                   file_system_path),
              Bind(&DevToolsWindow::IndexingDone,
                   weak_factory_.GetWeakPtr(),
                   request_id,
                   file_system_path)));
}

void DevToolsWindow::StopIndexing(int request_id) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  IndexingJobsMap::iterator it = indexing_jobs_.find(request_id);
  if (it == indexing_jobs_.end())
    return;
  it->second->Stop();
  indexing_jobs_.erase(it);
}

void DevToolsWindow::SearchInPath(int request_id,
                                  const std::string& file_system_path,
                                  const std::string& query) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme));
  if (!file_helper_->IsFileSystemAdded(file_system_path)) {
    SearchCompleted(request_id, file_system_path, std::vector<std::string>());
    return;
  }
  file_system_indexer_->SearchInPath(file_system_path,
                                     query,
                                     Bind(&DevToolsWindow::SearchCompleted,
                                          weak_factory_.GetWeakPtr(),
                                          request_id,
                                          file_system_path));
}

void DevToolsWindow::FileSavedAs(const std::string& url) {
  StringValue url_value(url);
  CallClientFunction("InspectorFrontendAPI.savedURL", &url_value, NULL, NULL);
}

void DevToolsWindow::AppendedTo(const std::string& url) {
  StringValue url_value(url);
  CallClientFunction("InspectorFrontendAPI.appendedToURL", &url_value, NULL,
                     NULL);
}

void DevToolsWindow::FileSystemsLoaded(
    const std::vector<DevToolsFileHelper::FileSystem>& file_systems) {
  ListValue file_systems_value;
  for (size_t i = 0; i < file_systems.size(); ++i)
    file_systems_value.Append(CreateFileSystemValue(file_systems[i]));
  CallClientFunction("InspectorFrontendAPI.fileSystemsLoaded",
                     &file_systems_value, NULL, NULL);
}

void DevToolsWindow::FileSystemAdded(
    const DevToolsFileHelper::FileSystem& file_system) {
  StringValue error_string_value((std::string()));
  DictionaryValue* file_system_value = NULL;
  if (!file_system.file_system_path.empty())
    file_system_value = CreateFileSystemValue(file_system);
  CallClientFunction("InspectorFrontendAPI.fileSystemAdded",
                     &error_string_value, file_system_value, NULL);
  if (file_system_value)
    delete file_system_value;
}

void DevToolsWindow::IndexingTotalWorkCalculated(
    int request_id,
    const std::string& file_system_path,
    int total_work) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  base::FundamentalValue request_id_value(request_id);
  StringValue file_system_path_value(file_system_path);
  base::FundamentalValue total_work_value(total_work);
  CallClientFunction("InspectorFrontendAPI.indexingTotalWorkCalculated",
                     &request_id_value, &file_system_path_value,
                     &total_work_value);
}

void DevToolsWindow::IndexingWorked(int request_id,
                                    const std::string& file_system_path,
                                    int worked) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  base::FundamentalValue request_id_value(request_id);
  StringValue file_system_path_value(file_system_path);
  base::FundamentalValue worked_value(worked);
  CallClientFunction("InspectorFrontendAPI.indexingWorked", &request_id_value,
                     &file_system_path_value, &worked_value);
}

void DevToolsWindow::IndexingDone(int request_id,
                                  const std::string& file_system_path) {
  indexing_jobs_.erase(request_id);
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  base::FundamentalValue request_id_value(request_id);
  StringValue file_system_path_value(file_system_path);
  CallClientFunction("InspectorFrontendAPI.indexingDone", &request_id_value,
                     &file_system_path_value, NULL);
}

void DevToolsWindow::SearchCompleted(
    int request_id,
    const std::string& file_system_path,
    const std::vector<std::string>& file_paths) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  ListValue file_paths_value;
  for (std::vector<std::string>::const_iterator it(file_paths.begin());
       it != file_paths.end(); ++it) {
    file_paths_value.AppendString(*it);
  }
  base::FundamentalValue request_id_value(request_id);
  StringValue file_system_path_value(file_system_path);
  CallClientFunction("InspectorFrontendAPI.searchCompleted", &request_id_value,
                     &file_system_path_value, &file_paths_value);
}

void DevToolsWindow::ShowDevToolsConfirmInfoBar(
    const string16& message,
    const InfoBarCallback& callback) {
  DevToolsConfirmInfoBarDelegate::Create(
      IsDocked() ?
          InfoBarService::FromWebContents(GetInspectedWebContents()) :
          InfoBarService::FromWebContents(web_contents_),
      callback, message);
}

void DevToolsWindow::CreateDevToolsBrowser() {
  std::string wp_key = GetDevToolsWindowPlacementPrefKey();
  PrefService* prefs = profile_->GetPrefs();
  const DictionaryValue* wp_pref = prefs->GetDictionary(wp_key.c_str());
  if (!wp_pref || wp_pref->empty()) {
    DictionaryPrefUpdate update(prefs, wp_key.c_str());
    DictionaryValue* defaults = update.Get();
    defaults->SetInteger("left", 100);
    defaults->SetInteger("top", 100);
    defaults->SetInteger("right", 740);
    defaults->SetInteger("bottom", 740);
    defaults->SetBoolean("maximized", false);
    defaults->SetBoolean("always_on_top", false);
  }

  browser_ = new Browser(Browser::CreateParams::CreateForDevTools(
      profile_,
      chrome::GetHostDesktopTypeForNativeView(
          web_contents_->GetView()->GetNativeView())));
  browser_->tab_strip_model()->AddWebContents(
      web_contents_, -1, content::PAGE_TRANSITION_AUTO_TOPLEVEL,
      TabStripModel::ADD_ACTIVE);
  GetRenderViewHost()->SyncRendererPrefs();
}

bool DevToolsWindow::FindInspectedBrowserAndTabIndex(Browser** browser,
                                                     int* tab) {
  content::WebContents* inspected_web_contents = GetInspectedWebContents();
  if (!inspected_web_contents)
    return false;

  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
    int tab_index = it->tab_strip_model()->GetIndexOfWebContents(
        inspected_web_contents);
    if (tab_index != TabStripModel::kNoTab) {
      *browser = *it;
      *tab = tab_index;
      return true;
    }
  }
  return false;
}

BrowserWindow* DevToolsWindow::GetInspectedBrowserWindow() {
  Browser* browser = NULL;
  int tab;
  return FindInspectedBrowserAndTabIndex(&browser, &tab) ?
      browser->window() : NULL;
}

bool DevToolsWindow::IsInspectedBrowserPopup() {
  Browser* browser = NULL;
  int tab;
  return FindInspectedBrowserAndTabIndex(&browser, &tab) &&
      browser->is_type_popup();
}

void DevToolsWindow::UpdateFrontendDockSide() {
  base::StringValue dock_side(SideToString(dock_side_));
  CallClientFunction("InspectorFrontendAPI.setDockSide", &dock_side, NULL,
                     NULL);
  base::FundamentalValue docked(IsDocked());
  CallClientFunction("InspectorFrontendAPI.setAttachedWindow", &docked, NULL,
                     NULL);
}

void DevToolsWindow::Hide() {
  if (IsDocked()) {
    // Update dev tools to reflect removed dev tools window.
    BrowserWindow* inspected_window = GetInspectedBrowserWindow();
    if (inspected_window)
      inspected_window->UpdateDevTools();
    // In case of docked web_contents_, we own it so delete here.
    delete web_contents_;

    delete this;
  } else {
    // First, initiate self-destruct to free all the registrars.
    // Then close all tabs. Browser will take care of deleting web_contents_
    // for us.
    Browser* browser = browser_;
    delete this;
    browser->tab_strip_model()->CloseAllTabs();
  }
}

void DevToolsWindow::ScheduleAction(DevToolsToggleAction action) {
  action_on_load_ = action;
  if (is_loaded_)
    DoAction();
}

void DevToolsWindow::DoAction() {
  UpdateFrontendDockSide();
  switch (action_on_load_) {
    case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
      CallClientFunction("InspectorFrontendAPI.showConsole", NULL, NULL, NULL);
      break;

    case DEVTOOLS_TOGGLE_ACTION_INSPECT:
      CallClientFunction("InspectorFrontendAPI.enterInspectElementMode", NULL,
                         NULL, NULL);
      break;

    case DEVTOOLS_TOGGLE_ACTION_SHOW:
    case DEVTOOLS_TOGGLE_ACTION_TOGGLE:
      // Do nothing.
      break;

    default:
      NOTREACHED();
      break;
  }
  action_on_load_ = DEVTOOLS_TOGGLE_ACTION_SHOW;
}

void DevToolsWindow::UpdateTheme() {
  ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_);
  DCHECK(tp);

  std::string command("InspectorFrontendAPI.setToolbarColors(\"" +
      SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) +
      "\", \"" +
      SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) +
      "\")");
  web_contents_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
      string16(), ASCIIToUTF16(command));
}

void DevToolsWindow::AddDevToolsExtensionsToClient() {
  content::WebContents* inspected_web_contents = GetInspectedWebContents();
  if (inspected_web_contents) {
    SessionTabHelper* session_tab_helper =
        SessionTabHelper::FromWebContents(inspected_web_contents);
    if (session_tab_helper) {
      base::FundamentalValue tabId(session_tab_helper->session_id().id());
      CallClientFunction("WebInspector.setInspectedTabId", &tabId, NULL, NULL);
    }
  }

  Profile* profile =
      Profile::FromBrowserContext(web_contents_->GetBrowserContext());
  const ExtensionService* extension_service = extensions::ExtensionSystem::Get(
      profile->GetOriginalProfile())->extension_service();
  if (!extension_service)
    return;
  const ExtensionSet* extensions = extension_service->extensions();

  ListValue results;
  for (ExtensionSet::const_iterator extension(extensions->begin());
       extension != extensions->end(); ++extension) {
    if (extensions::ManifestURL::GetDevToolsPage(extension->get()).is_empty())
      continue;
    DictionaryValue* extension_info = new DictionaryValue();
    extension_info->Set(
        "startPage",
        new StringValue(
            extensions::ManifestURL::GetDevToolsPage(extension->get()).spec()));
    extension_info->Set("name", new StringValue((*extension)->name()));
    extension_info->Set(
        "exposeExperimentalAPIs",
        new base::FundamentalValue((*extension)->HasAPIPermission(
            extensions::APIPermission::kExperimental)));
    results.Append(extension_info);
  }
  CallClientFunction("WebInspector.addExtensions", &results, NULL, NULL);
}

void DevToolsWindow::CallClientFunction(const std::string& function_name,
                                        const Value* arg1,
                                        const Value* arg2,
                                        const Value* arg3) {
  std::string params;
  if (arg1) {
    std::string json;
    base::JSONWriter::Write(arg1, &json);
    params.append(json);
    if (arg2) {
      base::JSONWriter::Write(arg2, &json);
      params.append(", " + json);
      if (arg3) {
        base::JSONWriter::Write(arg3, &json);
        params.append(", " + json);
      }
    }
  }
  string16 javascript = ASCIIToUTF16(function_name + "(" + params + ");");
  web_contents_->GetRenderViewHost()->
      ExecuteJavascriptInWebFrame(string16(), javascript);
}

void DevToolsWindow::UpdateBrowserToolbar() {
  BrowserWindow* inspected_window = GetInspectedBrowserWindow();
  if (inspected_window)
    inspected_window->UpdateToolbar(NULL);
}

bool DevToolsWindow::IsDocked() {
  return dock_side_ != DEVTOOLS_DOCK_SIDE_UNDOCKED;
}

void DevToolsWindow::Restore() {
  if (dock_side_ == DEVTOOLS_DOCK_SIDE_MINIMIZED)
    SetDockSide(SideToString(dock_side_before_minimized_));
}

content::WebContents* DevToolsWindow::GetInspectedWebContents() {
  return inspected_contents_observer_ ?
      inspected_contents_observer_->web_contents() : NULL;
}
