root/components/autofill/content/browser/wallet/wallet_address.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CreateAddressInternal
  2. is_complete_address_
  3. is_complete_address_
  4. CreateAddressWithID
  5. CreateAddress
  6. CreateDisplayAddress
  7. ToDictionaryWithID
  8. ToDictionaryWithoutID
  9. DisplayName
  10. DisplayNameDetail
  11. DisplayPhoneNumber
  12. GetInfo
  13. SetPhoneNumber
  14. EqualsIgnoreID
  15. GetStreetAddressLine

// Copyright 2013 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/content/browser/wallet/wallet_address.h"

#include "base/logging.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/autofill/core/browser/autofill_country.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/phone_number.h"
#include "components/autofill/core/browser/state_names.h"

namespace autofill {
namespace wallet {

// Server specified type for address with complete details.
const char kFullAddress[] = "FULL";

namespace {

Address* CreateAddressInternal(const base::DictionaryValue& dictionary,
                               const std::string& object_id) {
  std::string country_name_code;
  if (!dictionary.GetString("postal_address.country_name_code",
                            &country_name_code)) {
    DLOG(ERROR) << "Response from Google Wallet missing country name";
    return NULL;
  }

  base::string16 recipient_name;
  if (!dictionary.GetString("postal_address.recipient_name",
                            &recipient_name)) {
    DLOG(ERROR) << "Response from Google Wallet missing recipient name";
    return NULL;
  }

  base::string16 postal_code_number;
  if (!dictionary.GetString("postal_address.postal_code_number",
                            &postal_code_number)) {
    DLOG(ERROR) << "Response from Google Wallet missing postal code number";
    return NULL;
  }
  // TODO(estade): what about postal_code_number_extension?

  base::string16 sorting_code;
  if (!dictionary.GetString("postal_address.sorting_code",
                            &sorting_code)) {
    DVLOG(1) << "Response from Google Wallet missing sorting code";
  }

  base::string16 phone_number;
  if (!dictionary.GetString("phone_number", &phone_number))
    DVLOG(1) << "Response from Google Wallet missing phone number";

  std::vector<base::string16> street_address;
  const base::ListValue* address_line_list;
  if (dictionary.GetList("postal_address.address_line", &address_line_list)) {
    for (size_t i = 0; i < address_line_list->GetSize(); ++i) {
      base::string16 line;
      address_line_list->GetString(i, &line);
      street_address.push_back(line);
    }
  } else {
    DVLOG(1) << "Response from Google Wallet missing address lines";
  }

  base::string16 locality_name;
  if (!dictionary.GetString("postal_address.locality_name",
                            &locality_name)) {
    DVLOG(1) << "Response from Google Wallet missing locality name";
  }

  base::string16 dependent_locality_name;
  if (!dictionary.GetString("postal_address.dependent_locality_name",
                            &dependent_locality_name)) {
    DVLOG(1) << "Response from Google Wallet missing dependent locality name";
  }

  base::string16 administrative_area_name;
  if (!dictionary.GetString("postal_address.administrative_area_name",
                            &administrative_area_name)) {
    DVLOG(1) << "Response from Google Wallet missing administrative area name";
  }

  Address* address = new Address(country_name_code,
                                 recipient_name,
                                 street_address,
                                 locality_name,
                                 dependent_locality_name,
                                 administrative_area_name,
                                 postal_code_number,
                                 sorting_code,
                                 phone_number,
                                 object_id);

  bool is_minimal_address = false;
  if (dictionary.GetBoolean("is_minimal_address", &is_minimal_address))
    address->set_is_complete_address(!is_minimal_address);
  else
    DVLOG(1) << "Response from Google Wallet missing is_minimal_address bit";

  return address;
}

}  // namespace

Address::Address() {}

Address::Address(const AutofillProfile& profile)
    : country_name_code_(
          base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))),
      recipient_name_(profile.GetRawInfo(NAME_FULL)),
      locality_name_(profile.GetRawInfo(ADDRESS_HOME_CITY)),
      dependent_locality_name_(
          profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)),
      administrative_area_name_(profile.GetRawInfo(ADDRESS_HOME_STATE)),
      postal_code_number_(profile.GetRawInfo(ADDRESS_HOME_ZIP)),
      sorting_code_(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)),
      phone_number_(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)),
      is_complete_address_(true) {
  base::SplitString(
      profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS), '\n', &street_address_);

  if (!country_name_code_.empty())
    phone_object_ = i18n::PhoneObject(phone_number_, country_name_code_);
}

