- add sources.
[platform/framework/web/crosswalk.git] / src / components / autofill / core / browser / autofill_profile.cc
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
30 namespace autofill {
31 namespace {
32
33 // Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for
34 // first, middle, and last name field types.
35 ServerFieldType 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.
50 void 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.
110 const 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
123 base::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
131 template <class T>
132 void 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,
139                                       CollapseWhitespace(values[i], false));
140   }
141   // Must have at least one (possibly empty) element.
142   if (form_group_items->empty())
143     form_group_items->resize(1, prototype);
144 }
145
146 template <class T>
147 void CopyItemsToValues(const AutofillType& type,
148                        const std::vector<T>& form_group_items,
149                        const std::string& app_locale,
150                        std::vector<base::string16>* values) {
151   values->resize(form_group_items.size());
152   for (size_t i = 0; i < values->size(); ++i) {
153     (*values)[i] = GetFormGroupInfo(form_group_items[i], type, app_locale);
154   }
155 }
156
157 // Collapse compound field types to their "full" type.  I.e. First name
158 // collapses to full name, area code collapses to full phone, etc.
159 void CollapseCompoundFieldTypes(ServerFieldTypeSet* type_set) {
160   ServerFieldTypeSet collapsed_set;
161   for (ServerFieldTypeSet::iterator it = type_set->begin();
162        it != type_set->end(); ++it) {
163     switch (*it) {
164       case NAME_FIRST:
165       case NAME_MIDDLE:
166       case NAME_LAST:
167       case NAME_MIDDLE_INITIAL:
168       case NAME_FULL:
169       case NAME_SUFFIX:
170         collapsed_set.insert(NAME_FULL);
171         break;
172
173       case PHONE_HOME_NUMBER:
174       case PHONE_HOME_CITY_CODE:
175       case PHONE_HOME_COUNTRY_CODE:
176       case PHONE_HOME_CITY_AND_NUMBER:
177       case PHONE_HOME_WHOLE_NUMBER:
178         collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER);
179         break;
180
181       default:
182         collapsed_set.insert(*it);
183     }
184   }
185   std::swap(*type_set, collapsed_set);
186 }
187
188 class FindByPhone {
189  public:
190   FindByPhone(const base::string16& phone,
191               const std::string& country_code,
192               const std::string& app_locale)
193       : phone_(phone),
194         country_code_(country_code),
195         app_locale_(app_locale) {
196   }
197
198   bool operator()(const base::string16& phone) {
199     return i18n::PhoneNumbersMatch(phone, phone_, country_code_, app_locale_);
200   }
201
202   bool operator()(const base::string16* phone) {
203     return i18n::PhoneNumbersMatch(*phone, phone_, country_code_, app_locale_);
204   }
205
206  private:
207   base::string16 phone_;
208   std::string country_code_;
209   std::string app_locale_;
210 };
211
212 // Functor used to check for case-insensitive equality of two strings.
213 struct CaseInsensitiveStringEquals
214     : public std::binary_function<base::string16, base::string16, bool>
215 {
216   bool operator()(const base::string16& x, const base::string16& y) const {
217     return
218         x.size() == y.size() && StringToLowerASCII(x) == StringToLowerASCII(y);
219   }
220 };
221
222 }  // namespace
223
224 AutofillProfile::AutofillProfile(const std::string& guid,
225                                  const std::string& origin)
226     : AutofillDataModel(guid, origin),
227       name_(1),
228       email_(1),
229       phone_number_(1, PhoneNumber(this)) {
230 }
231
232 AutofillProfile::AutofillProfile()
233     : AutofillDataModel(base::GenerateGUID(), std::string()),
234       name_(1),
235       email_(1),
236       phone_number_(1, PhoneNumber(this)) {
237 }
238
239 AutofillProfile::AutofillProfile(const AutofillProfile& profile)
240     : AutofillDataModel(std::string(), std::string()) {
241   operator=(profile);
242 }
243
244 AutofillProfile::~AutofillProfile() {
245 }
246
247 AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
248   if (this == &profile)
249     return *this;
250
251   set_guid(profile.guid());
252   set_origin(profile.origin());
253
254   label_ = profile.label_;
255   name_ = profile.name_;
256   email_ = profile.email_;
257   company_ = profile.company_;
258   phone_number_ = profile.phone_number_;
259
260   for (size_t i = 0; i < phone_number_.size(); ++i)
261     phone_number_[i].set_profile(this);
262
263   address_ = profile.address_;
264
265   return *this;
266 }
267
268 void AutofillProfile::GetMatchingTypes(
269     const base::string16& text,
270     const std::string& app_locale,
271     ServerFieldTypeSet* matching_types) const {
272   FormGroupList info = FormGroups();
273   for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
274     (*it)->GetMatchingTypes(text, app_locale, matching_types);
275 }
276
277 base::string16 AutofillProfile::GetRawInfo(ServerFieldType type) const {
278   const FormGroup* form_group = FormGroupForType(AutofillType(type));
279   if (!form_group)
280     return base::string16();
281
282   return form_group->GetRawInfo(type);
283 }
284
285 void AutofillProfile::SetRawInfo(ServerFieldType type,
286                                  const base::string16& value) {
287   FormGroup* form_group = MutableFormGroupForType(AutofillType(type));
288   if (form_group)
289     form_group->SetRawInfo(type, CollapseWhitespace(value, false));
290 }
291
292 base::string16 AutofillProfile::GetInfo(const AutofillType& type,
293                                         const std::string& app_locale) const {
294   const FormGroup* form_group = FormGroupForType(type);
295   if (!form_group)
296     return base::string16();
297
298   return form_group->GetInfo(type, app_locale);
299 }
300
301 bool AutofillProfile::SetInfo(const AutofillType& type,
302                               const base::string16& value,
303                               const std::string& app_locale) {
304   FormGroup* form_group = MutableFormGroupForType(type);
305   if (!form_group)
306     return false;
307
308   return
309       form_group->SetInfo(type, CollapseWhitespace(value, false), app_locale);
310 }
311
312 base::string16 AutofillProfile::GetInfoForVariant(
313     const AutofillType& type,
314     size_t variant,
315     const std::string& app_locale) const {
316   std::vector<base::string16> values;
317   GetMultiInfo(type, app_locale, &values);
318
319   if (variant >= values.size()) {
320     // If the variant is unavailable, bail. This case is reachable, for
321     // example if Sync updates a profile during the filling process.
322     return base::string16();
323   }
324
325   return values[variant];
326 }
327
328 void AutofillProfile::SetRawMultiInfo(
329     ServerFieldType type,
330     const std::vector<base::string16>& values) {
331   switch (AutofillType(type).group()) {
332     case NAME:
333     case NAME_BILLING:
334       CopyValuesToItems(type, values, &name_, NameInfo());
335       break;
336     case EMAIL:
337       CopyValuesToItems(type, values, &email_, EmailInfo());
338       break;
339     case PHONE_HOME:
340     case PHONE_BILLING:
341       CopyValuesToItems(type,
342                         values,
343                         &phone_number_,
344                         PhoneNumber(this));
345       break;
346     default:
347       if (values.size() == 1) {
348         SetRawInfo(type, values[0]);
349       } else if (values.size() == 0) {
350         SetRawInfo(type, base::string16());
351       } else {
352         // Shouldn't attempt to set multiple values on single-valued field.
353         NOTREACHED();
354       }
355       break;
356   }
357 }
358
359 void AutofillProfile::GetRawMultiInfo(
360     ServerFieldType type,
361     std::vector<base::string16>* values) const {
362   GetMultiInfoImpl(AutofillType(type), std::string(), values);
363 }
364
365 void AutofillProfile::GetMultiInfo(const AutofillType& type,
366                                    const std::string& app_locale,
367                                    std::vector<base::string16>* values) const {
368   GetMultiInfoImpl(type, app_locale, values);
369 }
370
371 const base::string16 AutofillProfile::Label() const {
372   return label_;
373 }
374
375 bool AutofillProfile::IsEmpty(const std::string& app_locale) const {
376   ServerFieldTypeSet types;
377   GetNonEmptyTypes(app_locale, &types);
378   return types.empty();
379 }
380
381 bool AutofillProfile::IsPresentButInvalid(ServerFieldType type) const {
382   std::string country = UTF16ToUTF8(GetRawInfo(ADDRESS_HOME_COUNTRY));
383   base::string16 data = GetRawInfo(type);
384   if (data.empty())
385     return false;
386
387   switch (type) {
388     case ADDRESS_HOME_STATE:
389       return country == "US" && !autofill::IsValidState(data);
390
391     case ADDRESS_HOME_ZIP:
392       return country == "US" && !autofill::IsValidZip(data);
393
394     case PHONE_HOME_WHOLE_NUMBER:
395       return !i18n::PhoneObject(data, country).IsValidNumber();
396
397     case EMAIL_ADDRESS:
398       return !autofill::IsValidEmailAddress(data);
399
400     default:
401       NOTREACHED();
402       return false;
403   }
404 }
405
406
407 int AutofillProfile::Compare(const AutofillProfile& profile) const {
408   const ServerFieldType single_value_types[] = { COMPANY_NAME,
409                                                  ADDRESS_HOME_LINE1,
410                                                  ADDRESS_HOME_LINE2,
411                                                  ADDRESS_HOME_CITY,
412                                                  ADDRESS_HOME_STATE,
413                                                  ADDRESS_HOME_ZIP,
414                                                  ADDRESS_HOME_COUNTRY };
415
416   for (size_t i = 0; i < arraysize(single_value_types); ++i) {
417     int comparison = GetRawInfo(single_value_types[i]).compare(
418         profile.GetRawInfo(single_value_types[i]));
419     if (comparison != 0)
420       return comparison;
421   }
422
423   const ServerFieldType multi_value_types[] = { NAME_FIRST,
424                                                 NAME_MIDDLE,
425                                                 NAME_LAST,
426                                                 EMAIL_ADDRESS,
427                                                 PHONE_HOME_WHOLE_NUMBER };
428
429   for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
430     std::vector<base::string16> values_a;
431     std::vector<base::string16> values_b;
432     GetRawMultiInfo(multi_value_types[i], &values_a);
433     profile.GetRawMultiInfo(multi_value_types[i], &values_b);
434     if (values_a.size() < values_b.size())
435       return -1;
436     if (values_a.size() > values_b.size())
437       return 1;
438     for (size_t j = 0; j < values_a.size(); ++j) {
439       int comparison = values_a[j].compare(values_b[j]);
440       if (comparison != 0)
441         return comparison;
442     }
443   }
444
445   return 0;
446 }
447
448 bool AutofillProfile::operator==(const AutofillProfile& profile) const {
449   return guid() == profile.guid() &&
450          origin() == profile.origin() &&
451          Compare(profile) == 0;
452 }
453
454 bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
455   return !operator==(profile);
456 }
457
458 const base::string16 AutofillProfile::PrimaryValue() const {
459   return GetRawInfo(ADDRESS_HOME_LINE1) + GetRawInfo(ADDRESS_HOME_CITY);
460 }
461
462 bool AutofillProfile::IsSubsetOf(const AutofillProfile& profile,
463                                  const std::string& app_locale) const {
464   ServerFieldTypeSet types;
465   GetNonEmptyTypes(app_locale, &types);
466
467   for (ServerFieldTypeSet::const_iterator it = types.begin(); it != types.end();
468        ++it) {
469     if (*it == NAME_FULL) {
470       // Ignore the compound "full name" field type.  We are only interested in
471       // comparing the constituent parts.  For example, if |this| has a middle
472       // name saved, but |profile| lacks one, |profile| could still be a subset
473       // of |this|.
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
495 void 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   for (ServerFieldTypeSet::const_iterator iter = field_types.begin();
509        iter != field_types.end(); ++iter) {
510     if (AutofillProfile::SupportsMultiValue(*iter)) {
511       std::vector<base::string16> new_values;
512       profile.GetRawMultiInfo(*iter, &new_values);
513       std::vector<base::string16> existing_values;
514       GetRawMultiInfo(*iter, &existing_values);
515
516       // GetMultiInfo always returns at least one element, even if the profile
517       // has no data stored for this field type.
518       if (existing_values.size() == 1 && existing_values.front().empty())
519         existing_values.clear();
520
521       FieldTypeGroup group = AutofillType(*iter).group();
522       for (std::vector<base::string16>::iterator value_iter =
523                new_values.begin();
524            value_iter != new_values.end(); ++value_iter) {
525         // Don't add duplicates.
526         if (group == PHONE_HOME) {
527           AddPhoneIfUnique(*value_iter, app_locale, &existing_values);
528         } else {
529           std::vector<base::string16>::const_iterator existing_iter =
530               std::find_if(
531                   existing_values.begin(), existing_values.end(),
532                   std::bind1st(CaseInsensitiveStringEquals(), *value_iter));
533           if (existing_iter == existing_values.end())
534             existing_values.insert(existing_values.end(), *value_iter);
535         }
536       }
537       SetRawMultiInfo(*iter, existing_values);
538     } else {
539       base::string16 new_value = profile.GetRawInfo(*iter);
540       if (StringToLowerASCII(GetRawInfo(*iter)) !=
541               StringToLowerASCII(new_value)) {
542         SetRawInfo(*iter, new_value);
543       }
544     }
545   }
546 }
547
548 // static
549 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
550   FieldTypeGroup group = AutofillType(type).group();
551   return group == NAME ||
552          group == NAME_BILLING ||
553          group == EMAIL ||
554          group == PHONE_HOME ||
555          group == PHONE_BILLING;
556 }
557
558 // static
559 bool AutofillProfile::AdjustInferredLabels(
560     std::vector<AutofillProfile*>* profiles) {
561   const size_t kMinimalFieldsShown = 2;
562
563   std::vector<base::string16> created_labels;
564   CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
565                        &created_labels);
566   DCHECK_EQ(profiles->size(), created_labels.size());
567
568   bool updated_labels = false;
569   for (size_t i = 0; i < profiles->size(); ++i) {
570     if ((*profiles)[i]->Label() != created_labels[i]) {
571       updated_labels = true;
572       (*profiles)[i]->label_ = created_labels[i];
573     }
574   }
575   return updated_labels;
576 }
577
578 // static
579 void AutofillProfile::CreateInferredLabels(
580     const std::vector<AutofillProfile*>* profiles,
581     const std::vector<ServerFieldType>* suggested_fields,
582     ServerFieldType excluded_field,
583     size_t minimal_fields_shown,
584     std::vector<base::string16>* created_labels) {
585   DCHECK(profiles);
586   DCHECK(created_labels);
587
588   std::vector<ServerFieldType> fields_to_use;
589   GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
590                                      &fields_to_use);
591
592   // Construct the default label for each profile. Also construct a map that
593   // associates each label with the profiles that have this label. This map is
594   // then used to detect which labels need further differentiating fields.
595   std::map<base::string16, std::list<size_t> > labels;
596   for (size_t i = 0; i < profiles->size(); ++i) {
597     base::string16 label =
598         (*profiles)[i]->ConstructInferredLabel(fields_to_use,
599                                                minimal_fields_shown);
600     labels[label].push_back(i);
601   }
602
603   created_labels->resize(profiles->size());
604   for (std::map<base::string16, std::list<size_t> >::const_iterator it =
605            labels.begin();
606        it != labels.end(); ++it) {
607     if (it->second.size() == 1) {
608       // This label is unique, so use it without any further ado.
609       base::string16 label = it->first;
610       size_t profile_index = it->second.front();
611       (*created_labels)[profile_index] = label;
612     } else {
613       // We have more than one profile with the same label, so add
614       // differentiating fields.
615       CreateDifferentiatingLabels(*profiles, it->second, fields_to_use,
616                                   minimal_fields_shown, created_labels);
617     }
618   }
619 }
620
621 void AutofillProfile::GetSupportedTypes(
622     ServerFieldTypeSet* supported_types) const {
623   FormGroupList info = FormGroups();
624   for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
625     (*it)->GetSupportedTypes(supported_types);
626 }
627
628 void AutofillProfile::GetMultiInfoImpl(
629     const AutofillType& type,
630     const std::string& app_locale,
631     std::vector<base::string16>* values) const {
632   switch (type.group()) {
633     case NAME:
634     case NAME_BILLING:
635       CopyItemsToValues(type, name_, app_locale, values);
636       break;
637     case EMAIL:
638       CopyItemsToValues(type, email_, app_locale, values);
639       break;
640     case PHONE_HOME:
641     case PHONE_BILLING:
642       CopyItemsToValues(type, phone_number_, app_locale, values);
643       break;
644     default:
645       values->resize(1);
646       (*values)[0] = GetFormGroupInfo(*this, type, app_locale);
647   }
648 }
649
650 void AutofillProfile::AddPhoneIfUnique(
651     const base::string16& phone,
652     const std::string& app_locale,
653     std::vector<base::string16>* existing_phones) {
654   DCHECK(existing_phones);
655   // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
656   // "(800)356-9377" and "356-9377" are considered the same.
657   std::string country_code = UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
658   if (std::find_if(existing_phones->begin(), existing_phones->end(),
659                    FindByPhone(phone, country_code, app_locale)) ==
660       existing_phones->end()) {
661     existing_phones->push_back(phone);
662   }
663 }
664
665 base::string16 AutofillProfile::ConstructInferredLabel(
666     const std::vector<ServerFieldType>& included_fields,
667     size_t num_fields_to_use) const {
668   const base::string16 separator =
669       l10n_util::GetStringUTF16(IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR);
670
671   base::string16 label;
672   size_t num_fields_used = 0;
673   for (std::vector<ServerFieldType>::const_iterator it =
674            included_fields.begin();
675        it != included_fields.end() && num_fields_used < num_fields_to_use;
676        ++it) {
677     base::string16 field = GetRawInfo(*it);
678     if (field.empty())
679       continue;
680
681     if (!label.empty())
682       label.append(separator);
683
684     label.append(field);
685     ++num_fields_used;
686   }
687   return label;
688 }
689
690 // static
691 void AutofillProfile::CreateDifferentiatingLabels(
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>* created_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     (*created_labels)[*it] =
762         profile->ConstructInferredLabel(label_fields,
763                                         label_fields.size());
764   }
765 }
766
767 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
768   FormGroupList v(5);
769   v[0] = &name_[0];
770   v[1] = &email_[0];
771   v[2] = &company_;
772   v[3] = &phone_number_[0];
773   v[4] = &address_;
774   return v;
775 }
776
777 const FormGroup* AutofillProfile::FormGroupForType(
778     const AutofillType& type) const {
779   return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
780 }
781
782 FormGroup* AutofillProfile::MutableFormGroupForType(const AutofillType& type) {
783   switch (type.group()) {
784     case NAME:
785     case NAME_BILLING:
786       return &name_[0];
787
788     case EMAIL:
789       return &email_[0];
790
791     case COMPANY:
792       return &company_;
793
794     case PHONE_HOME:
795     case PHONE_BILLING:
796       return &phone_number_[0];
797
798     case ADDRESS_HOME:
799     case ADDRESS_BILLING:
800       return &address_;
801
802     case NO_GROUP:
803     case CREDIT_CARD:
804     case PASSWORD_FIELD:
805         return NULL;
806   }
807
808   NOTREACHED();
809   return NULL;
810 }
811
812 // So we can compare AutofillProfiles with EXPECT_EQ().
813 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
814   return os
815       << UTF16ToUTF8(profile.Label())
816       << " "
817       << profile.guid()
818       << " "
819       << profile.origin()
820       << " "
821       << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
822       << " "
823       << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
824       << " "
825       << UTF16ToUTF8(MultiString(profile, NAME_LAST))
826       << " "
827       << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
828       << " "
829       << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))
830       << " "
831       << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))
832       << " "
833       << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))
834       << " "
835       << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))
836       << " "
837       << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))
838       << " "
839       << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))
840       << " "
841       << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))
842       << " "
843       << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER));
844 }
845
846 }  // namespace autofill