// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "printing/print_settings_conversion.h"

#include <stddef.h>

#include <algorithm>
#include <cmath>
#include <memory>
#include <string>
#include <utility>

#include "base/containers/contains.h"
#include "base/containers/fixed_flat_set.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "printing/buildflags/buildflags.h"
#include "printing/mojom/print.mojom.h"
#include "printing/print_job_constants.h"
#include "printing/print_settings.h"
#include "printing/units.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "print_settings_conversion_chromeos.h"
#endif  // BUILDFLAG(IS_CHROMEOS)

namespace printing {

namespace {

// Note: If this code crashes, then the caller has passed in invalid `settings`.
// Fix the caller, instead of trying to avoid the crash here.
PageMargins GetCustomMarginsFromJobSettings(const base::Value::Dict& settings) {
  PageMargins margins_in_points;
  const base::Value::Dict* custom_margins =
      settings.FindDict(kSettingMarginsCustom);
  margins_in_points.top = custom_margins->FindInt(kSettingMarginTop).value();
  margins_in_points.bottom =
      custom_margins->FindInt(kSettingMarginBottom).value();
  margins_in_points.left = custom_margins->FindInt(kSettingMarginLeft).value();
  margins_in_points.right =
      custom_margins->FindInt(kSettingMarginRight).value();
  return margins_in_points;
}

void SetMarginsToJobSettings(const std::string& json_path,
                             const PageMargins& margins,
                             base::Value::Dict& job_settings) {
  base::Value::Dict dict;
  dict.Set(kSettingMarginTop, margins.top);
  dict.Set(kSettingMarginBottom, margins.bottom);
  dict.Set(kSettingMarginLeft, margins.left);
  dict.Set(kSettingMarginRight, margins.right);
  job_settings.Set(json_path, std::move(dict));
}

void SetSizeToJobSettings(const std::string& json_path,
                          const gfx::Size& size,
                          base::Value::Dict& job_settings) {
  base::Value::Dict dict;
  dict.Set("width", size.width());
  dict.Set("height", size.height());
  job_settings.Set(json_path, std::move(dict));
}

void SetRectToJobSettings(const std::string& json_path,
                          const gfx::Rect& rect,
                          base::Value::Dict& job_settings) {
  base::Value::Dict dict;
  dict.Set("x", rect.x());
  dict.Set("y", rect.y());
  dict.Set("width", rect.width());
  dict.Set("height", rect.height());
  job_settings.Set(json_path, std::move(dict));
}

void SetPrintableAreaIfValid(PrintSettings& settings,
                             const gfx::Size& size_microns,
                             const base::Value::Dict& media_size) {
  absl::optional<int> left_microns =
      media_size.FindInt(kSettingsImageableAreaLeftMicrons);
  absl::optional<int> bottom_microns =
      media_size.FindInt(kSettingsImageableAreaBottomMicrons);
  absl::optional<int> right_microns =
      media_size.FindInt(kSettingsImageableAreaRightMicrons);
  absl::optional<int> top_microns =
      media_size.FindInt(kSettingsImageableAreaTopMicrons);
  if (!bottom_microns.has_value() || !left_microns.has_value() ||
      !right_microns.has_value() || !top_microns.has_value()) {
    return;
  }

  // Scale the page size and printable area to device units.
  float x_scale =
      static_cast<float>(settings.device_units_per_inch_size().width()) /
      kMicronsPerInch;
  float y_scale =
      static_cast<float>(settings.device_units_per_inch_size().height()) /
      kMicronsPerInch;
  gfx::Size page_size = gfx::ScaleToRoundedSize(size_microns, x_scale, y_scale);
  // Flip the y-axis since the imageable area origin is at the bottom-left,
  // while the gfx::Rect origin is at the top-left.
  gfx::Rect printable_area = gfx::ScaleToRoundedRect(
      {left_microns.value(), size_microns.height() - top_microns.value(),
       right_microns.value() - left_microns.value(),
       top_microns.value() - bottom_microns.value()},
      x_scale, y_scale);
  // Sanity check that the printable area makes sense.
  if (printable_area.IsEmpty() ||
      !gfx::Rect(page_size).Contains(printable_area)) {
    return;
  }
  settings.SetPrinterPrintableArea(page_size, printable_area,
                                   /*landscape_needs_flip=*/true);
}

}  // namespace

PageRanges GetPageRangesFromJobSettings(const base::Value::Dict& job_settings) {
  PageRanges page_ranges;
  const base::Value::List* page_range_array =
      job_settings.FindList(kSettingPageRange);
  if (!page_range_array) {
    return page_ranges;
  }

  for (const base::Value& page_range : *page_range_array) {
    if (!page_range.is_dict()) {
      continue;
    }

    const auto& dict = page_range.GetDict();
    absl::optional<int> from = dict.FindInt(kSettingPageRangeFrom);
    absl::optional<int> to = dict.FindInt(kSettingPageRangeTo);
    if (!from.has_value() || !to.has_value()) {
      continue;
    }

    // Page numbers are 1-based in the dictionary.
    // Page numbers are 0-based for the printing context.
    page_ranges.push_back(PageRange{static_cast<uint32_t>(from.value() - 1),
                                    static_cast<uint32_t>(to.value() - 1)});
  }
  return page_ranges;
}

std::unique_ptr<PrintSettings> PrintSettingsFromJobSettings(
    const base::Value::Dict& job_settings) {
  auto settings = std::make_unique<PrintSettings>();
  absl::optional<bool> display_header_footer =
      job_settings.FindBool(kSettingHeaderFooterEnabled);
  if (!display_header_footer.has_value()) {
    return nullptr;
  }

  settings->set_display_header_footer(display_header_footer.value());
  if (settings->display_header_footer()) {
    const std::string* title =
        job_settings.FindString(kSettingHeaderFooterTitle);
    const std::string* url = job_settings.FindString(kSettingHeaderFooterURL);
    if (!title || !url) {
      return nullptr;
    }

    settings->set_title(base::UTF8ToUTF16(*title));
    settings->set_url(base::UTF8ToUTF16(*url));
  }

  absl::optional<bool> backgrounds =
      job_settings.FindBool(kSettingShouldPrintBackgrounds);
  absl::optional<bool> selection_only =
      job_settings.FindBool(kSettingShouldPrintSelectionOnly);
  if (!backgrounds.has_value() || !selection_only.has_value()) {
    return nullptr;
  }

  settings->set_should_print_backgrounds(backgrounds.value());
  settings->set_selection_only(selection_only.value());

  absl::optional<bool> collate = job_settings.FindBool(kSettingCollate);
  absl::optional<int> copies = job_settings.FindInt(kSettingCopies);
  absl::optional<int> color = job_settings.FindInt(kSettingColor);
  absl::optional<int> duplex_mode = job_settings.FindInt(kSettingDuplexMode);
  absl::optional<bool> landscape = job_settings.FindBool(kSettingLandscape);
  const std::string* device_name = job_settings.FindString(kSettingDeviceName);
  absl::optional<int> scale_factor = job_settings.FindInt(kSettingScaleFactor);
  absl::optional<bool> rasterize_pdf =
      job_settings.FindBool(kSettingRasterizePdf);
  absl::optional<int> pages_per_sheet =
      job_settings.FindInt(kSettingPagesPerSheet);
  if (!collate.has_value() || !copies.has_value() || !color.has_value() ||
      !duplex_mode.has_value() || !landscape.has_value() || !device_name ||
      !scale_factor.has_value() || !rasterize_pdf.has_value() ||
      !pages_per_sheet.has_value()) {
    return nullptr;
  }
  settings->set_collate(collate.value());
  settings->set_copies(copies.value());
  settings->SetOrientation(landscape.value());
  settings->set_device_name(base::UTF8ToUTF16(*device_name));
  settings->set_duplex_mode(
      static_cast<mojom::DuplexMode>(duplex_mode.value()));
  settings->set_color(static_cast<mojom::ColorModel>(color.value()));
  settings->set_scale_factor(static_cast<double>(scale_factor.value()) / 100.0);
  settings->set_rasterize_pdf(rasterize_pdf.value());
  settings->set_pages_per_sheet(pages_per_sheet.value());

  absl::optional<int> dpi_horizontal =
      job_settings.FindInt(kSettingDpiHorizontal);
  absl::optional<int> dpi_vertical = job_settings.FindInt(kSettingDpiVertical);
  if (!dpi_horizontal.has_value() || !dpi_vertical.has_value()) {
    return nullptr;
  }

  settings->set_dpi_xy(dpi_horizontal.value(), dpi_vertical.value());

  absl::optional<int> rasterize_pdf_dpi =
      job_settings.FindInt(kSettingRasterizePdfDpi);
  if (rasterize_pdf_dpi.has_value()) {
    settings->set_rasterize_pdf_dpi(rasterize_pdf_dpi.value());
  }

  PrintSettings::RequestedMedia requested_media;
  const base::Value::Dict* media_size_value =
      job_settings.FindDict(kSettingMediaSize);
  if (media_size_value) {
    absl::optional<int> width_microns =
        media_size_value->FindInt(kSettingMediaSizeWidthMicrons);
    absl::optional<int> height_microns =
        media_size_value->FindInt(kSettingMediaSizeHeightMicrons);
    if (width_microns.has_value() && height_microns.has_value()) {
      requested_media.size_microns =
          gfx::Size(width_microns.value(), height_microns.value());
      SetPrintableAreaIfValid(*settings, requested_media.size_microns,
                              *media_size_value);
    }

    const std::string* vendor_id =
        media_size_value->FindString(kSettingMediaSizeVendorId);
    if (vendor_id && !vendor_id->empty()) {
      requested_media.vendor_id = *vendor_id;
    }
  }
  settings->set_requested_media(requested_media);

  mojom::MarginType margin_type = static_cast<mojom::MarginType>(
      job_settings.FindInt(kSettingMarginsType)
          .value_or(static_cast<int>(mojom::MarginType::kDefaultMargins)));
  if (margin_type < mojom::MarginType::kMinValue ||
      margin_type > mojom::MarginType::kMaxValue) {
    margin_type = mojom::MarginType::kDefaultMargins;
  }
  settings->set_margin_type(margin_type);

  if (margin_type == mojom::MarginType::kCustomMargins) {
    settings->SetCustomMargins(GetCustomMarginsFromJobSettings(job_settings));
  }

  settings->set_ranges(GetPageRangesFromJobSettings(job_settings));

  absl::optional<bool> is_modifiable =
      job_settings.FindBool(kSettingPreviewModifiable);
  if (is_modifiable.has_value()) {
    settings->set_is_modifiable(is_modifiable.value());
  }

#if BUILDFLAG(IS_CHROMEOS) || (BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_CUPS))
  const base::Value::Dict* advanced_settings =
      job_settings.FindDict(kSettingAdvancedSettings);
  if (advanced_settings) {
    for (const auto item : *advanced_settings) {
      static constexpr auto kNonJobAttributes =
          base::MakeFixedFlatSet<base::StringPiece>(
              {"printer-info", "printer-make-and-model", "system_driverinfo"});
      if (!base::Contains(kNonJobAttributes, item.first)) {
        settings->advanced_settings().emplace(item.first, item.second.Clone());
      }
    }
  }
#endif  // BUILDFLAG(IS_CHROMEOS) || (BUILDFLAG(IS_LINUX) &&
        // BUILDFLAG(USE_CUPS))

#if BUILDFLAG(IS_CHROMEOS)
  bool send_user_info =
      job_settings.FindBool(kSettingSendUserInfo).value_or(false);
  settings->set_send_user_info(send_user_info);
  if (send_user_info) {
    const std::string* username = job_settings.FindString(kSettingUsername);
    if (username) {
      settings->set_username(*username);
    }
  }

  const std::string* oauth_token =
      job_settings.FindString(kSettingChromeOSAccessOAuthToken);
  if (oauth_token) {
    settings->set_oauth_token(*oauth_token);
  }

  const std::string* pin_value = job_settings.FindString(kSettingPinValue);
  if (pin_value) {
    settings->set_pin_value(*pin_value);
  }

  const base::Value::List* client_info_list =
      job_settings.FindList(kSettingIppClientInfo);
  if (client_info_list) {
    settings->set_client_infos(
        ConvertJobSettingToClientInfo(*client_info_list));
  }
#endif  // BUILDFLAG(IS_CHROMEOS)

  return settings;
}

base::Value::Dict PrintSettingsToJobSettingsDebug(
    const PrintSettings& settings) {
  base::Value::Dict job_settings;

  job_settings.Set(kSettingHeaderFooterEnabled,
                   settings.display_header_footer());
  job_settings.Set(kSettingHeaderFooterTitle, settings.title());
  job_settings.Set(kSettingHeaderFooterURL, settings.url());
  job_settings.Set(kSettingShouldPrintBackgrounds,
                   settings.should_print_backgrounds());
  job_settings.Set(kSettingShouldPrintSelectionOnly, settings.selection_only());
  job_settings.Set(kSettingMarginsType,
                   static_cast<int>(settings.margin_type()));
  if (!settings.ranges().empty()) {
    base::Value::List page_range_array;
    for (const auto& range : settings.ranges()) {
      base::Value::Dict dict;
      dict.Set(kSettingPageRangeFrom, static_cast<int>(range.from + 1));
      dict.Set(kSettingPageRangeTo, static_cast<int>(range.to + 1));
      page_range_array.Append(std::move(dict));
    }
    job_settings.Set(kSettingPageRange, std::move(page_range_array));
  }

  job_settings.Set(kSettingCollate, settings.collate());
  job_settings.Set(kSettingCopies, settings.copies());
  job_settings.Set(kSettingColor, static_cast<int>(settings.color()));
  job_settings.Set(kSettingDuplexMode,
                   static_cast<int>(settings.duplex_mode()));
  job_settings.Set(kSettingLandscape, settings.landscape());
  job_settings.Set(kSettingDeviceName, settings.device_name());
  job_settings.Set(kSettingDpiHorizontal, settings.dpi_horizontal());
  job_settings.Set(kSettingDpiVertical, settings.dpi_vertical());
  job_settings.Set(kSettingScaleFactor,
                   static_cast<int>((settings.scale_factor() * 100.0) + 0.5));
  job_settings.Set(kSettingRasterizePdf, settings.rasterize_pdf());
  job_settings.Set(kSettingPagesPerSheet, settings.pages_per_sheet());

  // Following values are not read form JSON by InitSettings, so do not have
  // common public constants. So just serialize in "debug" section.
  base::Value::Dict debug;
  debug.Set("dpi", settings.dpi());
  debug.Set("deviceUnitsPerInch", settings.device_units_per_inch());
  debug.Set("support_alpha_blend", settings.should_print_backgrounds());
  debug.Set("media_vendor_id", settings.requested_media().vendor_id);
  SetSizeToJobSettings("media_size", settings.requested_media().size_microns,
                       debug);
  SetMarginsToJobSettings("requested_custom_margins_in_points",
                          settings.requested_custom_margins_in_points(), debug);
  const PageSetup& page_setup = settings.page_setup_device_units();
  SetMarginsToJobSettings("effective_margins", page_setup.effective_margins(),
                          debug);
  SetSizeToJobSettings("physical_size", page_setup.physical_size(), debug);
  SetRectToJobSettings("overlay_area", page_setup.overlay_area(), debug);
  SetRectToJobSettings("content_area", page_setup.content_area(), debug);
  SetRectToJobSettings("printable_area", page_setup.printable_area(), debug);
  job_settings.Set("debug", std::move(debug));

#if BUILDFLAG(IS_CHROMEOS)
  job_settings.Set(kSettingIppClientInfo,
                   ConvertClientInfoToJobSetting(settings.client_infos()));
#endif  // BUILDFLAG(IS_CHROMEOS)

  return job_settings;
}

}  // namespace printing
