// Copyright 2018 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 "components/autofill/core/browser/autofill_profile_sync_util.h"

#include "base/guid.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/proto/autofill_sync.pb.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/sync/model/entity_data.h"

using base::UTF16ToUTF8;
using base::UTF8ToUTF16;
using sync_pb::AutofillProfileSpecifics;
using syncer::EntityData;

namespace autofill {
namespace {

std::string TruncateUTF8(const std::string& data) {
  std::string trimmed_value;
  base::TruncateUTF8ToByteSize(data, AutofillTable::kMaxDataLength,
                               &trimmed_value);
  return trimmed_value;
}

bool IsAutofillProfileSpecificsValid(
    const AutofillProfileSpecifics& specifics) {
  return base::IsValidGUID(specifics.guid());
}

}  // namespace

std::unique_ptr<EntityData> CreateEntityDataFromAutofillProfile(
    const AutofillProfile& entry) {
  // Validity of the guid is guaranteed by the database layer.
  DCHECK(base::IsValidGUID(entry.guid()));

  auto entity_data = std::make_unique<EntityData>();
  entity_data->non_unique_name = entry.guid();
  AutofillProfileSpecifics* specifics =
      entity_data->specifics.mutable_autofill_profile();

  specifics->set_guid(entry.guid());
  specifics->set_origin(entry.origin());

  specifics->set_use_count(entry.use_count());
  specifics->set_use_date(entry.use_date().ToTimeT());
  specifics->set_address_home_language_code(
      TruncateUTF8(entry.language_code()));
  specifics->set_validity_state_bitfield(entry.GetValidityBitfieldValue());

  // Set repeated fields.
  if (entry.HasRawInfo(NAME_FIRST)) {
    specifics->add_name_first(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_FIRST))));
  }
  if (entry.HasRawInfo(NAME_MIDDLE)) {
    specifics->add_name_middle(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_MIDDLE))));
  }
  if (entry.HasRawInfo(NAME_LAST)) {
    specifics->add_name_last(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_LAST))));
  }
  if (entry.HasRawInfo(NAME_FULL)) {
    specifics->add_name_full(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(NAME_FULL))));
  }
  if (entry.HasRawInfo(EMAIL_ADDRESS)) {
    specifics->add_email_address(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(EMAIL_ADDRESS))));
  }
  if (entry.HasRawInfo(PHONE_HOME_WHOLE_NUMBER)) {
    specifics->add_phone_home_whole_number(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(PHONE_HOME_WHOLE_NUMBER))));
  }

  // Set simple single-valued fields.
  if (entry.HasRawInfo(COMPANY_NAME)) {
    specifics->set_company_name(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(COMPANY_NAME))));
  }
  if (entry.HasRawInfo(ADDRESS_HOME_CITY)) {
    specifics->set_address_home_city(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_CITY))));
  }
  if (entry.HasRawInfo(ADDRESS_HOME_STATE)) {
    specifics->set_address_home_state(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_STATE))));
  }
  if (entry.HasRawInfo(ADDRESS_HOME_ZIP)) {
    specifics->set_address_home_zip(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_ZIP))));
  }
  if (entry.HasRawInfo(ADDRESS_HOME_SORTING_CODE)) {
    specifics->set_address_home_sorting_code(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_SORTING_CODE))));
  }
  if (entry.HasRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)) {
    specifics->set_address_home_dependent_locality(TruncateUTF8(
        UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))));
  }
  if (entry.HasRawInfo(ADDRESS_HOME_COUNTRY)) {
    specifics->set_address_home_country(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_COUNTRY))));
  }
  if (entry.HasRawInfo(ADDRESS_HOME_STREET_ADDRESS)) {
    specifics->set_address_home_street_address(TruncateUTF8(
        UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS))));
  }
  if (entry.HasRawInfo(ADDRESS_HOME_LINE1)) {
    specifics->set_address_home_line1(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_LINE1))));
  }
  if (entry.HasRawInfo(ADDRESS_HOME_LINE2)) {
    specifics->set_address_home_line2(
        TruncateUTF8(UTF16ToUTF8(entry.GetRawInfo(ADDRESS_HOME_LINE2))));
  }

  return entity_data;
}

