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