autofill_profile.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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/autofill_profile.h"
6
7#include <algorithm>
8#include <functional>
9#include <map>
10#include <ostream>
11#include <set>
12
13#include "base/basictypes.h"
14#include "base/guid.h"
15#include "base/logging.h"
16#include "base/strings/string_util.h"
17#include "base/strings/utf_string_conversions.h"
18#include "components/autofill/core/browser/address.h"
19#include "components/autofill/core/browser/address_i18n.h"
20#include "components/autofill/core/browser/autofill_country.h"
21#include "components/autofill/core/browser/autofill_field.h"
22#include "components/autofill/core/browser/autofill_type.h"
23#include "components/autofill/core/browser/contact_info.h"
24#include "components/autofill/core/browser/phone_number.h"
25#include "components/autofill/core/browser/phone_number_i18n.h"
26#include "components/autofill/core/browser/validation.h"
27#include "components/autofill/core/common/form_field_data.h"
28#include "grit/components_strings.h"
29#include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_data.h"
30#include "ui/base/l10n/l10n_util.h"
31
32using base::ASCIIToUTF16;
33using base::UTF16ToUTF8;
34
35namespace autofill {
36namespace {
37
38// Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for
39// first, middle, and last name field types.
40ServerFieldType GetStorableTypeCollapsingNames(ServerFieldType type) {
41  ServerFieldType storable_type = AutofillType(type).GetStorableType();
42  if (AutofillType(storable_type).group() == NAME)
43    return NAME_FULL;
44
45  return storable_type;
46}
47
48// Fills |distinguishing_fields| with a list of fields to use when creating
49// labels that can help to distinguish between two profiles. Draws fields from
50// |suggested_fields| if it is non-NULL; otherwise returns a default list.
51// If |suggested_fields| is non-NULL, does not include |excluded_field| in the
52// list. Otherwise, |excluded_field| is ignored, and should be set to
53// |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
54// decreasing order of importance.
55void GetFieldsForDistinguishingProfiles(
56    const std::vector<ServerFieldType>* suggested_fields,
57    ServerFieldType excluded_field,
58    std::vector<ServerFieldType>* distinguishing_fields) {
59  static const ServerFieldType kDefaultDistinguishingFields[] = {
60    NAME_FULL,
61    ADDRESS_HOME_LINE1,
62    ADDRESS_HOME_LINE2,
63    ADDRESS_HOME_CITY,
64    ADDRESS_HOME_STATE,
65    ADDRESS_HOME_ZIP,
66    ADDRESS_HOME_COUNTRY,
67    EMAIL_ADDRESS,
68    PHONE_HOME_WHOLE_NUMBER,
69    COMPANY_NAME,
70  };
71
72  if (!suggested_fields) {
73    DCHECK_EQ(excluded_field, UNKNOWN_TYPE);
74    distinguishing_fields->assign(
75        kDefaultDistinguishingFields,
76        kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
77    return;
78  }
79
80  // Keep track of which fields we've seen so that we avoid duplicate entries.
81  // Always ignore fields of unknown type and the excluded field.
82  std::set<ServerFieldType> seen_fields;
83  seen_fields.insert(UNKNOWN_TYPE);
84  seen_fields.insert(GetStorableTypeCollapsingNames(excluded_field));
85
86  distinguishing_fields->clear();
87  for (std::vector<ServerFieldType>::const_iterator it =
88           suggested_fields->begin();
89       it != suggested_fields->end(); ++it) {
90    ServerFieldType suggested_type = GetStorableTypeCollapsingNames(*it);
91    if (seen_fields.insert(suggested_type).second)
92      distinguishing_fields->push_back(suggested_type);
93  }
94
95  // Special case: If the excluded field is a partial name (e.g. first name) and
96  // the suggested fields include other name fields, include |NAME_FULL| in the
97  // list of distinguishing fields as a last-ditch fallback. This allows us to
98  // distinguish between profiles that are identical except for the name.
99  if (excluded_field != NAME_FULL &&
100      GetStorableTypeCollapsingNames(excluded_field) == NAME_FULL) {
101    for (std::vector<ServerFieldType>::const_iterator it =
102             suggested_fields->begin();
103         it != suggested_fields->end(); ++it) {
104      if (*it != excluded_field &&
105          GetStorableTypeCollapsingNames(*it) == NAME_FULL) {
106        distinguishing_fields->push_back(NAME_FULL);
107        break;
108      }
109    }
110  }
111}
112
113// A helper function for string streaming.  Concatenates multi-valued entries
114// stored for a given |type| into a single string.  This string is returned.
115const base::string16 MultiString(const AutofillProfile& p,
116                                 ServerFieldType type) {
117  std::vector<base::string16> values;
118  p.GetRawMultiInfo(type, &values);
119  base::string16 accumulate;
120  for (size_t i = 0; i < values.size(); ++i) {
121    if (i > 0)
122      accumulate += ASCIIToUTF16(" ");
123    accumulate += values[i];
124  }
125  return accumulate;
126}
127
128base::string16 GetFormGroupInfo(const FormGroup& form_group,
129                                const AutofillType& type,
130                                const std::string& app_locale) {
131  return app_locale.empty() ?
132      form_group.GetRawInfo(type.GetStorableType()) :
133      form_group.GetInfo(type, app_locale);
134}
135
136template <class T>
137void CopyValuesToItems(ServerFieldType type,
138                       const std::vector<base::string16>& values,
139                       std::vector<T>* form_group_items,
140                       const T& prototype) {
141  form_group_items->resize(values.size(), prototype);
142  for (size_t i = 0; i < form_group_items->size(); ++i) {
143    (*form_group_items)[i].SetRawInfo(type, values[i]);
144  }
145  // Must have at least one (possibly empty) element.
146  if (form_group_items->empty())
147    form_group_items->resize(1, prototype);
148}
149
150template <class T>
151void CopyItemsToValues(const AutofillType& type,
152                       const std::vector<T>& form_group_items,
153                       const std::string& app_locale,
154                       std::vector<base::string16>* values) {
155  values->resize(form_group_items.size());
156  for (size_t i = 0; i < values->size(); ++i) {
157    (*values)[i] = GetFormGroupInfo(form_group_items[i], type, app_locale);
158  }
159}
160
161// Collapse compound field types to their "full" type.  I.e. First name
162// collapses to full name, area code collapses to full phone, etc.
163void CollapseCompoundFieldTypes(ServerFieldTypeSet* type_set) {
164  ServerFieldTypeSet collapsed_set;
165  for (ServerFieldTypeSet::iterator it = type_set->begin();
166       it != type_set->end(); ++it) {
167    switch (*it) {
168      case NAME_FIRST:
169      case NAME_MIDDLE:
170      case NAME_LAST:
171      case NAME_MIDDLE_INITIAL:
172      case NAME_FULL:
173      case NAME_SUFFIX:
174        collapsed_set.insert(NAME_FULL);
175        break;
176
177      case PHONE_HOME_NUMBER:
178      case PHONE_HOME_CITY_CODE:
179      case PHONE_HOME_COUNTRY_CODE:
180      case PHONE_HOME_CITY_AND_NUMBER:
181      case PHONE_HOME_WHOLE_NUMBER:
182        collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER);
183        break;
184
185      default:
186        collapsed_set.insert(*it);
187    }
188  }
189  std::swap(*type_set, collapsed_set);
190}
191
192class FindByPhone {
193 public:
194  FindByPhone(const base::string16& phone,
195              const std::string& country_code,
196              const std::string& app_locale)
197      : phone_(phone),
198        country_code_(country_code),
199        app_locale_(app_locale) {
200  }
201
202  bool operator()(const base::string16& phone) {
203    return i18n::PhoneNumbersMatch(phone, phone_, country_code_, app_locale_);
204  }
205
206  bool operator()(const base::string16* phone) {
207    return i18n::PhoneNumbersMatch(*phone, phone_, country_code_, app_locale_);
208  }
209
210 private:
211  base::string16 phone_;
212  std::string country_code_;
213  std::string app_locale_;
214};
215
216// Functor used to check for case-insensitive equality of two strings.
217struct CaseInsensitiveStringEquals
218    : public std::binary_function<base::string16, base::string16, bool>
219{
220  bool operator()(const base::string16& x, const base::string16& y) const {
221    return
222        x.size() == y.size() && StringToLowerASCII(x) == StringToLowerASCII(y);
223  }
224};
225
226}  // namespace
227
228AutofillProfile::AutofillProfile(const std::string& guid,
229                                 const std::string& origin)
230    : AutofillDataModel(guid, origin),
231      name_(1),
232      email_(1),
233      phone_number_(1, PhoneNumber(this)) {
234}
235
236AutofillProfile::AutofillProfile()
237    : AutofillDataModel(base::GenerateGUID(), std::string()),
238      name_(1),
239      email_(1),
240      phone_number_(1, PhoneNumber(this)) {
241}
242
243AutofillProfile::AutofillProfile(const AutofillProfile& profile)
244    : AutofillDataModel(std::string(), std::string()) {
245  operator=(profile);
246}
247
248AutofillProfile::~AutofillProfile() {
249}
250
251AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
252  if (this == &profile)
253    return *this;
254
255  set_guid(profile.guid());
256  set_origin(profile.origin());
257
258  name_ = profile.name_;
259  email_ = profile.email_;
260  company_ = profile.company_;
261  phone_number_ = profile.phone_number_;
262
263  for (size_t i = 0; i < phone_number_.size(); ++i)
264    phone_number_[i].set_profile(this);
265
266  address_ = profile.address_;
267  set_language_code(profile.language_code());
268
269  return *this;
270}
271
272void AutofillProfile::GetMatchingTypes(
273    const base::string16& text,
274    const std::string& app_locale,
275    ServerFieldTypeSet* matching_types) const {
276  FormGroupList info = FormGroups();
277  for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
278    (*it)->GetMatchingTypes(text, app_locale, matching_types);
279}
280
281base::string16 AutofillProfile::GetRawInfo(ServerFieldType type) const {
282  const FormGroup* form_group = FormGroupForType(AutofillType(type));
283  if (!form_group)
284    return base::string16();
285
286  return form_group->GetRawInfo(type);
287}
288
289void AutofillProfile::SetRawInfo(ServerFieldType type,
290                                 const base::string16& value) {
291  FormGroup* form_group = MutableFormGroupForType(AutofillType(type));
292  if (form_group)
293    form_group->SetRawInfo(type, value);
294}
295
296base::string16 AutofillProfile::GetInfo(const AutofillType& type,
297                                        const std::string& app_locale) const {
298  if (type.html_type() == HTML_TYPE_FULL_ADDRESS) {
299    scoped_ptr< ::i18n::addressinput::AddressData> address_data =
300        i18n::CreateAddressDataFromAutofillProfile(*this, app_locale);
301    if (!address_data->HasAllRequiredFields())
302      return base::string16();
303
304    std::vector<std::string> lines;
305    address_data->FormatForDisplay(&lines);
306    return base::UTF8ToUTF16(JoinString(lines, '\n'));
307  }
308
309  const FormGroup* form_group = FormGroupForType(type);
310  if (!form_group)
311    return base::string16();
312
313  return form_group->GetInfo(type, app_locale);
314}
315
316bool AutofillProfile::SetInfo(const AutofillType& type,
317                              const base::string16& value,
318                              const std::string& app_locale) {
319  FormGroup* form_group = MutableFormGroupForType(type);
320  if (!form_group)
321    return false;
322
323  base::string16 trimmed_value;
324  base::TrimWhitespace(value, base::TRIM_ALL, &trimmed_value);
325  return form_group->SetInfo(type, trimmed_value, app_locale);
326}
327
328base::string16 AutofillProfile::GetInfoForVariant(
329    const AutofillType& type,
330    size_t variant,
331    const std::string& app_locale) const {
332  std::vector<base::string16> values;
333  GetMultiInfo(type, app_locale, &values);
334
335  if (variant >= values.size()) {
336    // If the variant is unavailable, bail. This case is reachable, for
337    // example if Sync updates a profile during the filling process.
338    return base::string16();
339  }
340
341  return values[variant];
342}
343
344void AutofillProfile::SetRawMultiInfo(
345    ServerFieldType type,
346    const std::vector<base::string16>& values) {
347  switch (AutofillType(type).group()) {
348    case NAME:
349    case NAME_BILLING:
350      CopyValuesToItems(type, values, &name_, NameInfo());
351      break;
352    case EMAIL:
353      CopyValuesToItems(type, values, &email_, EmailInfo());
354      break;
355    case PHONE_HOME:
356    case PHONE_BILLING:
357      CopyValuesToItems(type,
358                        values,
359                        &phone_number_,
360                        PhoneNumber(this));
361      break;
362    default:
363      if (values.size() == 1) {
364        SetRawInfo(type, values[0]);
365      } else if (values.size() == 0) {
366        SetRawInfo(type, base::string16());
367      } else {
368        // Shouldn't attempt to set multiple values on single-valued field.
369        NOTREACHED();
370      }
371      break;
372  }
373}
374
375void AutofillProfile::GetRawMultiInfo(
376    ServerFieldType type,
377    std::vector<base::string16>* values) const {
378  GetMultiInfoImpl(AutofillType(type), std::string(), values);
379}
380
381void AutofillProfile::GetMultiInfo(const AutofillType& type,
382                                   const std::string& app_locale,
383                                   std::vector<base::string16>* values) const {
384  GetMultiInfoImpl(type, app_locale, values);
385}
386
387bool AutofillProfile::IsEmpty(const std::string& app_locale) const {
388  ServerFieldTypeSet types;
389  GetNonEmptyTypes(app_locale, &types);
390  return types.empty();
391}
392
393bool AutofillProfile::IsPresentButInvalid(ServerFieldType type) const {
394  std::string country = UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY));
395  base::string16 data = GetRawInfo(type);
396  if (data.empty())
397    return false;
398
399  switch (type) {
400    case ADDRESS_HOME_STATE:
401      return country == "US" && !autofill::IsValidState(data);
402
403    case ADDRESS_HOME_ZIP:
404      return country == "US" && !autofill::IsValidZip(data);
405
406    case PHONE_HOME_WHOLE_NUMBER:
407      return !i18n::PhoneObject(data, country).IsValidNumber();
408
409    case EMAIL_ADDRESS:
410      return !autofill::IsValidEmailAddress(data);
411
412    default:
413      NOTREACHED();
414      return false;
415  }
416}
417
418int AutofillProfile::Compare(const AutofillProfile& profile) const {
419  const ServerFieldType single_value_types[] = {
420    COMPANY_NAME,
421    ADDRESS_HOME_STREET_ADDRESS,
422    ADDRESS_HOME_DEPENDENT_LOCALITY,
423    ADDRESS_HOME_CITY,
424    ADDRESS_HOME_STATE,
425    ADDRESS_HOME_ZIP,
426    ADDRESS_HOME_SORTING_CODE,
427    ADDRESS_HOME_COUNTRY,
428  };
429
430  for (size_t i = 0; i < arraysize(single_value_types); ++i) {
431    int comparison = GetRawInfo(single_value_types[i]).compare(
432        profile.GetRawInfo(single_value_types[i]));
433    if (comparison != 0)
434      return comparison;
435  }
436
437  const ServerFieldType multi_value_types[] = { NAME_FIRST,
438                                                NAME_MIDDLE,
439                                                NAME_LAST,
440                                                EMAIL_ADDRESS,
441                                                PHONE_HOME_WHOLE_NUMBER };
442
443  for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
444    std::vector<base::string16> values_a;
445    std::vector<base::string16> values_b;
446    GetRawMultiInfo(multi_value_types[i], &values_a);
447    profile.GetRawMultiInfo(multi_value_types[i], &values_b);
448    if (values_a.size() < values_b.size())
449      return -1;
450    if (values_a.size() > values_b.size())
451      return 1;
452    for (size_t j = 0; j < values_a.size(); ++j) {
453      int comparison = values_a[j].compare(values_b[j]);
454      if (comparison != 0)
455        return comparison;
456    }
457  }
458
459  return 0;
460}
461
462bool AutofillProfile::EqualsSansOrigin(const AutofillProfile& profile) const {
463  return guid() == profile.guid() &&
464         language_code() == profile.language_code() &&
465         Compare(profile) == 0;
466}
467
468bool AutofillProfile::EqualsSansGuid(const AutofillProfile& profile) const {
469  return origin() == profile.origin() &&
470         language_code() == profile.language_code() &&
471         Compare(profile) == 0;
472}
473
474bool AutofillProfile::operator==(const AutofillProfile& profile) const {
475  return guid() == profile.guid() && EqualsSansGuid(profile);
476}
477
478bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
479  return !operator==(profile);
480}
481
482const base::string16 AutofillProfile::PrimaryValue() const {
483  return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY);
484}
485
486bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile,
487                                 const std::string& app_locale) const {
488  ServerFieldTypeSet types;
489  GetNonEmptyTypes(app_locale, &types);
490
491  for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end();
492       ++it) {
493    if (*it == NAME_FULL || *it == ADDRESS_HOME_STREET_ADDRESS) {
494      // Ignore the compound "full name" field type.  We are only interested in
495      // comparing the constituent parts.  For example, if |this| has a middle
496      // name saved, but |profile| lacks one, |profile| could still be a subset
497      // of |this|.  Likewise, ignore the compound "street address" type, as we
498      // are only interested in matching line-by-line.
499      continue;
500    } else if (AutofillType(*it).group() == PHONE_HOME) {
501      // Phone numbers should be canonicalized prior to being compared.
502      if (*it != PHONE_HOME_WHOLE_NUMBER) {
503        continue;
504      } else if (!i18n::PhoneNumbersMatch(
505            GetRawInfo(*it),
506            profile.GetRawInfo(*it),
507            base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)),
508            app_locale)) {
509        return false;
510      }
511    } else if (StringToLowerASCII(GetRawInfo(*it)) !=
512                   StringToLowerASCII(profile.GetRawInfo(*it))) {
513      return false;
514    }
515  }
516
517  return true;
518}
519
520void AutofillProfile::OverwriteOrAppendNames(
521    const std::vector<NameInfo>& names) {
522  std::vector<NameInfo> results(name_);
523  for (std::vector<NameInfo>::const_iterator it = names.begin();
524       it != names.end();
525       ++it) {
526    NameInfo imported_name = *it;
527    bool should_append_imported_name = true;
528
529    for (size_t index = 0; index < name_.size(); ++index) {
530      NameInfo current_name = name_[index];
531      if (current_name.EqualsIgnoreCase(imported_name)) {
532        should_append_imported_name = false;
533        break;
534      }
535
536      base::string16 full_name = current_name.GetRawInfo(NAME_FULL);
537      if (StringToLowerASCII(full_name) ==
538          StringToLowerASCII(imported_name.GetRawInfo(NAME_FULL))) {
539        // The imported name has the same full name string as one of the
540        // existing names for this profile.  Because full names are
541        // _heuristically_ parsed into {first, middle, last} name components,
542        // it's possible that either the existing name or the imported name
543        // was misparsed.  Prefer to keep the name whose {first, middle,
544        // last} components do not match those computed by the heuristic
545        // parse, as this more likely represents the correct, user-input parse
546        // of the name.
547        NameInfo heuristically_parsed_name;
548        heuristically_parsed_name.SetRawInfo(NAME_FULL, full_name);
549        if (imported_name.EqualsIgnoreCase(heuristically_parsed_name)) {
550          should_append_imported_name = false;
551          break;
552        }
553
554        if (current_name.EqualsIgnoreCase(heuristically_parsed_name)) {
555          results[index] = imported_name;
556          should_append_imported_name = false;
557          break;
558        }
559      }
560    }
561
562    // Append unique names to the list.
563    if (should_append_imported_name)
564      results.push_back(imported_name);
565  }
566
567  name_.swap(results);
568}
569
570void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile,
571                                           const std::string& app_locale) {
572  // Verified profiles should never be overwritten with unverified data.
573  DCHECK(!IsVerified() || profile.IsVerified());
574  set_origin(profile.origin());
575  set_language_code(profile.language_code());
576
577  ServerFieldTypeSet field_types;
578  profile.GetNonEmptyTypes(app_locale, &field_types);
579
580  // Only transfer "full" types (e.g. full name) and not fragments (e.g.
581  // first name, last name).
582  CollapseCompoundFieldTypes(&field_types);
583
584  // TODO(isherman): Revisit this decision in the context of i18n and storing
585  // full addresses rather than storing 1-to-2 lines of an address.
586  // For addresses, do the opposite: transfer individual address lines, rather
587  // than full addresses.
588  field_types.erase(ADDRESS_HOME_STREET_ADDRESS);
589
590  for (ServerFieldTypeSet::const_iterator iter = field_types.begin();
591       iter != field_types.end(); ++iter) {
592    if (AutofillProfile::SupportsMultiValue(*iter)) {
593      std::vector<base::string16> new_values;
594      profile.GetRawMultiInfo(*iter, &new_values);
595      std::vector<base::string16> existing_values;
596      GetRawMultiInfo(*iter, &existing_values);
597
598      // GetMultiInfo always returns at least one element, even if the profile
599      // has no data stored for this field type.
600      if (existing_values.size() == 1 && existing_values.front().empty())
601        existing_values.clear();
602
603      FieldTypeGroup group = AutofillType(*iter).group();
604      for (std::vector<base::string16>::iterator value_iter =
605               new_values.begin();
606           value_iter != new_values.end(); ++value_iter) {
607        // Don't add duplicates.
608        if (group == PHONE_HOME) {
609          AddPhoneIfUnique(*value_iter, app_locale, &existing_values);
610        } else {
611          std::vector<base::string16>::const_iterator existing_iter =
612              std::find_if(
613                  existing_values.begin(), existing_values.end(),
614                  std::bind1st(CaseInsensitiveStringEquals(), *value_iter));
615          if (existing_iter == existing_values.end())
616            existing_values.insert(existing_values.end(), *value_iter);
617        }
618      }
619      if (group == NAME)
620        OverwriteOrAppendNames(profile.name_);
621      else
622        SetRawMultiInfo(*iter, existing_values);
623    } else {
624      base::string16 new_value = profile.GetRawInfo(*iter);
625      if (StringToLowerASCII(GetRawInfo(*iter)) !=
626              StringToLowerASCII(new_value)) {
627        SetRawInfo(*iter, new_value);
628      }
629    }
630  }
631}
632
633// static
634bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
635  FieldTypeGroup group = AutofillType(type).group();
636  return group == NAME ||
637         group == NAME_BILLING ||
638         group == EMAIL ||
639         group == PHONE_HOME ||
640         group == PHONE_BILLING;
641}
642
643// static
644void AutofillProfile::CreateDifferentiatingLabels(
645    const std::vector<AutofillProfile*>& profiles,
646    std::vector<base::string16>* labels) {
647  const size_t kMinimalFieldsShown = 2;
648  CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
649                       labels);
650  DCHECK_EQ(profiles.size(), labels->size());
651}
652
653// static
654void AutofillProfile::CreateInferredLabels(
655    const std::vector<AutofillProfile*>& profiles,
656    const std::vector<ServerFieldType>* suggested_fields,
657    ServerFieldType excluded_field,
658    size_t minimal_fields_shown,
659    std::vector<base::string16>* labels) {
660  std::vector<ServerFieldType> fields_to_use;
661  GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
662                                     &fields_to_use);
663
664  // Construct the default label for each profile. Also construct a map that
665  // associates each label with the profiles that have this label. This map is
666  // then used to detect which labels need further differentiating fields.
667  std::map<base::string16, std::list<size_t> > labels_to_profiles;
668  for (size_t i = 0; i < profiles.size(); ++i) {
669    base::string16 label =
670        profiles[i]->ConstructInferredLabel(fields_to_use,
671                                            minimal_fields_shown);
672    labels_to_profiles[label].push_back(i);
673  }
674
675  labels->resize(profiles.size());
676  for (std::map<base::string16, std::list<size_t> >::const_iterator it =
677           labels_to_profiles.begin();
678       it != labels_to_profiles.end(); ++it) {
679    if (it->second.size() == 1) {
680      // This label is unique, so use it without any further ado.
681      base::string16 label = it->first;
682      size_t profile_index = it->second.front();
683      (*labels)[profile_index] = label;
684    } else {
685      // We have more than one profile with the same label, so add
686      // differentiating fields.
687      CreateInferredLabelsHelper(profiles, it->second, fields_to_use,
688                                 minimal_fields_shown, labels);
689    }
690  }
691}
692
693void AutofillProfile::GetSupportedTypes(
694    ServerFieldTypeSet* supported_types) const {
695  FormGroupList info = FormGroups();
696  for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
697    (*it)->GetSupportedTypes(supported_types);
698}
699
700void AutofillProfile::GetMultiInfoImpl(
701    const AutofillType& type,
702    const std::string& app_locale,
703    std::vector<base::string16>* values) const {
704  switch (type.group()) {
705    case NAME:
706    case NAME_BILLING:
707      CopyItemsToValues(type, name_, app_locale, values);
708      break;
709    case EMAIL:
710      CopyItemsToValues(type, email_, app_locale, values);
711      break;
712    case PHONE_HOME:
713    case PHONE_BILLING:
714      CopyItemsToValues(type, phone_number_, app_locale, values);
715      break;
716    default:
717      values->resize(1);
718      (*values)[0] = GetFormGroupInfo(*this, type, app_locale);
719  }
720}
721
722void AutofillProfile::AddPhoneIfUnique(
723    const base::string16& phone,
724    const std::string& app_locale,
725    std::vector<base::string16>* existing_phones) {
726  DCHECK(existing_phones);
727  // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
728  // "(800)356-9377" and "356-9377" are considered the same.
729  std::string country_code =
730      base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
731  if (std::find_if(existing_phones->begin(), existing_phones->end(),
732                   FindByPhone(phone, country_code, app_locale)) ==
733      existing_phones->end()) {
734    existing_phones->push_back(phone);
735  }
736}
737
738base::string16 AutofillProfile::ConstructInferredLabel(
739    const std::vector<ServerFieldType>& included_fields,
740    size_t num_fields_to_use) const {
741  const base::string16 separator =
742      l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
743
744  base::string16 label;
745  size_t num_fields_used = 0;
746  for (std::vector<ServerFieldType>::const_iterator it =
747           included_fields.begin();
748       it != included_fields.end() && num_fields_used < num_fields_to_use;
749       ++it) {
750    base::string16 field = GetRawInfo(*it);
751    if (field.empty())
752      continue;
753
754    if (!label.empty())
755      label.append(separator);
756
757    label.append(field);
758    ++num_fields_used;
759  }
760
761  // Flatten the label if need be.
762  const base::string16& line_separator =
763      l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR);
764  base::ReplaceChars(label, base::ASCIIToUTF16("\n"), line_separator, &label);
765
766  return label;
767}
768
769// static
770void AutofillProfile::CreateInferredLabelsHelper(
771    const std::vector<AutofillProfile*>& profiles,
772    const std::list<size_t>& indices,
773    const std::vector<ServerFieldType>& fields,
774    size_t num_fields_to_include,
775    std::vector<base::string16>* labels) {
776  // For efficiency, we first construct a map of fields to their text values and
777  // each value's frequency.
778  std::map<ServerFieldType,
779           std::map<base::string16, size_t> > field_text_frequencies_by_field;
780  for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
781       field != fields.end(); ++field) {
782    std::map<base::string16, size_t>& field_text_frequencies =
783        field_text_frequencies_by_field[*field];
784
785    for (std::list<size_t>::const_iterator it = indices.begin();
786         it != indices.end(); ++it) {
787      const AutofillProfile* profile = profiles[*it];
788      base::string16 field_text = profile->GetRawInfo(*field);
789
790      // If this label is not already in the map, add it with frequency 0.
791      if (!field_text_frequencies.count(field_text))
792        field_text_frequencies[field_text] = 0;
793
794      // Now, increment the frequency for this label.
795      ++field_text_frequencies[field_text];
796    }
797  }
798
799  // Now comes the meat of the algorithm. For each profile, we scan the list of
800  // fields to use, looking for two things:
801  //  1. A (non-empty) field that differentiates the profile from all others
802  //  2. At least |num_fields_to_include| non-empty fields
803  // Before we've satisfied condition (2), we include all fields, even ones that
804  // are identical across all the profiles. Once we've satisfied condition (2),
805  // we only include fields that that have at last two distinct values.
806  for (std::list<size_t>::const_iterator it = indices.begin();
807       it != indices.end(); ++it) {
808    const AutofillProfile* profile = profiles[*it];
809
810    std::vector<ServerFieldType> label_fields;
811    bool found_differentiating_field = false;
812    for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
813         field != fields.end(); ++field) {
814      // Skip over empty fields.
815      base::string16 field_text = profile->GetRawInfo(*field);
816      if (field_text.empty())
817        continue;
818
819      std::map<base::string16, size_t>& field_text_frequencies =
820          field_text_frequencies_by_field[*field];
821      found_differentiating_field |=
822          !field_text_frequencies.count(base::string16()) &&
823          (field_text_frequencies[field_text] == 1);
824
825      // Once we've found enough non-empty fields, skip over any remaining
826      // fields that are identical across all the profiles.
827      if (label_fields.size() >= num_fields_to_include &&
828          (field_text_frequencies.size() == 1))
829        continue;
830
831      label_fields.push_back(*field);
832
833      // If we've (1) found a differentiating field and (2) found at least
834      // |num_fields_to_include| non-empty fields, we're done!
835      if (found_differentiating_field &&
836          label_fields.size() >= num_fields_to_include)
837        break;
838    }
839
840    (*labels)[*it] =
841        profile->ConstructInferredLabel(label_fields, label_fields.size());
842  }
843}
844
845AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
846  FormGroupList v(5);
847  v[0] = &name_[0];
848  v[1] = &email_[0];
849  v[2] = &company_;
850  v[3] = &phone_number_[0];
851  v[4] = &address_;
852  return v;
853}
854
855const FormGroup* AutofillProfile::FormGroupForType(
856    const AutofillType& type) const {
857  return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
858}
859
860FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) {
861  switch (type.group()) {
862    case NAME:
863    case NAME_BILLING:
864      return &name_[0];
865
866    case EMAIL:
867      return &email_[0];
868
869    case COMPANY:
870      return &company_;
871
872    case PHONE_HOME:
873    case PHONE_BILLING:
874      return &phone_number_[0];
875
876    case ADDRESS_HOME:
877    case ADDRESS_BILLING:
878      return &address_;
879
880    case NO_GROUP:
881    case CREDIT_CARD:
882    case PASSWORD_FIELD:
883        return NULL;
884  }
885
886  NOTREACHED();
887  return NULL;
888}
889
890// So we can compare AutofillProfiles with EXPECT_EQ().
891std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
892  return os
893      << profile.guid()
894      << " "
895      << profile.origin()
896      << " "
897      << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
898      << " "
899      << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
900      << " "
901      << UTF16ToUTF8(MultiString(profile, NAME_LAST))
902      << " "
903      << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
904      << " "
905      << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))
906      << " "
907      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))
908      << " "
909      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))
910      << " "
911      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))
912      << " "
913      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))
914      << " "
915      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))
916      << " "
917      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))
918      << " "
919      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE))
920      << " "
921      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))
922      << " "
923      << profile.language_code()
924      << " "
925      << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER));
926}
927
928}  // namespace autofill
929