// 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/extensions/extension_uninstall_dialog.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/chrome_app_icon_service.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/native_window_tracker.h"
#include "chrome/grit/generated_resources.h"
#include "extensions/browser/extension_dialog_auto_confirm.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/image_loader.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_urls.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/manifest_url_handlers.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/layout.h"
#include "ui/base/page_transition_types.h"
#include "ui/base/window_open_disposition.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"

namespace extensions {

namespace {

constexpr int kIconSize = 64;

constexpr char kExtensionRemovedError[] =
    "Extension was removed before dialog closed.";

constexpr char kReferrerId[] = "chrome-remove-extension-dialog";

float GetScaleFactor(gfx::NativeWindow window) {
  const display::Screen* screen = display::Screen::GetScreen();
  if (!screen)
    return 1.0;  // Happens in unit_tests.
  if (window)
    return screen->GetDisplayNearestWindow(window).device_scale_factor();
  return screen->GetPrimaryDisplay().device_scale_factor();
}

}  // namespace

ExtensionUninstallDialog::ExtensionUninstallDialog(
    Profile* profile,
    gfx::NativeWindow parent,
    ExtensionUninstallDialog::Delegate* delegate)
    : profile_(profile), parent_(parent), delegate_(delegate), observer_(this) {
  if (parent)
    parent_window_tracker_ = NativeWindowTracker::Create(parent);
}

ExtensionUninstallDialog::~ExtensionUninstallDialog() = default;

void ExtensionUninstallDialog::ConfirmUninstallByExtension(
    const scoped_refptr<const Extension>& extension,
    const scoped_refptr<const Extension>& triggering_extension,
    UninstallReason reason,
    UninstallSource source) {
  triggering_extension_ = triggering_extension;
  ConfirmUninstall(extension, reason, source);
}

void ExtensionUninstallDialog::ConfirmUninstall(
    const scoped_refptr<const Extension>& extension,
    UninstallReason reason,
    UninstallSource source) {
  DCHECK(thread_checker_.CalledOnValidThread());

  UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallSource", source,
                            NUM_UNINSTALL_SOURCES);

  extension_ = extension;
  uninstall_reason_ = reason;

  if (parent() && parent_window_tracker_->WasNativeWindowClosed()) {
    OnDialogClosed(CLOSE_ACTION_CANCELED);
    return;
  }

  // Track that extension uninstalled externally.
  DCHECK(!observer_.IsObserving(ExtensionRegistry::Get(profile_)));
  observer_.Add(ExtensionRegistry::Get(profile_));

  // Dialog will be shown once icon is loaded.
  DCHECK(!dialog_shown_);
  icon_ = ChromeAppIconService::Get(profile_)->CreateIcon(this, extension->id(),
                                                          kIconSize);
  icon_->image_skia().GetRepresentation(GetScaleFactor(parent_));
}

void ExtensionUninstallDialog::OnIconUpdated(ChromeAppIcon* icon) {
  // Ignore initial update.
  if (!icon_ || dialog_shown_)
    return;

  DCHECK_EQ(icon, icon_.get());

  dialog_shown_ = true;

  if (parent() && parent_window_tracker_->WasNativeWindowClosed()) {
    OnDialogClosed(CLOSE_ACTION_CANCELED);
    return;
  }

  switch (ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
    case ScopedTestDialogAutoConfirm::NONE:
      Show();
      break;
    case ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION:
      OnDialogClosed(CLOSE_ACTION_UNINSTALL_AND_REPORT_ABUSE);
      break;
    case ScopedTestDialogAutoConfirm::ACCEPT:
      OnDialogClosed(CLOSE_ACTION_UNINSTALL);
      break;
    case ScopedTestDialogAutoConfirm::CANCEL:
      OnDialogClosed(CLOSE_ACTION_CANCELED);
      break;
  }
}

void ExtensionUninstallDialog::OnExtensionUninstalled(
    content::BrowserContext* browser_context,
    const Extension* extension,
    UninstallReason reason) {
  // Handle the case when extension was uninstalled externally and we have to
  // close current dialog.
  if (extension != extension_)
    return;

  delegate_->OnExtensionUninstallDialogClosed(
      false, base::ASCIIToUTF16(kExtensionRemovedError));
}

std::string ExtensionUninstallDialog::GetHeadingText() {
  if (triggering_extension_) {
    return l10n_util::GetStringFUTF8(
        IDS_EXTENSION_PROGRAMMATIC_UNINSTALL_PROMPT_HEADING,
        base::UTF8ToUTF16(triggering_extension_->name()),
        base::UTF8ToUTF16(extension_->name()));
  }
  return l10n_util::GetStringFUTF8(IDS_EXTENSION_UNINSTALL_PROMPT_HEADING,
                                   base::UTF8ToUTF16(extension_->name()));
}

bool ExtensionUninstallDialog::ShouldShowReportAbuseCheckbox() const {
  return ManifestURL::UpdatesFromGallery(extension_.get());
}

void ExtensionUninstallDialog::OnDialogClosed(CloseAction action) {
  // We don't want to artificially weight any of the options, so only record if
  // reporting abuse was available.
  if (ShouldShowReportAbuseCheckbox()) {
    UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallDialogAction",
                              action,
                              CLOSE_ACTION_LAST);
  }

  bool success = false;
  base::string16 error;
  switch (action) {
    case CLOSE_ACTION_UNINSTALL_AND_REPORT_ABUSE:
      // If the extension specifies a custom uninstall page via
      // chrome.runtime.setUninstallURL, then at uninstallation its uninstall
      // page opens. To ensure that the CWS Report Abuse page is the active tab
      // at uninstallation, HandleReportAbuse() is called after Uninstall().
      success = Uninstall(&error);
      HandleReportAbuse();
      break;
    case CLOSE_ACTION_UNINSTALL: {
      success = Uninstall(&error);
      break;
    }
    case CLOSE_ACTION_CANCELED:
      error = base::ASCIIToUTF16("User canceled uninstall dialog");
      break;
    case CLOSE_ACTION_LAST:
      NOTREACHED();
  }
  delegate_->OnExtensionUninstallDialogClosed(success, error);
}

bool ExtensionUninstallDialog::Uninstall(base::string16* error) {
  const Extension* current_extension =
      ExtensionRegistry::Get(profile_)->GetExtensionById(
          extension_->id(), ExtensionRegistry::EVERYTHING);
  if (current_extension) {
    // Prevent notifications triggered by our request.
    observer_.RemoveAll();
    return ExtensionSystem::Get(profile_)
        ->extension_service()
        ->UninstallExtension(extension_->id(), uninstall_reason_, error);
  }
  *error = base::ASCIIToUTF16(kExtensionRemovedError);
  return false;
}

void ExtensionUninstallDialog::HandleReportAbuse() {
  NavigateParams params(
      profile_,
      extension_urls::GetWebstoreReportAbuseUrl(extension_->id(), kReferrerId),
      ui::PAGE_TRANSITION_LINK);
  params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
  Navigate(&params);
}

}  // namespace extensions
