#include "ash/scanner/scanner_feedback.h"
#include <cstddef>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <variant>
#include <vector>
#include "base/containers/to_value_list.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "components/manta/proto/scanner.pb.h"
namespace ash {
namespace {
base::Value::Dict EmailAddressToDict(
manta::proto::NewContactAction::EmailAddress&& email_address) {
base::Value::Dict dict;
if (!email_address.value().empty()) {
dict.Set("value", std::move(*email_address.mutable_value()));
}
if (!email_address.type().empty()) {
dict.Set("type", std::move(*email_address.mutable_type()));
}
return dict;
}
base::Value::Dict PhoneNumberToDict(
manta::proto::NewContactAction::PhoneNumber&& phone_number) {
base::Value::Dict dict;
if (!phone_number.value().empty()) {
dict.Set("value", std::move(*phone_number.mutable_value()));
}
if (!phone_number.type().empty()) {
dict.Set("type", std::move(*phone_number.mutable_type()));
}
return dict;
}
base::Value::Dict NewEventToDict(manta::proto::NewEventAction&& new_event) {
base::Value::Dict dict;
if (!new_event.title().empty()) {
dict.Set("title", std::move(*new_event.mutable_title()));
}
if (!new_event.description().empty()) {
dict.Set("description", std::move(*new_event.mutable_description()));
}
if (!new_event.dates().empty()) {
dict.Set("dates", std::move(*new_event.mutable_dates()));
}
if (!new_event.location().empty()) {
dict.Set("location", std::move(*new_event.mutable_location()));
}
return base::Value::Dict().Set("new_event", std::move(dict));
}
base::Value::Dict NewContactToDict(
manta::proto::NewContactAction&& new_contact) {
base::Value::Dict dict;
if (!new_contact.given_name().empty()) {
dict.Set("given_name", std::move(*new_contact.mutable_given_name()));
}
if (!new_contact.family_name().empty()) {
dict.Set("family_name", std::move(*new_contact.mutable_family_name()));
}
if (!new_contact.email().empty()) {
dict.Set("email", std::move(*new_contact.mutable_email()));
}
if (!new_contact.phone().empty()) {
dict.Set("phone", std::move(*new_contact.mutable_phone()));
}
if (!new_contact.email_addresses().empty()) {
dict.Set(
"email_addresses",
base::ToValueList(
*new_contact.mutable_email_addresses(),
[](manta::proto::NewContactAction::EmailAddress& email_address) {
return EmailAddressToDict(std::move(email_address));
}));
}
if (!new_contact.phone_numbers().empty()) {
dict.Set("phone_numbers",
base::ToValueList(
*new_contact.mutable_phone_numbers(),
[](manta::proto::NewContactAction::PhoneNumber& phone_number) {
return PhoneNumberToDict(std::move(phone_number));
}));
}
return base::Value::Dict().Set("new_contact", std::move(dict));
}
base::Value::Dict NewGoogleDocToDict(
manta::proto::NewGoogleDocAction&& new_google_doc) {
base::Value::Dict dict;
if (!new_google_doc.title().empty()) {
dict.Set("title", std::move(*new_google_doc.mutable_title()));
}
if (!new_google_doc.html_contents().empty()) {
dict.Set("html_contents",
std::move(*new_google_doc.mutable_html_contents()));
}
return base::Value::Dict().Set("new_google_doc", std::move(dict));
}
base::Value::Dict NewGoogleSheetToDict(
manta::proto::NewGoogleSheetAction&& new_google_sheet) {
base::Value::Dict dict;
if (!new_google_sheet.title().empty()) {
dict.Set("title", std::move(*new_google_sheet.mutable_title()));
}
if (!new_google_sheet.csv_contents().empty()) {
dict.Set("csv_contents",
std::move(*new_google_sheet.mutable_csv_contents()));
}
return base::Value::Dict().Set("new_google_sheet", std::move(dict));
}
base::Value::Dict CopyToClipboardToDict(
manta::proto::CopyToClipboardAction&& copy_to_clipboard) {
base::Value::Dict dict;
if (!copy_to_clipboard.plain_text().empty()) {
dict.Set("plain_text", std::move(*copy_to_clipboard.mutable_plain_text()));
}
if (!copy_to_clipboard.html_text().empty()) {
dict.Set("html_text", std::move(*copy_to_clipboard.mutable_html_text()));
}
return base::Value::Dict().Set("copy_to_clipboard", std::move(dict));
}
class UserFacingValueWriter {
public:
explicit UserFacingValueWriter(size_t depth_limit, size_t output_limit)
: user_facing_string_(""),
depth_limit_(depth_limit),
output_limit_(output_limit) {}
void BuildString(std::monostate node) { OutputValue("null"); }
void BuildString(bool node) { OutputValue(node ? "true" : "false"); }
void BuildString(int node) { OutputValue(base::NumberToString(node)); }
void BuildString(double node) { OutputValue(base::NumberToString(node)); }
void BuildString(std::string_view node) { OutputValue(node); }
void BuildString(const base::Value::BlobStorage& node) {
user_facing_string_.reset();
}
void BuildString(const base::Value::Dict& node) {
if (path_.size() >= depth_limit_) {
user_facing_string_.reset();
return;
}
for (auto [key, value] : node) {
path_.push_back(key);
value.Visit([this](const auto& member) { BuildString(member); });
path_.pop_back();
}
}
void BuildString(const base::Value::List& node) {
if (path_.size() >= depth_limit_) {
user_facing_string_.reset();
return;
}
size_t i = 0;
for (const base::Value& value : node) {
path_.push_back(base::NumberToString(i));
value.Visit([this](const auto& member) { BuildString(member); });
path_.pop_back();
++i;
}
}
std::optional<std::string>&& user_facing_string() && {
return std::move(user_facing_string_);
}
private:
void OutputValue(std::string_view value) {
if (!user_facing_string_.has_value()) {
return;
}
if (!path_.empty()) {
user_facing_string_->append(path_[0]);
for (size_t i = 1; i < path_.size(); ++i) {
user_facing_string_->push_back('.');
user_facing_string_->append(path_[i]);
}
user_facing_string_->append(": ");
}
user_facing_string_->append(value);
user_facing_string_->push_back('\n');
if (user_facing_string_->size() > output_limit_) {
user_facing_string_.reset();
return;
}
}
std::vector<std::string> path_;
std::optional<std::string> user_facing_string_;
size_t depth_limit_;
size_t output_limit_;
};
}
base::Value::Dict ScannerActionToDict(manta::proto::ScannerAction action) {
switch (action.action_case()) {
case manta::proto::ScannerAction::kNewEvent:
return NewEventToDict(std::move(*action.mutable_new_event()));
case manta::proto::ScannerAction::kNewContact:
return NewContactToDict(std::move(*action.mutable_new_contact()));
case manta::proto::ScannerAction::kNewGoogleDoc:
return NewGoogleDocToDict(std::move(*action.mutable_new_google_doc()));
case manta::proto::ScannerAction::kNewGoogleSheet:
return NewGoogleSheetToDict(
std::move(*action.mutable_new_google_sheet()));
case manta::proto::ScannerAction::kCopyToClipboard:
return CopyToClipboardToDict(
std::move(*action.mutable_copy_to_clipboard()));
case manta::proto::ScannerAction::ACTION_NOT_SET:
return base::Value::Dict();
}
}
std::optional<std::string> ValueToUserFacingString(base::ValueView value,
size_t depth_limit,
size_t output_limit) {
UserFacingValueWriter writer(depth_limit, output_limit);
value.Visit([&writer](const auto& value) { writer.BuildString(value); });
return std::move(writer).user_facing_string();
}
}