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

#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/convert_web_app.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/extensions/manifest_handlers/app_icon_color_info.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/common/extensions/manifest_handlers/app_theme_color_info.h"
#include "chrome/common/extensions/manifest_handlers/linked_app_icons.h"
#include "components/crx_file/id_util.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/protocol/app_specifics.pb.h"
#include "components/sync/protocol/extension_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_url_handlers.h"

using syncer::StringOrdinal;

namespace extensions {

namespace {

std::string GetExtensionSpecificsLogMessage(
    const sync_pb::ExtensionSpecifics& specifics) {
  return base::StringPrintf(
      "id: %s\nversion: %s\nupdate_url: %s\nenabled: %i\ndisable_reasons: %i",
      specifics.id().c_str(),
      specifics.version().c_str(),
      specifics.update_url().c_str(),
      specifics.enabled(),
      specifics.disable_reasons());
}

enum BadSyncDataReason {
  // Invalid extension ID.
  BAD_EXTENSION_ID,

  // Invalid version.
  BAD_VERSION,

  // Invalid update URL.
  BAD_UPDATE_URL,

  // No ExtensionSpecifics in the EntitySpecifics.
  NO_EXTENSION_SPECIFICS,

  // Not used anymore; still here because of UMA.
  DEPRECATED_BAD_DISABLE_REASONS,