Address::Address(const std::string& country_name_code,
                 const base::string16& recipient_name,
                 const std::vector<base::string16>& street_address,
                 const base::string16& locality_name,
                 const base::string16& dependent_locality_name,
                 const base::string16& administrative_area_name,
                 const base::string16& postal_code_number,
                 const base::string16& sorting_code,
                 const base::string16& phone_number,
                 const std::string& object_id)
    : country_name_code_(country_name_code),
      recipient_name_(recipient_name),
      street_address_(street_address),
      locality_name_(locality_name),
      dependent_locality_name_(dependent_locality_name),
      administrative_area_name_(administrative_area_name),
      postal_code_number_(postal_code_number),
      sorting_code_(sorting_code),
      phone_number_(phone_number),
      phone_object_(phone_number, country_name_code),
      object_id_(object_id),
      is_complete_address_(true) {}

Address::~Address() {}

// static
scoped_ptr<Address> Address::CreateAddressWithID(
    const base::DictionaryValue& dictionary) {
  std::string object_id;
  if (!dictionary.GetString("id", &object_id)) {
    DLOG(ERROR) << "Response from Google Wallet missing object id";
    return scoped_ptr<Address>();
  }
  return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id));
}

// static
scoped_ptr<Address> Address::CreateAddress(
    const base::DictionaryValue& dictionary) {
  std::string object_id;
  dictionary.GetString("id", &object_id);
  return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id));
}

// static
scoped_ptr<Address> Address::CreateDisplayAddress(
    const base::DictionaryValue& dictionary) {
  std::string country_code;
  if (!dictionary.GetString("country_code", &country_code)) {
    DLOG(ERROR) << "Reponse from Google Wallet missing country code";
    return scoped_ptr<Address>();
  }

  base::string16 name;
  if (!dictionary.GetString("name", &name)) {
    DLOG(ERROR) << "Reponse from Google Wallet missing name";
    return scoped_ptr<Address>();
  }

  base::string16 postal_code;
  if (!dictionary.GetString("postal_code", &postal_code)) {
    DLOG(ERROR) << "Reponse from Google Wallet missing postal code";
    return scoped_ptr<Address>();
  }

  base::string16 sorting_code;
  if (!dictionary.GetString("sorting_code", &sorting_code)) {
    DVLOG(1) << "Reponse from Google Wallet missing sorting code";
  }

  std::vector<base::string16> street_address;
  base::string16 address1;
  if (dictionary.GetString("address1", &address1))
    street_address.push_back(address1);
  else
    DVLOG(1) << "Reponse from Google Wallet missing address1";

  base::string16 address2;
  if (dictionary.GetString("address2", &address2) && !address2.empty()) {
    street_address.resize(2);
    street_address[1] = address2;
  } else {
    DVLOG(1) << "Reponse from Google Wallet missing or empty address2";
  }

  base::string16 city;
  if (!dictionary.GetString("city", &city))
    DVLOG(1) << "Reponse from Google Wallet missing city";

  base::string16 dependent_locality_name;
  if (!dictionary.GetString("dependent_locality_name",
                            &dependent_locality_name)) {
    DVLOG(1) << "Reponse from Google Wallet missing district";
  }

  base::string16 state;
  if (!dictionary.GetString("state", &state))
    DVLOG(1) << "Reponse from Google Wallet missing state";

  base::string16 phone_number;
  if (!dictionary.GetString("phone_number", &phone_number))
    DVLOG(1) << "Reponse from Google Wallet missing phone number";

  std::string address_state;
  if (!dictionary.GetString("type", &address_state))
    DVLOG(1) << "Response from Google Wallet missing type/state of address";

  scoped_ptr<Address> address(
      new Address(country_code,
                  name,
                  street_address,
                  city,
                  dependent_locality_name,
                  state,
                  postal_code,
                  sorting_code,
                  phone_number,
                  std::string()));
  address->set_is_complete_address(address_state == kFullAddress);

  return address.Pass();
}

scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithID() const {
  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());

  if (!object_id_.empty())
    dict->SetString("id", object_id_);
  dict->SetString("phone_number", phone_number_);
  dict->Set("postal_address", ToDictionaryWithoutID().release());

  return dict.Pass();
}

scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithoutID() const {
  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());

  scoped_ptr<base::ListValue> address_lines(new base::ListValue());
  address_lines->AppendStrings(street_address_);
  dict->Set("address_line", address_lines.release());

  dict->SetString("country_name_code", country_name_code_);
  dict->SetString("recipient_name", recipient_name_);
  dict->SetString("locality_name", locality_name_);
  dict->SetString("dependent_locality_name", dependent_locality_name_);
  dict->SetString("administrative_area_name",
                  administrative_area_name_);
  dict->SetString("postal_code_number", postal_code_number_);
  dict->SetString("sorting_code", sorting_code_);

  return dict.Pass();
}

base::string16 Address::DisplayName() const {
#if defined(OS_ANDROID)
  // TODO(aruslan): improve this stub implementation.
  return recipient_name();
#else
  // TODO(estade): improve this stub implementation + l10n.
  return recipient_name() + base::ASCIIToUTF16(", ") + GetStreetAddressLine(0);
#endif
}

base::string16 Address::DisplayNameDetail() const {
#if defined(OS_ANDROID)
  // TODO(aruslan): improve this stub implementation.
  return GetStreetAddressLine(0);
#else
  return base::string16();
#endif
}

base::string16 Address::DisplayPhoneNumber() const {
  // Return a formatted phone number. Wallet doesn't store user formatting, so
  // impose our own. phone_number() always includes a country code, so using
  // PhoneObject to format it would result in an internationalized format. Since
  // Wallet only supports the US right now, stick to national formatting.
  return i18n::PhoneObject(phone_number(), country_name_code()).
      GetNationallyFormattedNumber();
}

base::string16 Address::GetInfo(const AutofillType& type,
                                const std::string& app_locale) const {
  if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
    DCHECK(IsStringASCII(country_name_code()));
    return base::ASCIIToUTF16(country_name_code());
  }

  switch (type.GetStorableType()) {
    case NAME_FULL:
      return recipient_name();

    case ADDRESS_HOME_STREET_ADDRESS:
      return JoinString(street_address_, base::ASCIIToUTF16("\n"));

    case ADDRESS_HOME_LINE1:
      return GetStreetAddressLine(0);

    case ADDRESS_HOME_LINE2:
      return GetStreetAddressLine(1);

    case ADDRESS_HOME_CITY:
      return locality_name();

    case ADDRESS_HOME_STATE:
      return administrative_area_name();

    case ADDRESS_HOME_ZIP:
      return postal_code_number();

    case ADDRESS_HOME_COUNTRY: {
      AutofillCountry country(country_name_code(), app_locale);
      return country.name();
    }

    case PHONE_HOME_WHOLE_NUMBER:
      // Wallet doesn't store user phone number formatting, so just strip all
      // formatting.
      return phone_object_.GetWholeNumber();

    case ADDRESS_HOME_DEPENDENT_LOCALITY:
      return dependent_locality_name_;

    case ADDRESS_HOME_SORTING_CODE:
      return sorting_code_;

    case COMPANY_NAME:
      // A field that Wallet doesn't support. TODO(dbeam): can it be supported?
      return base::string16();

    default:
      NOTREACHED();
      return base::string16();
  }
}

void Address::SetPhoneNumber(const base::string16& phone_number) {
  phone_number_ = phone_number;
  phone_object_ = i18n::PhoneObject(phone_number_, country_name_code_);
}

bool Address::EqualsIgnoreID(const Address& other) const {
  return country_name_code_ == other.country_name_code_ &&
         recipient_name_ == other.recipient_name_ &&
         street_address_ == other.street_address_ &&
         locality_name_ == other.locality_name_ &&
         dependent_locality_name_ == other.dependent_locality_name_ &&
         administrative_area_name_ == other.administrative_area_name_ &&
         postal_code_number_ == other.postal_code_number_ &&
         sorting_code_ == other.sorting_code_ &&
         phone_number_ == other.phone_number_ &&
         is_complete_address_ == other.is_complete_address_;
}

base::string16 Address::GetStreetAddressLine(size_t line) const {
  return street_address_.size() > line ? street_address_[line] :
                                         base::string16();
}

bool Address::operator==(const Address& other) const {
  return object_id_ == other.object_id_ && EqualsIgnoreID(other);
}

bool Address::operator!=(const Address& other) const {
  return !(*this == other);
}

}  // namespace wallet
}  // namespace autofill

/* [<][>][^][v][top][bottom][index][help] */