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

#include "base/files/file_path.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/extensions_client.h"
#include "extensions/strings/grit/extensions_strings.h"
#include "net/base/escape.h"
#include "ui/base/l10n/l10n_util.h"

using content::BrowserThread;

namespace {
// Prefix for message parameters indicating that the parameter needs to
// be translated from an extension id to the extension name.
const char kTranslate[] = "TO_TRANSLATE:";
const size_t kMaxNumberOfParameters = 4;
}

namespace extensions {

//
// Warning
//

Warning::Warning(
    WarningType type,
    const std::string& extension_id,
    int message_id,
    const std::vector<std::string>& message_parameters)
    : type_(type),
      extension_id_(extension_id),
      message_id_(message_id),
      message_parameters_(message_parameters) {
  // These are invalid here because they do not have corresponding warning
  // messages in the UI.
  CHECK_NE(type, kInvalid);
  CHECK_NE(type, kMaxWarningType);
  CHECK_LE(message_parameters.size(), kMaxNumberOfParameters);
}

Warning::Warning(const Warning& other)
  : type_(other.type_),
    extension_id_(other.extension_id_),
    message_id_(other.message_id_),
    message_parameters_(other.message_parameters_) {}

Warning::~Warning() {
}

Warning& Warning::operator=(const Warning& other) {
  type_ = other.type_;
  extension_id_ = other.extension_id_;
  message_id_ = other.message_id_;
  message_parameters_ = other.message_parameters_;
  return *this;
}

// static
Warning Warning::CreateNetworkDelayWarning(
    const std::string& extension_id) {
  std::vector<std::string> message_parameters;
  message_parameters.push_back(ExtensionsClient::Get()->GetProductName());
  return Warning(
      kNetworkDelay,
      extension_id,
      IDS_EXTENSION_WARNINGS_NETWORK_DELAY,
      message_parameters);
}

// static
Warning Warning::CreateNetworkConflictWarning(const std::string& extension_id) {
  std::vector<std::string> message_parameters;
  return Warning(
      kNetworkConflict,
      extension_id,
      IDS_EXTENSION_WARNINGS_NETWORK_CONFLICT,
      message_parameters);
}

// static
Warning Warning::CreateRedirectConflictWarning(
    const std::string& extension_id,
    const std::string& winning_extension_id,
    const GURL& attempted_redirect_url,
    const GURL& winning_redirect_url) {
  std::vector<std::string> message_parameters;
  message_parameters.push_back(attempted_redirect_url.spec());
  message_parameters.push_back(kTranslate + winning_extension_id);
  message_parameters.push_back(winning_redirect_url.spec());
  return Warning(
      kRedirectConflict,
      extension_id,
      IDS_EXTENSION_WARNINGS_REDIRECT_CONFLICT,
      message_parameters);
}

// static
Warning Warning::CreateRequestHeaderConflictWarning(
    const std::string& extension_id,
    const std::string& winning_extension_id,
    const std::string& conflicting_header) {
  std::vector<std::string> message_parameters;
  message_parameters.push_back(conflicting_header);
  message_parameters.push_back(kTranslate + winning_extension_id);
  return Warning(
      kNetworkConflict,
      extension_id,
      IDS_EXTENSION_WARNINGS_REQUEST_HEADER_CONFLICT,
      message_parameters);
}

// static
Warning Warning::CreateResponseHeaderConflictWarning(
    const std::string& extension_id,
    const std::string& winning_extension_id,
    const std::string& conflicting_header) {
  std::vector<std::string> message_parameters;
  message_parameters.push_back(conflicting_header);
  message_parameters.push_back(kTranslate + winning_extension_id);
  return Warning(
      kNetworkConflict,
      extension_id,
      IDS_EXTENSION_WARNINGS_RESPONSE_HEADER_CONFLICT,
      message_parameters);
}

// static
Warning Warning::CreateCredentialsConflictWarning(
    const std::string& extension_id,
    const std::string& winning_extension_id) {
  std::vector<std::string> message_parameters;
  message_parameters.push_back(kTranslate + winning_extension_id);
  return Warning(
      kNetworkConflict,
      extension_id,
      IDS_EXTENSION_WARNINGS_CREDENTIALS_CONFLICT,
      message_parameters);
}

// static
Warning Warning::CreateRepeatedCacheFlushesWarning(
    const std::string& extension_id) {
  std::vector<std::string> message_parameters;
  message_parameters.push_back(ExtensionsClient::Get()->GetProductName());
  return Warning(
      kRepeatedCacheFlushes,
      extension_id,
      IDS_EXTENSION_WARNINGS_NETWORK_DELAY,
      message_parameters);
}

// static
Warning Warning::CreateDownloadFilenameConflictWarning(
    const std::string& losing_extension_id,
    const std::string& winning_extension_id,
    const base::FilePath& losing_filename,
    const base::FilePath& winning_filename) {
  std::vector<std::string> message_parameters;
  message_parameters.push_back(base::UTF16ToUTF8(
      losing_filename.LossyDisplayName()));
  message_parameters.push_back(kTranslate + winning_extension_id);
  message_parameters.push_back(base::UTF16ToUTF8(
      winning_filename.LossyDisplayName()));
  return Warning(
      kDownloadFilenameConflict,
      losing_extension_id,
      IDS_EXTENSION_WARNINGS_DOWNLOAD_FILENAME_CONFLICT,
      message_parameters);
}

// static
Warning Warning::CreateReloadTooFrequentWarning(
    const std::string& extension_id) {
  std::vector<std::string> message_parameters;
  return Warning(kReloadTooFrequent,
                          extension_id,
                          IDS_EXTENSION_WARNING_RELOAD_TOO_FREQUENT,
                          message_parameters);
}

std::string Warning::GetLocalizedMessage(const ExtensionSet* extensions) const {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);

  // These parameters may be unsafe (URLs and Extension names) and need
  // to be HTML-escaped before being embedded in the UI. Also extension IDs
  // are translated to full extension names.
  std::vector<base::string16> final_parameters;
  for (size_t i = 0; i < message_parameters_.size(); ++i) {
    std::string message = message_parameters_[i];
    if (StartsWithASCII(message, kTranslate, true)) {
      std::string extension_id = message.substr(sizeof(kTranslate) - 1);
      const extensions::Extension* extension =
          extensions->GetByID(extension_id);
      message = extension ? extension->name() : extension_id;
    }
    final_parameters.push_back(base::UTF8ToUTF16(net::EscapeForHTML(message)));
  }

  COMPILE_ASSERT(kMaxNumberOfParameters == 4u, YouNeedToAddMoreCaseStatements);
  switch (final_parameters.size()) {
    case 0:
      return l10n_util::GetStringUTF8(message_id_);
    case 1:
      return l10n_util::GetStringFUTF8(message_id_, final_parameters[0]);
    case 2:
      return l10n_util::GetStringFUTF8(message_id_, final_parameters[0],
          final_parameters[1]);
    case 3:
      return l10n_util::GetStringFUTF8(message_id_, final_parameters[0],
          final_parameters[1], final_parameters[2]);
    case 4:
      return l10n_util::GetStringFUTF8(message_id_, final_parameters[0],
          final_parameters[1], final_parameters[2], final_parameters[3]);
    default:
      NOTREACHED();
      return std::string();
  }
}

bool operator<(const Warning& a, const Warning& b) {
  if (a.extension_id() != b.extension_id())
    return a.extension_id() < b.extension_id();
  return a.warning_type() < b.warning_type();
}

}  // namespace extensions
