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