std::unique_ptr<AutofillProfile> CreateAutofillProfileFromSpecifics(
    const AutofillProfileSpecifics& specifics) {
  if (!IsAutofillProfileSpecificsValid(specifics)) {
    return nullptr;
  }
  std::unique_ptr<AutofillProfile> profile =
      std::make_unique<AutofillProfile>(specifics.guid(), specifics.origin());

  // Set info that has a default value (and does not distinguish whether it is
  // set or not).
  profile->set_use_count(specifics.use_count());
  profile->set_use_date(base::Time::FromTimeT(specifics.use_date()));
  profile->set_language_code(specifics.address_home_language_code());
  profile->SetValidityFromBitfieldValue(specifics.validity_state_bitfield());

  // Set repeated fields.
  if (specifics.name_first_size() > 0) {
    profile->SetRawInfo(NAME_FIRST, UTF8ToUTF16(specifics.name_first(0)));
  }
  if (specifics.name_middle_size() > 0) {
    profile->SetRawInfo(NAME_MIDDLE, UTF8ToUTF16(specifics.name_middle(0)));
  }
  if (specifics.name_last_size() > 0) {
    profile->SetRawInfo(NAME_LAST, UTF8ToUTF16(specifics.name_last(0)));
  }
  if (specifics.name_full_size() > 0) {
    profile->SetRawInfo(NAME_FULL, UTF8ToUTF16(specifics.name_full(0)));
  }
  if (specifics.email_address_size() > 0) {
    profile->SetRawInfo(EMAIL_ADDRESS, UTF8ToUTF16(specifics.email_address(0)));
  }
  if (specifics.phone_home_whole_number_size() > 0) {
    profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                        UTF8ToUTF16(specifics.phone_home_whole_number(0)));
  }

  // Set simple single-valued fields.
  if (specifics.has_company_name()) {
    profile->SetRawInfo(COMPANY_NAME, UTF8ToUTF16(specifics.company_name()));
  }
  if (specifics.has_address_home_city()) {
    profile->SetRawInfo(ADDRESS_HOME_CITY,
                        UTF8ToUTF16(specifics.address_home_city()));
  }
  if (specifics.has_address_home_state()) {
    profile->SetRawInfo(ADDRESS_HOME_STATE,
                        UTF8ToUTF16(specifics.address_home_state()));
  }
  if (specifics.has_address_home_zip()) {
    profile->SetRawInfo(ADDRESS_HOME_ZIP,
                        UTF8ToUTF16(specifics.address_home_zip()));
  }
  if (specifics.has_address_home_sorting_code()) {
    profile->SetRawInfo(ADDRESS_HOME_SORTING_CODE,
                        UTF8ToUTF16(specifics.address_home_sorting_code()));
  }
  if (specifics.has_address_home_dependent_locality()) {
    profile->SetRawInfo(
        ADDRESS_HOME_DEPENDENT_LOCALITY,
        UTF8ToUTF16(specifics.address_home_dependent_locality()));
  }
  if (specifics.has_address_home_country()) {
    // Update the country field, which can contain either a country code (if set
    // by a newer version of Chrome), or a country name (if set by an older
    // version of Chrome).
    // TODO(jkrcal): Move this migration logic into Address::SetRawInfo()?
    base::string16 country_name_or_code =
        base::ASCIIToUTF16(specifics.address_home_country());
    std::string country_code =
        CountryNames::GetInstance()->GetCountryCode(country_name_or_code);
    profile->SetRawInfo(ADDRESS_HOME_COUNTRY, UTF8ToUTF16(country_code));
  }
  if (specifics.has_address_home_line1()) {
    profile->SetRawInfo(ADDRESS_HOME_LINE1,
                        UTF8ToUTF16(specifics.address_home_line1()));
  }
  if (specifics.has_address_home_line2()) {
    profile->SetRawInfo(ADDRESS_HOME_LINE2,
                        UTF8ToUTF16(specifics.address_home_line2()));
  }
  // Set first the deprecated subparts (line1 & line2) and only after that the
  // full address (street_address) so that the latter wins in case of conflict.
  // This is needed because all the address fields are backed by the same
  // storage.
  if (specifics.has_address_home_street_address()) {
    profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
                        UTF8ToUTF16(specifics.address_home_street_address()));
  }

  return profile;
}

std::string GetStorageKeyFromAutofillProfile(const AutofillProfile& entry) {
  // Validity of the guid is guaranteed by the database layer.
  DCHECK(base::IsValidGUID(entry.guid()));
  return entry.guid();
}

std::string GetStorageKeyFromAutofillProfileSpecifics(
    const AutofillProfileSpecifics& specifics) {
  if (!IsAutofillProfileSpecificsValid(specifics)) {
    return std::string();
  }
  return specifics.guid();
}

}  // namespace autofill
