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/core/browser/phone_number.h"
6
7#include "base/basictypes.h"
8#include "base/strings/string_number_conversions.h"
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "components/autofill/core/browser/autofill_country.h"
12#include "components/autofill/core/browser/autofill_profile.h"
13#include "components/autofill/core/browser/autofill_type.h"
14#include "components/autofill/core/browser/field_types.h"
15#include "components/autofill/core/browser/phone_number_i18n.h"
16
17namespace autofill {
18namespace {
19
20// Returns the region code for this phone number, which is an ISO 3166 2-letter
21// country code.  The returned value is based on the |profile|; if the |profile|
22// does not have a country code associated with it, falls back to the country
23// code corresponding to the |app_locale|.
24std::string GetRegion(const AutofillProfile& profile,
25                      const std::string& app_locale) {
26  base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY);
27  if (!country_code.empty())
28    return base::UTF16ToASCII(country_code);
29
30  return AutofillCountry::CountryCodeForLocale(app_locale);
31}
32
33}  // namespace
34
35PhoneNumber::PhoneNumber(AutofillProfile* profile)
36    : profile_(profile) {
37}
38
39PhoneNumber::PhoneNumber(const PhoneNumber& number)
40    : profile_(NULL) {
41  *this = number;
42}
43
44PhoneNumber::~PhoneNumber() {}
45
46PhoneNumber& PhoneNumber::operator=(const PhoneNumber& number) {
47  if (this == &number)
48    return *this;
49
50  number_ = number.number_;
51  profile_ = number.profile_;
52  cached_parsed_phone_ = number.cached_parsed_phone_;
53  return *this;
54}
55
56void PhoneNumber::GetSupportedTypes(ServerFieldTypeSet* supported_types) const {
57  supported_types->insert(PHONE_HOME_WHOLE_NUMBER);
58  supported_types->insert(PHONE_HOME_NUMBER);
59  supported_types->insert(PHONE_HOME_CITY_CODE);
60  supported_types->insert(PHONE_HOME_CITY_AND_NUMBER);
61  supported_types->insert(PHONE_HOME_COUNTRY_CODE);
62}
63
64base::string16 PhoneNumber::GetRawInfo(ServerFieldType type) const {
65  DCHECK_EQ(PHONE_HOME, AutofillType(type).group());
66  if (type == PHONE_HOME_WHOLE_NUMBER)
67    return number_;
68
69  // Only the whole number is available as raw data.  All of the other types are
70  // parsed from this raw info, and parsing requires knowledge of the phone
71  // number's region, which is only available via GetInfo().
72  return base::string16();
73}
74
75void PhoneNumber::SetRawInfo(ServerFieldType type,
76                             const base::string16& value) {
77  DCHECK_EQ(PHONE_HOME, AutofillType(type).group());
78  if (type != PHONE_HOME_CITY_AND_NUMBER && type != PHONE_HOME_WHOLE_NUMBER) {
79    // Only full phone numbers should be set directly.  The remaining field
80    // field types are read-only.
81    return;
82  }
83
84  number_ = value;
85
86  // Invalidate the cached number.
87  cached_parsed_phone_ = i18n::PhoneObject();
88}
89
90// Normalize phones if |type| is a whole number:
91//   (650)2345678 -> 6502345678
92//   1-800-FLOWERS -> 18003569377
93// If the phone cannot be normalized, returns the stored value verbatim.
94base::string16 PhoneNumber::GetInfo(const AutofillType& type,
95                                    const std::string& app_locale) const {
96  ServerFieldType storable_type = type.GetStorableType();
97  UpdateCacheIfNeeded(app_locale);
98
99  // Queries for whole numbers will return the non-normalized number if
100  // normalization for the number fails.  All other field types require
101  // normalization.
102  if (storable_type != PHONE_HOME_WHOLE_NUMBER &&
103      !cached_parsed_phone_.IsValidNumber())
104    return base::string16();
105
106  switch (storable_type) {
107    case PHONE_HOME_WHOLE_NUMBER:
108      return cached_parsed_phone_.GetWholeNumber();
109
110    case PHONE_HOME_NUMBER:
111      return cached_parsed_phone_.number();
112
113    case PHONE_HOME_CITY_CODE:
114      return cached_parsed_phone_.city_code();
115
116    case PHONE_HOME_COUNTRY_CODE:
117      return cached_parsed_phone_.country_code();
118
119    case PHONE_HOME_CITY_AND_NUMBER:
120      return
121          cached_parsed_phone_.city_code() + cached_parsed_phone_.number();
122
123    default:
124      NOTREACHED();
125      return base::string16();
126  }
127}
128
129bool PhoneNumber::SetInfo(const AutofillType& type,
130                          const base::string16& value,
131                          const std::string& app_locale) {
132  SetRawInfo(type.GetStorableType(), value);
133
134  if (number_.empty())
135    return true;
136
137  // Store a formatted (i.e., pretty printed) version of the number if either
138  // the number doesn't contain formatting marks.
139  UpdateCacheIfNeeded(app_locale);
140  if (base::ContainsOnlyChars(number_, base::ASCIIToUTF16("+0123456789"))) {
141    number_ = cached_parsed_phone_.GetFormattedNumber();
142  } else if (i18n::NormalizePhoneNumber(
143                 number_, GetRegion(*profile_, app_locale)).empty()) {
144    // The number doesn't make sense for this region; clear it.
145    number_.clear();
146  }
147  return !number_.empty();
148}
149
150void PhoneNumber::GetMatchingTypes(const base::string16& text,
151                                   const std::string& app_locale,
152                                   ServerFieldTypeSet* matching_types) const {
153  base::string16 stripped_text = text;
154  base::RemoveChars(stripped_text, base::ASCIIToUTF16(" .()-"), &stripped_text);
155  FormGroup::GetMatchingTypes(stripped_text, app_locale, matching_types);
156
157  // For US numbers, also compare to the three-digit prefix and the four-digit
158  // suffix, since web sites often split numbers into these two fields.
159  base::string16 number = GetInfo(AutofillType(PHONE_HOME_NUMBER), app_locale);
160  if (GetRegion(*profile_, app_locale) == "US" &&
161      number.size() == (kPrefixLength + kSuffixLength)) {
162    base::string16 prefix = number.substr(kPrefixOffset, kPrefixLength);
163    base::string16 suffix = number.substr(kSuffixOffset, kSuffixLength);
164    if (text == prefix || text == suffix)
165      matching_types->insert(PHONE_HOME_NUMBER);
166  }
167
168  base::string16 whole_number =
169      GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale);
170  if (!whole_number.empty()) {
171    base::string16 normalized_number =
172        i18n::NormalizePhoneNumber(text, GetRegion(*profile_, app_locale));
173    if (normalized_number == whole_number)
174      matching_types->insert(PHONE_HOME_WHOLE_NUMBER);
175  }
176}
177
178void PhoneNumber::UpdateCacheIfNeeded(const std::string& app_locale) const {
179  std::string region = GetRegion(*profile_, app_locale);
180  if (!number_.empty() && cached_parsed_phone_.region() != region)
181    cached_parsed_phone_ = i18n::PhoneObject(number_, region);
182}
183
184PhoneNumber::PhoneCombineHelper::PhoneCombineHelper() {
185}
186
187PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() {
188}
189
190bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& type,
191                                              const base::string16& value) {
192  ServerFieldType storable_type = type.GetStorableType();
193  if (storable_type == PHONE_HOME_COUNTRY_CODE) {
194    country_ = value;
195    return true;
196  }
197
198  if (storable_type == PHONE_HOME_CITY_CODE) {
199    city_ = value;
200    return true;
201  }
202
203  if (storable_type == PHONE_HOME_CITY_AND_NUMBER) {
204    phone_ = value;
205    return true;
206  }
207
208  if (storable_type == PHONE_HOME_WHOLE_NUMBER) {
209    whole_number_ = value;
210    return true;
211  }
212
213  if (storable_type == PHONE_HOME_NUMBER) {
214    phone_.append(value);
215    return true;
216  }
217
218  return false;
219}
220
221bool PhoneNumber::PhoneCombineHelper::ParseNumber(
222    const AutofillProfile& profile,
223    const std::string& app_locale,
224    base::string16* value) {
225  if (IsEmpty())
226    return false;
227
228  if (!whole_number_.empty()) {
229    *value = whole_number_;
230    return true;
231  }
232
233  return i18n::ConstructPhoneNumber(
234      country_, city_, phone_, GetRegion(profile, app_locale), value);
235}
236
237bool PhoneNumber::PhoneCombineHelper::IsEmpty() const {
238  return phone_.empty() && whole_number_.empty();
239}
240
241}  // namespace autofill
242