  // Must be at the end.
  NUM_BAD_SYNC_DATA_REASONS
};

void RecordBadSyncData(BadSyncDataReason reason) {
  UMA_HISTOGRAM_ENUMERATION("Extensions.BadSyncDataReason", reason,
                            NUM_BAD_SYNC_DATA_REASONS);
}

}  // namespace

ExtensionSyncData::LinkedAppIconInfo::LinkedAppIconInfo() {
}

ExtensionSyncData::LinkedAppIconInfo::~LinkedAppIconInfo() {
}

ExtensionSyncData::ExtensionSyncData()
    : is_app_(false),
      uninstalled_(false),
      enabled_(false),
      supports_disable_reasons_(false),
      disable_reasons_(disable_reason::DISABLE_NONE),
      incognito_enabled_(false),
      remote_install_(false),
      launch_type_(LAUNCH_TYPE_INVALID) {}

ExtensionSyncData::ExtensionSyncData(const Extension& extension,
                                     bool enabled,
                                     int disable_reasons,
                                     bool incognito_enabled,
                                     bool remote_install,
                                     const GURL& update_url)
    : ExtensionSyncData(extension,
                        enabled,
                        disable_reasons,
                        incognito_enabled,
                        remote_install,
                        update_url,
                        StringOrdinal(),
                        StringOrdinal(),
                        LAUNCH_TYPE_INVALID) {}

ExtensionSyncData::ExtensionSyncData(const Extension& extension,
                                     bool enabled,
                                     int disable_reasons,
                                     bool incognito_enabled,
                                     bool remote_install,
                                     const GURL& update_url,
                                     const StringOrdinal& app_launch_ordinal,
                                     const StringOrdinal& page_ordinal,
                                     extensions::LaunchType launch_type)
    : is_app_(extension.is_app()),
      id_(extension.id()),
      uninstalled_(false),
      enabled_(enabled),
      supports_disable_reasons_(true),
      disable_reasons_(disable_reasons),
      incognito_enabled_(incognito_enabled),
      remote_install_(remote_install),
      version_(extension.from_bookmark() ? base::Version("0")
                                         : extension.version()),
      update_url_(update_url),
      name_(extension.non_localized_name()),
      app_launch_ordinal_(app_launch_ordinal),
      page_ordinal_(page_ordinal),
      launch_type_(launch_type) {
  if (is_app_ && extension.from_bookmark()) {
    bookmark_app_description_ = extension.description();
    bookmark_app_url_ = AppLaunchInfo::GetLaunchWebURL(&extension).spec();
    bookmark_app_scope_ = GetScopeURLFromBookmarkApp(&extension).spec();
    bookmark_app_icon_color_ = AppIconColorInfo::GetIconColorString(&extension);
    bookmark_app_theme_color_ = AppThemeColorInfo::GetThemeColor(&extension);
    extensions::LinkedAppIcons icons =
        LinkedAppIcons::GetLinkedAppIcons(&extension);
    for (const auto& icon : icons.icons) {
      LinkedAppIconInfo linked_icon;
      linked_icon.url = icon.url;
      linked_icon.size = icon.size;
      linked_icons_.push_back(linked_icon);
    }
  }
}

ExtensionSyncData::ExtensionSyncData(const ExtensionSyncData& other) = default;

ExtensionSyncData::~ExtensionSyncData() {}

// static
std::unique_ptr<ExtensionSyncData> ExtensionSyncData::CreateFromSyncData(
    const syncer::SyncData& sync_data) {
  std::unique_ptr<ExtensionSyncData> data(new ExtensionSyncData);
  if (data->PopulateFromSyncData(sync_data))
    return data;
  return nullptr;
}

// static
std::unique_ptr<ExtensionSyncData> ExtensionSyncData::CreateFromSyncChange(
    const syncer::SyncChange& sync_change) {
  std::unique_ptr<ExtensionSyncData> data(
      CreateFromSyncData(sync_change.sync_data()));
  if (!data.get())
    return nullptr;

  if (sync_change.change_type() == syncer::SyncChange::ACTION_DELETE)
    data->uninstalled_ = true;
  return data;
}

syncer::SyncData ExtensionSyncData::GetSyncData() const {
  sync_pb::EntitySpecifics specifics;
  if (is_app_)
    ToAppSpecifics(specifics.mutable_app());
  else
    ToExtensionSpecifics(specifics.mutable_extension());

  return syncer::SyncData::CreateLocalData(id_, name_, specifics);
}

syncer::SyncChange ExtensionSyncData::GetSyncChange(
    syncer::SyncChange::SyncChangeType change_type) const {
  return syncer::SyncChange(FROM_HERE, change_type, GetSyncData());
}

void ExtensionSyncData::ToExtensionSpecifics(
    sync_pb::ExtensionSpecifics* specifics) const {
  DCHECK(crx_file::id_util::IdIsValid(id_));
  specifics->set_id(id_);
  specifics->set_update_url(update_url_.spec());
  specifics->set_version(version_.GetString());
  specifics->set_enabled(enabled_);
  if (supports_disable_reasons_)
    specifics->set_disable_reasons(disable_reasons_);
  specifics->set_incognito_enabled(incognito_enabled_);
  specifics->set_remote_install(remote_install_);
  specifics->set_name(name_);
}

void ExtensionSyncData::ToAppSpecifics(sync_pb::AppSpecifics* specifics) const {
  DCHECK(specifics);
  // Only sync the ordinal values and launch type if they are valid.
  if (app_launch_ordinal_.IsValid())
    specifics->set_app_launch_ordinal(app_launch_ordinal_.ToInternalValue());
  if (page_ordinal_.IsValid())
    specifics->set_page_ordinal(page_ordinal_.ToInternalValue());

  sync_pb::AppSpecifics::LaunchType sync_launch_type =
      static_cast<sync_pb::AppSpecifics::LaunchType>(launch_type_);

  // The corresponding validation of this value during processing of an
  // ExtensionSyncData is in ExtensionSyncService::ApplySyncData.
  if (launch_type_ >= LAUNCH_TYPE_FIRST && launch_type_ < NUM_LAUNCH_TYPES &&
      sync_pb::AppSpecifics_LaunchType_IsValid(sync_launch_type)) {
    specifics->set_launch_type(sync_launch_type);
  }

  if (!bookmark_app_url_.empty())
    specifics->set_bookmark_app_url(bookmark_app_url_);

  if (!bookmark_app_description_.empty())
    specifics->set_bookmark_app_description(bookmark_app_description_);

  if (!bookmark_app_scope_.empty())
    specifics->set_bookmark_app_scope(bookmark_app_scope_);

  if (!bookmark_app_icon_color_.empty())
    specifics->set_bookmark_app_icon_color(bookmark_app_icon_color_);

  if (bookmark_app_theme_color_)
    specifics->set_bookmark_app_theme_color(bookmark_app_theme_color_.value());

  for (const auto& linked_icon : linked_icons_) {
    sync_pb::LinkedAppIconInfo* linked_app_icon_info =
        specifics->add_linked_app_icons();
    DCHECK(linked_icon.url.is_valid());
    linked_app_icon_info->set_url(linked_icon.url.spec());
    linked_app_icon_info->set_size(linked_icon.size);
  }

  ToExtensionSpecifics(specifics->mutable_extension());
}

bool ExtensionSyncData::PopulateFromExtensionSpecifics(
    const sync_pb::ExtensionSpecifics& specifics) {
  if (!crx_file::id_util::IdIsValid(specifics.id())) {
    LOG(ERROR) << "Attempt to sync bad ExtensionSpecifics (bad ID):\n"
               << GetExtensionSpecificsLogMessage(specifics);
    RecordBadSyncData(BAD_EXTENSION_ID);
    return false;
  }

  base::Version specifics_version(specifics.version());
  if (!specifics_version.IsValid()) {
    LOG(ERROR) << "Attempt to sync bad ExtensionSpecifics (bad version):\n"
               << GetExtensionSpecificsLogMessage(specifics);
    RecordBadSyncData(BAD_VERSION);
    return false;
  }

  // The update URL must be either empty or valid.
  GURL specifics_update_url(specifics.update_url());
  if (!specifics_update_url.is_empty() && !specifics_update_url.is_valid()) {
    LOG(ERROR) << "Attempt to sync bad ExtensionSpecifics (bad update URL):\n"
               << GetExtensionSpecificsLogMessage(specifics);
    RecordBadSyncData(BAD_UPDATE_URL);
    return false;
  }

  id_ = specifics.id();
  update_url_ = specifics_update_url;
  version_ = specifics_version;
  enabled_ = specifics.enabled();
  supports_disable_reasons_ = specifics.has_disable_reasons();
  disable_reasons_ = specifics.disable_reasons();
  incognito_enabled_ = specifics.incognito_enabled();
  remote_install_ = specifics.remote_install();
  name_ = specifics.name();
  return true;
}

bool ExtensionSyncData::PopulateFromAppSpecifics(
    const sync_pb::AppSpecifics& specifics) {
  if (!PopulateFromExtensionSpecifics(specifics.extension()))
    return false;

  is_app_ = true;

  app_launch_ordinal_ = syncer::StringOrdinal(specifics.app_launch_ordinal());
  page_ordinal_ = syncer::StringOrdinal(specifics.page_ordinal());

  launch_type_ = specifics.has_launch_type()
      ? static_cast<extensions::LaunchType>(specifics.launch_type())
      : LAUNCH_TYPE_INVALID;

  bookmark_app_url_ = specifics.bookmark_app_url();
  bookmark_app_description_ = specifics.bookmark_app_description();
  bookmark_app_scope_ = specifics.bookmark_app_scope();
  bookmark_app_icon_color_ = specifics.bookmark_app_icon_color();
  if (specifics.has_bookmark_app_theme_color())
    bookmark_app_theme_color_ = specifics.bookmark_app_theme_color();

  for (int i = 0; i < specifics.linked_app_icons_size(); ++i) {
    const sync_pb::LinkedAppIconInfo& linked_app_icon_info =
        specifics.linked_app_icons(i);
    if (linked_app_icon_info.has_url() && linked_app_icon_info.has_size()) {
      LinkedAppIconInfo linked_icon;
      linked_icon.url = GURL(linked_app_icon_info.url());
      linked_icon.size = linked_app_icon_info.size();
      linked_icons_.push_back(linked_icon);
    }
  }

  return true;
}

bool ExtensionSyncData::PopulateFromSyncData(
    const syncer::SyncData& sync_data) {
  const sync_pb::EntitySpecifics& entity_specifics = sync_data.GetSpecifics();

  if (entity_specifics.has_app())
    return PopulateFromAppSpecifics(entity_specifics.app());

  if (entity_specifics.has_extension())
    return PopulateFromExtensionSpecifics(entity_specifics.extension());

  LOG(ERROR) << "Attempt to sync bad EntitySpecifics: no extension data.";
  RecordBadSyncData(NO_EXTENSION_SPECIFICS);
  return false;
}

}  // namespace extensions
