1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/autofill/content/browser/wallet/wallet_address.h"
6
7#include "base/logging.h"
8#include "base/strings/string_split.h"
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "base/values.h"
12#include "components/autofill/core/browser/autofill_country.h"
13#include "components/autofill/core/browser/autofill_profile.h"
14#include "components/autofill/core/browser/autofill_type.h"
15#include "components/autofill/core/browser/phone_number.h"
16#include "components/autofill/core/browser/state_names.h"
17
18namespace autofill {
19namespace wallet {
20
21// Server specified type for address with complete details.
22const char kFullAddress[] = "FULL";
23
24namespace {
25
26Address* CreateAddressInternal(const base::DictionaryValue& dictionary,
27                               const std::string& object_id) {
28  std::string country_name_code;
29  if (!dictionary.GetString("postal_address.country_name_code",
30                            &country_name_code)) {
31    DLOG(ERROR) << "Response from Google Wallet missing country name";
32    return NULL;
33  }
34
35  base::string16 recipient_name;
36  if (!dictionary.GetString("postal_address.recipient_name",
37                            &recipient_name)) {
38    DLOG(ERROR) << "Response from Google Wallet missing recipient name";
39    return NULL;
40  }
41
42  base::string16 postal_code_number;
43  if (!dictionary.GetString("postal_address.postal_code_number",
44                            &postal_code_number)) {
45    DLOG(ERROR) << "Response from Google Wallet missing postal code number";
46    return NULL;
47  }
48  // TODO(estade): what about postal_code_number_extension?
49
50  base::string16 sorting_code;
51  if (!dictionary.GetString("postal_address.sorting_code",
52                            &sorting_code)) {
53    DVLOG(1) << "Response from Google Wallet missing sorting code";
54  }
55
56  base::string16 phone_number;
57  if (!dictionary.GetString("phone_number", &phone_number))
58    DVLOG(1) << "Response from Google Wallet missing phone number";
59
60  std::vector<base::string16> street_address;
61  const base::ListValue* address_line_list;
62  if (dictionary.GetList("postal_address.address_line", &address_line_list)) {
63    for (size_t i = 0; i < address_line_list->GetSize(); ++i) {
64      base::string16 line;
65      address_line_list->GetString(i, &line);
66      street_address.push_back(line);
67    }
68  } else {
69    DVLOG(1) << "Response from Google Wallet missing address lines";
70  }
71
72  base::string16 locality_name;
73  if (!dictionary.GetString("postal_address.locality_name",
74                            &locality_name)) {
75    DVLOG(1) << "Response from Google Wallet missing locality name";
76  }
77
78  base::string16 dependent_locality_name;
79  if (!dictionary.GetString("postal_address.dependent_locality_name",
80                            &dependent_locality_name)) {
81    DVLOG(1) << "Response from Google Wallet missing dependent locality name";
82  }
83
84  base::string16 administrative_area_name;
85  if (!dictionary.GetString("postal_address.administrative_area_name",
86                            &administrative_area_name)) {
87    DVLOG(1) << "Response from Google Wallet missing administrative area name";
88  }
89
90  std::string language_code;
91  if (!dictionary.GetString("postal_address.language_code",
92                            &language_code)) {
93    DVLOG(1) << "Response from Google Wallet missing language code";
94  }
95
96  Address* address = new Address(country_name_code,
97                                 recipient_name,
98                                 street_address,
99                                 locality_name,
100                                 dependent_locality_name,
101                                 administrative_area_name,
102                                 postal_code_number,
103                                 sorting_code,
104                                 phone_number,
105                                 object_id,
106                                 language_code);
107
108  bool is_minimal_address = false;
109  if (dictionary.GetBoolean("is_minimal_address", &is_minimal_address))
110    address->set_is_complete_address(!is_minimal_address);
111  else
112    DVLOG(1) << "Response from Google Wallet missing is_minimal_address bit";
113
114  return address;
115}
116
117}  // namespace
118
119Address::Address() {}
120
121Address::Address(const AutofillProfile& profile)
122    : country_name_code_(
123          base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))),
124      recipient_name_(profile.GetRawInfo(NAME_FULL)),
125      locality_name_(profile.GetRawInfo(ADDRESS_HOME_CITY)),
126      dependent_locality_name_(
127          profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY)),
128      administrative_area_name_(profile.GetRawInfo(ADDRESS_HOME_STATE)),
129      postal_code_number_(profile.GetRawInfo(ADDRESS_HOME_ZIP)),
130      sorting_code_(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)),
131      phone_number_(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER)),
132      is_complete_address_(true),
133      language_code_(profile.language_code()) {
134  base::SplitString(
135      profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS), '\n', &street_address_);
136
137  if (!country_name_code_.empty())
138    phone_object_ = i18n::PhoneObject(phone_number_, country_name_code_);
139}
140
141Address::Address(const std::string& country_name_code,
142                 const base::string16& recipient_name,
143                 const std::vector<base::string16>& street_address,
144                 const base::string16& locality_name,
145                 const base::string16& dependent_locality_name,
146                 const base::string16& administrative_area_name,
147                 const base::string16& postal_code_number,
148                 const base::string16& sorting_code,
149                 const base::string16& phone_number,
150                 const std::string& object_id,
151                 const std::string& language_code)
152    : country_name_code_(country_name_code),
153      recipient_name_(recipient_name),
154      street_address_(street_address),
155      locality_name_(locality_name),
156      dependent_locality_name_(dependent_locality_name),
157      administrative_area_name_(administrative_area_name),
158      postal_code_number_(postal_code_number),
159      sorting_code_(sorting_code),
160      phone_number_(phone_number),
161      phone_object_(phone_number, country_name_code),
162      object_id_(object_id),
163      is_complete_address_(true),
164      language_code_(language_code) {}
165
166Address::~Address() {}
167
168// static
169scoped_ptr<Address> Address::CreateAddressWithID(
170    const base::DictionaryValue& dictionary) {
171  std::string object_id;
172  if (!dictionary.GetString("id", &object_id)) {
173    DLOG(ERROR) << "Response from Google Wallet missing object id";
174    return scoped_ptr<Address>();
175  }
176  return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id));
177}
178
179// static
180scoped_ptr<Address> Address::CreateAddress(
181    const base::DictionaryValue& dictionary) {
182  std::string object_id;
183  dictionary.GetString("id", &object_id);
184  return scoped_ptr<Address>(CreateAddressInternal(dictionary, object_id));
185}
186
187// static
188scoped_ptr<Address> Address::CreateDisplayAddress(
189    const base::DictionaryValue& dictionary) {
190  std::string country_code;
191  if (!dictionary.GetString("country_code", &country_code)) {
192    DLOG(ERROR) << "Reponse from Google Wallet missing country code";
193    return scoped_ptr<Address>();
194  }
195
196  base::string16 name;
197  if (!dictionary.GetString("name", &name)) {
198    DLOG(ERROR) << "Reponse from Google Wallet missing name";
199    return scoped_ptr<Address>();
200  }
201
202  base::string16 postal_code;
203  if (!dictionary.GetString("postal_code", &postal_code)) {
204    DLOG(ERROR) << "Reponse from Google Wallet missing postal code";
205    return scoped_ptr<Address>();
206  }
207
208  base::string16 sorting_code;
209  if (!dictionary.GetString("sorting_code", &sorting_code)) {
210    DVLOG(1) << "Reponse from Google Wallet missing sorting code";
211  }
212
213  std::vector<base::string16> street_address;
214  base::string16 address1;
215  if (dictionary.GetString("address1", &address1))
216    street_address.push_back(address1);
217  else
218    DVLOG(1) << "Reponse from Google Wallet missing address1";
219
220  base::string16 address2;
221  if (dictionary.GetString("address2", &address2) && !address2.empty()) {
222    street_address.resize(2);
223    street_address[1] = address2;
224  } else {
225    DVLOG(1) << "Reponse from Google Wallet missing or empty address2";
226  }
227
228  base::string16 city;
229  if (!dictionary.GetString("city", &city))
230    DVLOG(1) << "Reponse from Google Wallet missing city";
231
232  base::string16 dependent_locality_name;
233  if (!dictionary.GetString("dependent_locality_name",
234                            &dependent_locality_name)) {
235    DVLOG(1) << "Reponse from Google Wallet missing district";
236  }
237
238  base::string16 state;
239  if (!dictionary.GetString("state", &state))
240    DVLOG(1) << "Reponse from Google Wallet missing state";
241
242  base::string16 phone_number;
243  if (!dictionary.GetString("phone_number", &phone_number))
244    DVLOG(1) << "Reponse from Google Wallet missing phone number";
245
246  std::string address_state;
247  if (!dictionary.GetString("type", &address_state))
248    DVLOG(1) << "Response from Google Wallet missing type/state of address";
249
250  std::string language_code;
251  if (!dictionary.GetString("language_code", &language_code))
252    DVLOG(1) << "Response from Google Wallet missing language code";
253
254  scoped_ptr<Address> address(
255      new Address(country_code,
256                  name,
257                  street_address,
258                  city,
259                  dependent_locality_name,
260                  state,
261                  postal_code,
262                  sorting_code,
263                  phone_number,
264                  std::string(),
265                  language_code));
266  address->set_is_complete_address(address_state == kFullAddress);
267
268  return address.Pass();
269}
270
271scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithID() const {
272  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
273
274  if (!object_id_.empty())
275    dict->SetString("id", object_id_);
276  dict->SetString("phone_number", phone_number_);
277  dict->Set("postal_address", ToDictionaryWithoutID().release());
278
279  return dict.Pass();
280}
281
282scoped_ptr<base::DictionaryValue> Address::ToDictionaryWithoutID() const {
283  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
284
285  scoped_ptr<base::ListValue> address_lines(new base::ListValue());
286  address_lines->AppendStrings(street_address_);
287  dict->Set("address_line", address_lines.release());
288
289  dict->SetString("country_name_code", country_name_code_);
290  dict->SetString("recipient_name", recipient_name_);
291  dict->SetString("locality_name", locality_name_);
292  dict->SetString("dependent_locality_name", dependent_locality_name_);
293  dict->SetString("administrative_area_name",
294                  administrative_area_name_);
295  dict->SetString("postal_code_number", postal_code_number_);
296  dict->SetString("sorting_code", sorting_code_);
297  dict->SetString("language_code", language_code_);
298
299  return dict.Pass();
300}
301
302base::string16 Address::DisplayName() const {
303#if defined(OS_ANDROID)
304  // TODO(aruslan): improve this stub implementation.
305  return recipient_name();
306#else
307  // TODO(estade): improve this stub implementation + l10n.
308  return recipient_name() + base::ASCIIToUTF16(", ") + GetStreetAddressLine(0);
309#endif
310}
311
312base::string16 Address::DisplayNameDetail() const {
313#if defined(OS_ANDROID)
314  // TODO(aruslan): improve this stub implementation.
315  return GetStreetAddressLine(0);
316#else
317  return base::string16();
318#endif
319}
320
321base::string16 Address::DisplayPhoneNumber() const {
322  // Return a formatted phone number. Wallet doesn't store user formatting, so
323  // impose our own. phone_number() always includes a country code, so using
324  // PhoneObject to format it would result in an internationalized format. Since
325  // Wallet only supports the US right now, stick to national formatting.
326  return i18n::PhoneObject(phone_number(), country_name_code()).
327      GetNationallyFormattedNumber();
328}
329
330base::string16 Address::GetInfo(const AutofillType& type,
331                                const std::string& app_locale) const {
332  if (type.html_type() == HTML_TYPE_COUNTRY_CODE) {
333    DCHECK(base::IsStringASCII(country_name_code()));
334    return base::ASCIIToUTF16(country_name_code());
335  }
336
337  switch (type.GetStorableType()) {
338    case NAME_FULL:
339      return recipient_name();
340
341    case ADDRESS_HOME_STREET_ADDRESS:
342      return JoinString(street_address_, base::ASCIIToUTF16("\n"));
343
344    case ADDRESS_HOME_LINE1:
345      return GetStreetAddressLine(0);
346
347    case ADDRESS_HOME_LINE2:
348      return GetStreetAddressLine(1);
349
350    case ADDRESS_HOME_CITY:
351      return locality_name();
352
353    case ADDRESS_HOME_STATE:
354      return administrative_area_name();
355
356    case ADDRESS_HOME_ZIP:
357      return postal_code_number();
358
359    case ADDRESS_HOME_COUNTRY: {
360      AutofillCountry country(country_name_code(), app_locale);
361      return country.name();
362    }
363
364    case PHONE_HOME_WHOLE_NUMBER:
365      // Wallet doesn't store user phone number formatting, so just strip all
366      // formatting.
367      return phone_object_.GetWholeNumber();
368
369    case ADDRESS_HOME_DEPENDENT_LOCALITY:
370      return dependent_locality_name_;
371
372    case ADDRESS_HOME_SORTING_CODE:
373      return sorting_code_;
374
375    case COMPANY_NAME:
376      // A field that Wallet doesn't support. TODO(dbeam): can it be supported?
377      return base::string16();
378
379    default:
380      NOTREACHED();
381      return base::string16();
382  }
383}
384
385void Address::SetPhoneNumber(const base::string16& phone_number) {
386  phone_number_ = phone_number;
387  phone_object_ = i18n::PhoneObject(phone_number_, country_name_code_);
388}
389
390bool Address::EqualsIgnoreID(const Address& other) const {
391  return country_name_code_ == other.country_name_code_ &&
392         recipient_name_ == other.recipient_name_ &&
393         street_address_ == other.street_address_ &&
394         locality_name_ == other.locality_name_ &&
395         dependent_locality_name_ == other.dependent_locality_name_ &&
396         administrative_area_name_ == other.administrative_area_name_ &&
397         postal_code_number_ == other.postal_code_number_ &&
398         sorting_code_ == other.sorting_code_ &&
399         phone_number_ == other.phone_number_ &&
400         is_complete_address_ == other.is_complete_address_;
401}
402
403base::string16 Address::GetStreetAddressLine(size_t line) const {
404  return street_address_.size() > line ? street_address_[line] :
405                                         base::string16();
406}
407
408bool Address::operator==(const Address& other) const {
409  return object_id_ == other.object_id_ &&
410         language_code_ == other.language_code_ &&
411         EqualsIgnoreID(other);
412}
413
414bool Address::operator!=(const Address& other) const {
415  return !(*this == other);
416}
417
418}  // namespace wallet
419}  // namespace autofill
420