autofill_profile.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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
266  return *this;
267}
268
269void AutofillProfile::GetMatchingTypes(
270    const base::string16& text,
271    const std::string& app_locale,
272    ServerFieldTypeSet* matching_types) const {
273  FormGroupList info = FormGroups();
274  for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
275    (*it)->GetMatchingTypes(text, app_locale, matching_types);
276}
277
278base::string16 AutofillProfile::GetRawInfo(ServerFieldType type) const {
279  const FormGroup* form_group = FormGroupForType(AutofillType(type));
280  if (!form_group)
281    return base::string16();
282
283  return form_group->GetRawInfo(type);
284}
285
286void AutofillProfile::SetRawInfo(ServerFieldType type,
287                                 const base::string16& value) {
288  FormGroup* form_group = MutableFormGroupForType(AutofillType(type));
289  if (form_group)
290    form_group->SetRawInfo(type, value);
291}
292
293base::string16 AutofillProfile::GetInfo(const AutofillType& type,
294                                        const std::string& app_locale) const {
295  const FormGroup* form_group = FormGroupForType(type);
296  if (!form_group)
297    return base::string16();
298
299  return form_group->GetInfo(type, app_locale);
300}
301
302bool AutofillProfile::SetInfo(const AutofillType& type,
303                              const base::string16& value,
304                              const std::string& app_locale) {
305  FormGroup* form_group = MutableFormGroupForType(type);
306  if (!form_group)
307    return false;
308
309  base::string16 trimmed_value;
310  base::TrimWhitespace(value, base::TRIM_ALL, &trimmed_value);
311  return form_group->SetInfo(type, trimmed_value, app_locale);
312}
313
314base::string16 AutofillProfile::GetInfoForVariant(
315    const AutofillType& type,
316    size_t variant,
317    const std::string& app_locale) const {
318  std::vector<base::string16> values;
319  GetMultiInfo(type, app_locale, &values);
320
321  if (variant >= values.size()) {
322    // If the variant is unavailable, bail. This case is reachable, for
323    // example if Sync updates a profile during the filling process.
324    return base::string16();
325  }
326
327  return values[variant];
328}
329
330void AutofillProfile::SetRawMultiInfo(
331    ServerFieldType type,
332    const std::vector<base::string16>& values) {
333  switch (AutofillType(type).group()) {
334    case NAME:
335    case NAME_BILLING:
336      CopyValuesToItems(type, values, &name_, NameInfo());
337      break;
338    case EMAIL:
339      CopyValuesToItems(type, values, &email_, EmailInfo());
340      break;
341    case PHONE_HOME:
342    case PHONE_BILLING:
343      CopyValuesToItems(type,
344                        values,
345                        &phone_number_,
346                        PhoneNumber(this));
347      break;
348    default:
349      if (values.size() == 1) {
350        SetRawInfo(type, values[0]);
351      } else if (values.size() == 0) {
352        SetRawInfo(type, base::string16());
353      } else {
354        // Shouldn't attempt to set multiple values on single-valued field.
355        NOTREACHED();
356      }
357      break;
358  }
359}
360
361void AutofillProfile::GetRawMultiInfo(
362    ServerFieldType type,
363    std::vector<base::string16>* values) const {
364  GetMultiInfoImpl(AutofillType(type), std::string(), values);
365}
366
367void AutofillProfile::GetMultiInfo(const AutofillType& type,
368                                   const std::string& app_locale,
369                                   std::vector<base::string16>* values) const {
370  GetMultiInfoImpl(type, app_locale, values);
371}
372
373bool AutofillProfile::IsEmpty(const std::string& app_locale) const {
374  ServerFieldTypeSet types;
375  GetNonEmptyTypes(app_locale, &types);
376  return types.empty();
377}
378
379bool AutofillProfile::IsPresentButInvalid(ServerFieldType type) const {
380  std::string country = UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY));
381  base::string16 data = GetRawInfo(type);
382  if (data.empty())
383    return false;
384
385  switch (type) {
386    case ADDRESS_HOME_STATE:
387      return country == "US" && !autofill::IsValidState(data);
388
389    case ADDRESS_HOME_ZIP:
390      return country == "US" && !autofill::IsValidZip(data);
391
392    case PHONE_HOME_WHOLE_NUMBER:
393      return !i18n::PhoneObject(data, country).IsValidNumber();
394
395    case EMAIL_ADDRESS:
396      return !autofill::IsValidEmailAddress(data);
397
398    default:
399      NOTREACHED();
400      return false;
401  }
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::operator==(const AutofillProfile& profile) const {
451  return guid() == profile.guid() &&
452         origin() == profile.origin() &&
453         Compare(profile) == 0;
454}
455
456bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
457  return !operator==(profile);
458}
459
460const base::string16 AutofillProfile::PrimaryValue() const {
461  return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY);
462}
463
464bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile,
465                                 const std::string& app_locale) const {
466  ServerFieldTypeSet types;
467  GetNonEmptyTypes(app_locale, &types);
468
469  for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end();
470       ++it) {
471    if (*it == NAME_FULL || *it == ADDRESS_HOME_STREET_ADDRESS) {
472      // Ignore the compound "full name" field type.  We are only interested in
473      // comparing the constituent parts.  For example, if |this| has a middle
474      // name saved, but |profile| lacks one, |profile| could still be a subset
475      // of |this|.  Likewise, ignore the compound "street address" type, as we
476      // are only interested in matching line-by-line.
477      continue;
478    } else if (AutofillType(*it).group() == PHONE_HOME) {
479      // Phone numbers should be canonicalized prior to being compared.
480      if (*it != PHONE_HOME_WHOLE_NUMBER) {
481        continue;
482      } else if (!i18n::PhoneNumbersMatch(
483            GetRawInfo(*it),
484            profile.GetRawInfo(*it),
485            base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)),
486            app_locale)) {
487        return false;
488      }
489    } else if (StringToLowerASCII(GetRawInfo(*it)) !=
490                   StringToLowerASCII(profile.GetRawInfo(*it))) {
491      return false;
492    }
493  }
494
495  return true;
496}
497
498void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile,
499                                           const std::string& app_locale) {
500  // Verified profiles should never be overwritten with unverified data.
501  DCHECK(!IsVerified() || profile.IsVerified());
502  set_origin(profile.origin());
503
504  ServerFieldTypeSet field_types;
505  profile.GetNonEmptyTypes(app_locale, &field_types);
506
507  // Only transfer "full" types (e.g. full name) and not fragments (e.g.
508  // first name, last name).
509  CollapseCompoundFieldTypes(&field_types);
510
511  // TODO(isherman): Revisit this decision in the context of i18n and storing
512  // full addresses rather than storing 1-to-2 lines of an address.
513  // For addresses, do the opposite: transfer individual address lines, rather
514  // than full addresses.
515  field_types.erase(ADDRESS_HOME_STREET_ADDRESS);
516
517  for (ServerFieldTypeSet::const_iterator iter = field_types.begin();
518       iter != field_types.end(); ++iter) {
519    if (AutofillProfile::SupportsMultiValue(*iter)) {
520      std::vector<base::string16> new_values;
521      profile.GetRawMultiInfo(*iter, &new_values);
522      std::vector<base::string16> existing_values;
523      GetRawMultiInfo(*iter, &existing_values);
524
525      // GetMultiInfo always returns at least one element, even if the profile
526      // has no data stored for this field type.
527      if (existing_values.size() == 1 && existing_values.front().empty())
528        existing_values.clear();
529
530      FieldTypeGroup group = AutofillType(*iter).group();
531      for (std::vector<base::string16>::iterator value_iter =
532               new_values.begin();
533           value_iter != new_values.end(); ++value_iter) {
534        // Don't add duplicates.
535        if (group == PHONE_HOME) {
536          AddPhoneIfUnique(*value_iter, app_locale, &existing_values);
537        } else {
538          std::vector<base::string16>::const_iterator existing_iter =
539              std::find_if(
540                  existing_values.begin(), existing_values.end(),
541                  std::bind1st(CaseInsensitiveStringEquals(), *value_iter));
542          if (existing_iter == existing_values.end())
543            existing_values.insert(existing_values.end(), *value_iter);
544        }
545      }
546      SetRawMultiInfo(*iter, existing_values);
547    } else {
548      base::string16 new_value = profile.GetRawInfo(*iter);
549      if (StringToLowerASCII(GetRawInfo(*iter)) !=
550              StringToLowerASCII(new_value)) {
551        SetRawInfo(*iter, new_value);
552      }
553    }
554  }
555}
556
557// static
558bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
559  FieldTypeGroup group = AutofillType(type).group();
560  return group == NAME ||
561         group == NAME_BILLING ||
562         group == EMAIL ||
563         group == PHONE_HOME ||
564         group == PHONE_BILLING;
565}
566
567// static
568void AutofillProfile::CreateDifferentiatingLabels(
569    const std::vector<AutofillProfile*>& profiles,
570    std::vector<base::string16>* labels) {
571  const size_t kMinimalFieldsShown = 2;
572  CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
573                       labels);
574  DCHECK_EQ(profiles.size(), labels->size());
575}
576
577// static
578void AutofillProfile::CreateInferredLabels(
579    const std::vector<AutofillProfile*>& profiles,
580    const std::vector<ServerFieldType>* suggested_fields,
581    ServerFieldType excluded_field,
582    size_t minimal_fields_shown,
583    std::vector<base::string16>* labels) {
584  std::vector<ServerFieldType> fields_to_use;
585  GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
586                                     &fields_to_use);
587
588  // Construct the default label for each profile. Also construct a map that
589  // associates each label with the profiles that have this label. This map is
590  // then used to detect which labels need further differentiating fields.
591  std::map<base::string16, std::list<size_t> > labels_to_profiles;
592  for (size_t i = 0; i < profiles.size(); ++i) {
593    base::string16 label =
594        profiles[i]->ConstructInferredLabel(fields_to_use,
595                                            minimal_fields_shown);
596    labels_to_profiles[label].push_back(i);
597  }
598
599  labels->resize(profiles.size());
600  for (std::map<base::string16, std::list<size_t> >::const_iterator it =
601           labels_to_profiles.begin();
602       it != labels_to_profiles.end(); ++it) {
603    if (it->second.size() == 1) {
604      // This label is unique, so use it without any further ado.
605      base::string16 label = it->first;
606      size_t profile_index = it->second.front();
607      (*labels)[profile_index] = label;
608    } else {
609      // We have more than one profile with the same label, so add
610      // differentiating fields.
611      CreateInferredLabelsHelper(profiles, it->second, fields_to_use,
612                                 minimal_fields_shown, labels);
613    }
614  }
615}
616
617void AutofillProfile::GetSupportedTypes(
618    ServerFieldTypeSet* supported_types) const {
619  FormGroupList info = FormGroups();
620  for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
621    (*it)->GetSupportedTypes(supported_types);
622}
623
624void AutofillProfile::GetMultiInfoImpl(
625    const AutofillType& type,
626    const std::string& app_locale,
627    std::vector<base::string16>* values) const {
628  switch (type.group()) {
629    case NAME:
630    case NAME_BILLING:
631      CopyItemsToValues(type, name_, app_locale, values);
632      break;
633    case EMAIL:
634      CopyItemsToValues(type, email_, app_locale, values);
635      break;
636    case PHONE_HOME:
637    case PHONE_BILLING:
638      CopyItemsToValues(type, phone_number_, app_locale, values);
639      break;
640    default:
641      values->resize(1);
642      (*values)[0] = GetFormGroupInfo(*this, type, app_locale);
643  }
644}
645
646void AutofillProfile::AddPhoneIfUnique(
647    const base::string16& phone,
648    const std::string& app_locale,
649    std::vector<base::string16>* existing_phones) {
650  DCHECK(existing_phones);
651  // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
652  // "(800)356-9377" and "356-9377" are considered the same.
653  std::string country_code =
654      base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
655  if (std::find_if(existing_phones->begin(), existing_phones->end(),
656                   FindByPhone(phone, country_code, app_locale)) ==
657      existing_phones->end()) {
658    existing_phones->push_back(phone);
659  }
660}
661
662base::string16 AutofillProfile::ConstructInferredLabel(
663    const std::vector<ServerFieldType>& included_fields,
664    size_t num_fields_to_use) const {
665  const base::string16 separator =
666      l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
667
668  base::string16 label;
669  size_t num_fields_used = 0;
670  for (std::vector<ServerFieldType>::const_iterator it =
671           included_fields.begin();
672       it != included_fields.end() && num_fields_used < num_fields_to_use;
673       ++it) {
674    base::string16 field = GetRawInfo(*it);
675    if (field.empty())
676      continue;
677
678    if (!label.empty())
679      label.append(separator);
680
681    label.append(field);
682    ++num_fields_used;
683  }
684
685  // Flatten the label if need be.
686  const base::char16 kNewline[] = { '\n', 0 };
687  const base::string16 newline_separator =
688      l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR);
689  base::ReplaceChars(label, kNewline, newline_separator, &label);
690
691  return label;
692}
693
694// static
695void AutofillProfile::CreateInferredLabelsHelper(
696    const std::vector<AutofillProfile*>& profiles,
697    const std::list<size_t>& indices,
698    const std::vector<ServerFieldType>& fields,
699    size_t num_fields_to_include,
700    std::vector<base::string16>* labels) {
701  // For efficiency, we first construct a map of fields to their text values and
702  // each value's frequency.
703  std::map<ServerFieldType,
704           std::map<base::string16, size_t> > field_text_frequencies_by_field;
705  for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
706       field != fields.end(); ++field) {
707    std::map<base::string16, size_t>& field_text_frequencies =
708        field_text_frequencies_by_field[*field];
709
710    for (std::list<size_t>::const_iterator it = indices.begin();
711         it != indices.end(); ++it) {
712      const AutofillProfile* profile = profiles[*it];
713      base::string16 field_text = profile->GetRawInfo(*field);
714
715      // If this label is not already in the map, add it with frequency 0.
716      if (!field_text_frequencies.count(field_text))
717        field_text_frequencies[field_text] = 0;
718
719      // Now, increment the frequency for this label.
720      ++field_text_frequencies[field_text];
721    }
722  }
723
724  // Now comes the meat of the algorithm. For each profile, we scan the list of
725  // fields to use, looking for two things:
726  //  1. A (non-empty) field that differentiates the profile from all others
727  //  2. At least |num_fields_to_include| non-empty fields
728  // Before we've satisfied condition (2), we include all fields, even ones that
729  // are identical across all the profiles. Once we've satisfied condition (2),
730  // we only include fields that that have at last two distinct values.
731  for (std::list<size_t>::const_iterator it = indices.begin();
732       it != indices.end(); ++it) {
733    const AutofillProfile* profile = profiles[*it];
734
735    std::vector<ServerFieldType> label_fields;
736    bool found_differentiating_field = false;
737    for (std::vector<ServerFieldType>::const_iterator field = fields.begin();
738         field != fields.end(); ++field) {
739      // Skip over empty fields.
740      base::string16 field_text = profile->GetRawInfo(*field);
741      if (field_text.empty())
742        continue;
743
744      std::map<base::string16, size_t>& field_text_frequencies =
745          field_text_frequencies_by_field[*field];
746      found_differentiating_field |=
747          !field_text_frequencies.count(base::string16()) &&
748          (field_text_frequencies[field_text] == 1);
749
750      // Once we've found enough non-empty fields, skip over any remaining
751      // fields that are identical across all the profiles.
752      if (label_fields.size() >= num_fields_to_include &&
753          (field_text_frequencies.size() == 1))
754        continue;
755
756      label_fields.push_back(*field);
757
758      // If we've (1) found a differentiating field and (2) found at least
759      // |num_fields_to_include| non-empty fields, we're done!
760      if (found_differentiating_field &&
761          label_fields.size() >= num_fields_to_include)
762        break;
763    }
764
765    (*labels)[*it] =
766        profile->ConstructInferredLabel(label_fields, label_fields.size());
767  }
768}
769
770AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
771  FormGroupList v(5);
772  v[0] = &name_[0];
773  v[1] = &email_[0];
774  v[2] = &company_;
775  v[3] = &phone_number_[0];
776  v[4] = &address_;
777  return v;
778}
779
780const FormGroup* AutofillProfile::FormGroupForType(
781    const AutofillType& type) const {
782  return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
783}
784
785FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) {
786  switch (type.group()) {
787    case NAME:
788    case NAME_BILLING:
789      return &name_[0];
790
791    case EMAIL:
792      return &email_[0];
793
794    case COMPANY:
795      return &company_;
796
797    case PHONE_HOME:
798    case PHONE_BILLING:
799      return &phone_number_[0];
800
801    case ADDRESS_HOME:
802    case ADDRESS_BILLING:
803      return &address_;
804
805    case NO_GROUP:
806    case CREDIT_CARD:
807    case PASSWORD_FIELD:
808        return NULL;
809  }
810
811  NOTREACHED();
812  return NULL;
813}
814
815// So we can compare AutofillProfiles with EXPECT_EQ().
816std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
817  return os
818      << profile.guid()
819      << " "
820      << profile.origin()
821      << " "
822      << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
823      << " "
824      << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
825      << " "
826      << UTF16ToUTF8(MultiString(profile, NAME_LAST))
827      << " "
828      << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
829      << " "
830      << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))
831      << " "
832      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))
833      << " "
834      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))
835      << " "
836      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))
837      << " "
838      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))
839      << " "
840      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))
841      << " "
842      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))
843      << " "
844      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE))
845      << " "
846      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))
847      << " "
848      << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER));
849}
850
851}  // namespace autofill
852