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

#include <stddef.h>
#include <stdint.h>

#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/base64.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/json/json_file_value_serializer.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/web_applications/components/web_app_helpers.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
#include "chrome/common/extensions/manifest_handlers/app_theme_color_info.h"
#include "chrome/common/web_application_info.h"
#include "crypto/sha2.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
#include "extensions/common/file_util.h"
#include "extensions/common/image_util.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/file_handler_info.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/safe_integer_conversions.h"
#include "url/gurl.h"

namespace extensions {

namespace keys = manifest_keys;

namespace {
const char kIconsDirName[] = "icons";
const char kScopeUrlHandlerId[] = "scope";

std::unique_ptr<base::DictionaryValue> CreateFileHandlersForBookmarkApp(
    blink::Manifest::FileHandler file_handler) {
  base::Value file_handlers(base::Value::Type::DICTIONARY);

  for (const auto& handler : file_handler) {
    base::Value file_handler(base::Value::Type::DICTIONARY);
    file_handler.SetKey(keys::kFileHandlerIncludeDirectories,
                        base::Value(false));
    file_handler.SetKey(keys::kFileHandlerVerb,
                        base::Value(extensions::file_handler_verbs::kOpenWith));

    base::Value mime_types(base::Value::Type::LIST);
    base::Value file_extensions(base::Value::Type::LIST);

    for (const auto& acceptsUTF16 : handler.accept) {
      std::string acceptsUTF8 = base::UTF16ToUTF8(acceptsUTF16);
      if (acceptsUTF8.size() == 0)
        continue;

      if (acceptsUTF8[0] == '.') {
        file_extensions.GetList().push_back(base::Value(acceptsUTF8.substr(1)));
      } else {
        mime_types.GetList().push_back(base::Value(acceptsUTF8));
      }
    }

    file_handler.SetKey(keys::kFileHandlerTypes, std::move(mime_types));
    file_handler.SetKey(keys::kFileHandlerExtensions,
                        std::move(file_extensions));

    file_handlers.SetKey(base::UTF16ToUTF8(handler.name),
                         std::move(file_handler));
  }

  return base::DictionaryValue::From(
      base::Value::ToUniquePtrValue(std::move(file_handlers)));
}

}  // namespace

std::unique_ptr<base::DictionaryValue> CreateURLHandlersForBookmarkApp(
    const GURL& scope_url,
    const base::string16& title) {
  auto matches = std::make_unique<base::ListValue>();
  matches->AppendString(scope_url.GetOrigin().Resolve(scope_url.path()).spec() +
                        "*");

  auto scope_handler = std::make_unique<base::DictionaryValue>();
  scope_handler->SetList(keys::kMatches, std::move(matches));
  // The URL handler title is not used anywhere but we set it to the
  // web app's title just in case.
  scope_handler->SetString(keys::kUrlHandlerTitle, base::UTF16ToUTF8(title));

  auto url_handlers = std::make_unique<base::DictionaryValue>();
  // Use "scope" as the url handler's identifier.
  url_handlers->SetDictionary(kScopeUrlHandlerId, std::move(scope_handler));
  return url_handlers;
}

GURL GetScopeURLFromBookmarkApp(const Extension* extension) {
  DCHECK(extension->from_bookmark());
  const std::vector<UrlHandlerInfo>* url_handlers =
      UrlHandlers::GetUrlHandlers(extension);
  if (!url_handlers)
    return GURL();

  // A Bookmark app created by us should only have a url_handler with id
  // kScopeUrlHandlerId. This URL handler should have a single pattern which
  // corresponds to the web manifest's scope. The URL handler's pattern should
  // be the Web Manifest's scope's origin + path with a wildcard, '*', appended
  // to it.
  auto handler_it = std::find_if(
      url_handlers->begin(), url_handlers->end(),
      [](const UrlHandlerInfo& info) { return info.id == kScopeUrlHandlerId; });
  if (handler_it == url_handlers->end()) {
    return GURL();
  }

  const auto& patterns = handler_it->patterns;
  DCHECK(patterns.size() == 1);
  const auto& pattern_iter = patterns.begin();
  // Remove the '*' character at the end (which was added when creating the URL
  // handler, see CreateURLHandlersForBookmarkApp()).
  const std::string& pattern_str = pattern_iter->GetAsString();
  DCHECK_EQ(pattern_str.back(), '*');
  return GURL(pattern_str.substr(0, pattern_str.size() - 1));
}

// Generates a version for the converted app using the current date. This isn't
// really needed, but it seems like useful information.
std::string ConvertTimeToExtensionVersion(const base::Time& create_time) {
  base::Time::Exploded create_time_exploded;
  create_time.UTCExplode(&create_time_exploded);

  double micros = static_cast<double>(
      (create_time_exploded.millisecond *
       base::Time::kMicrosecondsPerMillisecond) +
      (create_time_exploded.second * base::Time::kMicrosecondsPerSecond) +
      (create_time_exploded.minute * base::Time::kMicrosecondsPerMinute) +
      (create_time_exploded.hour * base::Time::kMicrosecondsPerHour));
  double day_fraction = micros / base::Time::kMicrosecondsPerDay;
  int stamp =
      gfx::ToRoundedInt(day_fraction * std::numeric_limits<uint16_t>::max());

  return base::StringPrintf("%i.%i.%i.%i", create_time_exploded.year,
                            create_time_exploded.month,
                            create_time_exploded.day_of_month, stamp);
}

scoped_refptr<Extension> ConvertWebAppToExtension(
    const WebApplicationInfo& web_app,
    const base::Time& create_time,
    const base::FilePath& extensions_dir,
    int extra_creation_flags,
    Manifest::Location install_source) {
  base::FilePath install_temp_dir =
      file_util::GetInstallTempDir(extensions_dir);
  if (install_temp_dir.empty()) {
    LOG(ERROR) << "Could not get path to profile temporary directory.";
    return NULL;
  }

  base::ScopedTempDir temp_dir;
  if (!temp_dir.CreateUniqueTempDirUnderPath(install_temp_dir)) {
    LOG(ERROR) << "Could not create temporary directory.";
    return NULL;
  }

  // Create the manifest
  std::unique_ptr<base::DictionaryValue> root(new base::DictionaryValue);
  root->SetString(keys::kPublicKey,
                  web_app::GenerateAppKeyFromURL(web_app.app_url));
  root->SetString(keys::kName, base::UTF16ToUTF8(web_app.title));
  root->SetString(keys::kVersion, ConvertTimeToExtensionVersion(create_time));
  root->SetString(keys::kDescription, base::UTF16ToUTF8(web_app.description));
  root->SetString(keys::kLaunchWebURL, web_app.app_url.spec());
  if (web_app.generated_icon_color != SK_ColorTRANSPARENT) {
    root->SetString(keys::kAppIconColor, image_util::GenerateHexColorString(
                                             web_app.generated_icon_color));
  }

  if (web_app.theme_color) {
    root->SetString(keys::kAppThemeColor, color_utils::SkColorToRgbaString(
                                              web_app.theme_color.value()));
  }

  if (!web_app.scope.is_empty()) {
    root->SetDictionary(keys::kUrlHandlers, CreateURLHandlersForBookmarkApp(
                                                web_app.scope, web_app.title));
  }

  if (web_app.file_handler) {
    root->SetDictionary(keys::kFileHandlers, CreateFileHandlersForBookmarkApp(
                                                 web_app.file_handler.value()));
  }

  // Add the icons and linked icon information.
  auto icons = std::make_unique<base::DictionaryValue>();
  auto linked_icons = std::make_unique<base::ListValue>();
  for (const auto& icon : web_app.icons) {
    std::string size = base::StringPrintf("%i", icon.width);
    std::string icon_path = base::StringPrintf("%s/%s.png", kIconsDirName,
                                               size.c_str());
    icons->SetString(size, icon_path);

    if (icon.url.is_valid()) {
      std::unique_ptr<base::DictionaryValue> linked_icon(
          new base::DictionaryValue());
      linked_icon->SetString(keys::kLinkedAppIconURL, icon.url.spec());
      linked_icon->SetInteger(keys::kLinkedAppIconSize, icon.width);
      linked_icons->Append(std::move(linked_icon));
    }
  }
  root->Set(keys::kIcons, std::move(icons));
  root->Set(keys::kLinkedAppIcons, std::move(linked_icons));

  // Write the manifest.
  base::FilePath manifest_path = temp_dir.GetPath().Append(kManifestFilename);
  JSONFileValueSerializer serializer(manifest_path);
  if (!serializer.Serialize(*root)) {
    LOG(ERROR) << "Could not serialize manifest.";
    return NULL;
  }

  // Write the icon files.
  base::FilePath icons_dir = temp_dir.GetPath().AppendASCII(kIconsDirName);
  if (!base::CreateDirectory(icons_dir)) {
    LOG(ERROR) << "Could not create icons directory.";
    return NULL;
  }
  for (size_t i = 0; i < web_app.icons.size(); ++i) {
    // Skip unfetched bitmaps.
    if (web_app.icons[i].data.colorType() == kUnknown_SkColorType)
      continue;

    base::FilePath icon_file = icons_dir.AppendASCII(
        base::StringPrintf("%i.png", web_app.icons[i].width));
    std::vector<unsigned char> image_data;
    if (!gfx::PNGCodec::EncodeBGRASkBitmap(web_app.icons[i].data,
                                           false,
                                           &image_data)) {
      LOG(ERROR) << "Could not create icon file.";
      return NULL;
    }

    const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]);
    int size = base::checked_cast<int>(image_data.size());
    if (base::WriteFile(icon_file, image_data_ptr, size) != size) {
      LOG(ERROR) << "Could not write icon file.";
      return NULL;
    }
  }

  // Finally, create the extension object to represent the unpacked directory.
  std::string error;
  scoped_refptr<Extension> extension = Extension::Create(
      temp_dir.GetPath(), install_source, *root,
      Extension::FROM_BOOKMARK | extra_creation_flags, &error);
  if (!extension.get()) {
    LOG(ERROR) << error;
    return NULL;
  }

  temp_dir.Take();  // The caller takes ownership of the directory.
  return extension;
}

}  // namespace extensions
