// 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/ui/app_list/extension_app_item.h"

#include <stddef.h>
#include <utility>

#include "ash/public/cpp/app_list/app_list_config.h"
#include "base/macros.h"
#include "base/metrics/user_metrics.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/chrome_app_icon.h"
#include "chrome/browser/extensions/chrome_app_icon_service.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/launch_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
#include "chrome/browser/ui/app_list/extension_app_context_menu.h"
#include "chrome/browser/ui/app_list/md_icon_normalizer.h"
#include "chrome/browser/ui/extensions/extension_enable_flow.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_metrics.h"
#include "components/prefs/pref_service.h"
#include "components/sync/model/string_ordinal.h"
#include "extensions/browser/app_sorting.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_icon_set.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/manifest_url_handlers.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/display/types/display_constants.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/image/canvas_image_source.h"
#include "ui/gfx/skia_util.h"

using extensions::Extension;

ExtensionAppItem::ExtensionAppItem(
    Profile* profile,
    AppListModelUpdater* model_updater,
    const app_list::AppListSyncableService::SyncItem* sync_item,
    const std::string& extension_id,
    const std::string& extension_name,
    const gfx::ImageSkia& installing_icon,
    bool is_platform_app)
    : ChromeAppListItem(profile, extension_id),
      extension_name_(extension_name),
      installing_icon_(CreateDisabledIcon(installing_icon)),
      is_platform_app_(is_platform_app) {
  Reload();
  if (sync_item && sync_item->item_ordinal.IsValid())
    UpdateFromSync(sync_item);
  else
    SetDefaultPositionIfApplicable(model_updater);

  // Set model updater last to avoid being called during construction.
  set_model_updater(model_updater);
}

ExtensionAppItem::~ExtensionAppItem() = default;

void ExtensionAppItem::Reload() {
  const Extension* extension = GetExtension();
  bool is_installing = !extension;
  SetIsInstalling(is_installing);
  if (is_installing) {
    SetName(extension_name_);
    SetIcon(installing_icon_);
    return;
  }
  SetNameAndShortName(extension->name(), extension->short_name());
  if (!icon_) {
    icon_ = extensions::ChromeAppIconService::Get(profile())->CreateIcon(
        this, extension_id(),
        app_list::AppListConfig::instance().grid_icon_dimension(),
        base::BindRepeating(&app_list::MaybeResizeAndPadIconForMd));
  } else {
    icon_->Reload();
  }
}

void ExtensionAppItem::OnIconUpdated(extensions::ChromeAppIcon* icon) {
  SetIcon(icon->IsValid() ? icon->image_skia() : installing_icon_);
}

const Extension* ExtensionAppItem::GetExtension() const {
  const extensions::ExtensionRegistry* registry =
      extensions::ExtensionRegistry::Get(profile());
  const Extension* extension = registry->GetInstalledExtension(extension_id());
  return extension;
}

bool ExtensionAppItem::RunExtensionEnableFlow() {
  if (extensions::util::IsAppLaunchableWithoutEnabling(extension_id(),
                                                       profile()))
    return false;

  if (!extension_enable_flow_) {
    extension_enable_flow_ =
        std::make_unique<ExtensionEnableFlow>(profile(), extension_id(), this);
    extension_enable_flow_->StartForNativeWindow(nullptr);
  }
  return true;
}

void ExtensionAppItem::Launch(int event_flags) {
  // |extension| could be NULL when it is being unloaded for updating.
  const Extension* extension = GetExtension();
  if (!extension)
    return;

  // Don't auto-enable apps that cannot be launched.
  if (!extensions::util::IsAppLaunchable(extension_id(), profile()))
    return;

  if (RunExtensionEnableFlow())
    return;

  GetController()->LaunchApp(profile(), extension,
                             AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
                             event_flags, display::kInvalidDisplayId);
}

void ExtensionAppItem::ExtensionEnableFlowFinished() {
  extension_enable_flow_.reset();
  // Automatically launch app after enabling.
  Launch(ui::EF_NONE);
}

void ExtensionAppItem::ExtensionEnableFlowAborted(bool user_initiated) {
  extension_enable_flow_.reset();
}

void ExtensionAppItem::Activate(int event_flags) {
  // |extension| could be NULL when it is being unloaded for updating.
  const Extension* extension = GetExtension();
  if (!extension)
    return;

  // Don't auto-enable apps that cannot be launched.
  if (!extensions::util::IsAppLaunchable(extension_id(), profile()))
    return;

  if (RunExtensionEnableFlow())
    return;

  extensions::RecordAppListMainLaunch(extension);
  GetController()->ActivateApp(profile(), extension,
                               AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
                               event_flags);
}

void ExtensionAppItem::GetContextMenuModel(GetMenuModelCallback callback) {
  context_menu_ = std::make_unique<app_list::ExtensionAppContextMenu>(
      this, profile(), extension_id(), GetController());
  context_menu_->set_is_platform_app(is_platform_app_);
  context_menu_->GetMenuModel(std::move(callback));
}

// static
const char ExtensionAppItem::kItemType[] = "ExtensionAppItem";

const char* ExtensionAppItem::GetItemType() const {
  return ExtensionAppItem::kItemType;
}

bool ExtensionAppItem::IsBadged() const {
  return icon_ && icon_->icon_is_badged();
}

app_list::AppContextMenu* ExtensionAppItem::GetAppContextMenu() {
  return context_menu_.get();
}

void ExtensionAppItem::ExecuteLaunchCommand(int event_flags) {
  Launch(event_flags);
}
