// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/autofill/personal_data_manager.h"

#include <algorithm>
#include <iterator>

#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_field.h"
#include "chrome/browser/autofill/form_structure.h"
#include "chrome/browser/autofill/phone_number.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"

namespace {

// The minimum number of fields that must contain user data and have known types
// before AutoFill will attempt to import the data into a profile or a credit
// card.
const int kMinProfileImportSize = 3;
const int kMinCreditCardImportSize = 2;

template<typename T>
class FormGroupGUIDMatchesFunctor {
 public:
  explicit FormGroupGUIDMatchesFunctor(const std::string& guid) : guid_(guid) {}

  bool operator()(const T& form_group) {
    return form_group.guid() == guid_;
  }

 private:
  std::string guid_;
};

template<typename T>
class FormGroupGUIDMatchesFunctor<T *> {
 public:
  explicit FormGroupGUIDMatchesFunctor(const std::string& guid) : guid_(guid) {}

  bool operator()(const T* form_group) {
    return form_group->guid() == guid_;
  }

 private:
  std::string guid_;
};

template<typename T>
class DereferenceFunctor {
 public:
  template<typename T_Iterator>
  const T& operator()(const T_Iterator& iterator) {
    return *iterator;
  }
};

template<typename T>
T* address_of(T& v) {
  return &v;
}

template<typename T, typename C>
bool FindByGUID(const C& container, const std::string& guid) {
  return std::find_if(container.begin(), container.end(),
                      FormGroupGUIDMatchesFunctor<T>(guid)) != container.end();
}

}  // namespace

PersonalDataManager::~PersonalDataManager() {
  CancelPendingQuery(&pending_profiles_query_);
  CancelPendingQuery(&pending_creditcards_query_);
}

void PersonalDataManager::OnWebDataServiceRequestDone(
    WebDataService::Handle h,
    const WDTypedResult* result) {
  // Error from the web database.
  if (!result)
    return;

  DCHECK(pending_profiles_query_ || pending_creditcards_query_);
  DCHECK(result->GetType() == AUTOFILL_PROFILES_RESULT ||
         result->GetType() == AUTOFILL_CREDITCARDS_RESULT);

  switch (result->GetType()) {
    case AUTOFILL_PROFILES_RESULT:
      ReceiveLoadedProfiles(h, result);
      break;
    case AUTOFILL_CREDITCARDS_RESULT:
      ReceiveLoadedCreditCards(h, result);
      break;
    default:
      NOTREACHED();
  }

  // If both requests have responded, then all personal data is loaded.
  if (pending_profiles_query_ == 0 && pending_creditcards_query_ == 0) {
    is_data_loaded_ = true;
    std::vector<AutoFillProfile*> profile_pointers(web_profiles_.size());
    std::copy(web_profiles_.begin(), web_profiles_.end(),
              profile_pointers.begin());
    AutoFillProfile::AdjustInferredLabels(&profile_pointers);
    FOR_EACH_OBSERVER(Observer, observers_, OnPersonalDataLoaded());
  }
}

/////////////////////////////////////////////////////////////////////////////
// PersonalDataManager,
// views::ButtonListener implementations
void PersonalDataManager::OnAutoFillDialogApply(
    std::vector<AutoFillProfile>* profiles,
    std::vector<CreditCard>* credit_cards) {
  // |profiles| may be NULL.
  // |credit_cards| may be NULL.
  if (profiles) {
    CancelPendingQuery(&pending_profiles_query_);
    SetProfiles(profiles);
  }
  if (credit_cards) {
    CancelPendingQuery(&pending_creditcards_query_);
    SetCreditCards(credit_cards);
  }
}

void PersonalDataManager::SetObserver(PersonalDataManager::Observer* observer) {
  // TODO: RemoveObserver is for compatibility with old code, it should be
  // nuked.
  observers_.RemoveObserver(observer);
  observers_.AddObserver(observer);
}

void PersonalDataManager::RemoveObserver(
    PersonalDataManager::Observer* observer) {
  observers_.RemoveObserver(observer);
}

bool PersonalDataManager::ImportFormData(
    const std::vector<FormStructure*>& form_structures) {
  // Parse the form and construct a profile based on the information that is
  // possible to import.
  int importable_fields = 0;
  int importable_credit_card_fields = 0;
  imported_profile_.reset(new AutoFillProfile);
  // TODO(jhawkins): Use a hash of the CC# instead of a list of unique IDs?
  imported_credit_card_.reset(new CreditCard);

  std::vector<FormStructure*>::const_iterator iter;
  for (iter = form_structures.begin(); iter != form_structures.end(); ++iter) {
    const FormStructure* form = *iter;
    for (size_t i = 0; i < form->field_count(); ++i) {
      const AutoFillField* field = form->field(i);
      string16 value = CollapseWhitespace(field->value(), false);

      // If we don't know the type of the field, or the user hasn't entered any
      // information into the field, then skip it.
      if (!field->IsFieldFillable() || value.empty())
        continue;

      AutoFillType field_type(field->type());
      FieldTypeGroup group(field_type.group());

      if (group == AutoFillType::CREDIT_CARD) {
        // If the user has a password set, we have no way of setting credit
        // card numbers.
        if (!HasPassword()) {
          imported_credit_card_->SetInfo(AutoFillType(field_type.field_type()),
                                         value);
          ++importable_credit_card_fields;
        }
      } else {
        // In the case of a phone number, if the whole phone number was entered
        // into a single field, then parse it and set the sub components.
        if (field_type.subgroup() == AutoFillType::PHONE_WHOLE_NUMBER) {
          string16 number;
          string16 city_code;
          string16 country_code;
          PhoneNumber::ParsePhoneNumber(value,
                                        &number,
                                        &city_code,
                                        &country_code);
          if (number.empty())
            continue;

          if (group == AutoFillType::PHONE_HOME) {
            imported_profile_->SetInfo(AutoFillType(PHONE_HOME_COUNTRY_CODE),
                                       country_code);
            imported_profile_->SetInfo(AutoFillType(PHONE_HOME_CITY_CODE),
                                       city_code);
            imported_profile_->SetInfo(AutoFillType(PHONE_HOME_NUMBER), number);
          } else if (group == AutoFillType::PHONE_FAX) {
            imported_profile_->SetInfo(AutoFillType(PHONE_FAX_COUNTRY_CODE),
                                       country_code);
            imported_profile_->SetInfo(AutoFillType(PHONE_FAX_CITY_CODE),
                                       city_code);
            imported_profile_->SetInfo(AutoFillType(PHONE_FAX_NUMBER), number);
          }

          continue;
        }

        // Phone and fax numbers can be split across multiple fields, so we
        // might have already stored the prefix, and now be at the suffix.
        // If so, combine them to form the full number.
        if (group == AutoFillType::PHONE_HOME ||
            group == AutoFillType::PHONE_FAX) {
          AutoFillType number_type(PHONE_HOME_NUMBER);
          if (group == AutoFillType::PHONE_FAX)
            number_type = AutoFillType(PHONE_FAX_NUMBER);

          string16 stored_number = imported_profile_->GetFieldText(number_type);
          if (stored_number.size() ==
                  static_cast<size_t>(PhoneNumber::kPrefixLength) &&
              value.size() == static_cast<size_t>(PhoneNumber::kSuffixLength)) {
            value = stored_number + value;
          }
        }

        imported_profile_->SetInfo(AutoFillType(field_type.field_type()),
                                   value);
        ++importable_fields;
      }
    }
  }

  // If the user did not enter enough information on the page then don't bother
  // importing the data.
  if (importable_fields < kMinProfileImportSize)
    imported_profile_.reset();
  if (importable_credit_card_fields < kMinCreditCardImportSize)
    imported_credit_card_.reset();

  if (imported_credit_card_.get()) {
    if (!CreditCard::IsCreditCardNumber(imported_credit_card_->GetFieldText(
          AutoFillType(CREDIT_CARD_NUMBER)))) {
      imported_credit_card_.reset();
    }
  }

  // Don't import if we already have this info.
  if (imported_credit_card_.get()) {
    for (std::vector<CreditCard*>::const_iterator iter = credit_cards_.begin();
         iter != credit_cards_.end();
         ++iter) {
      if (imported_credit_card_->IsSubsetOf(**iter)) {
        imported_credit_card_.reset();
        break;
      }
    }
  }

  if (imported_profile_.get()) {
    // We always save imported profiles.
    SaveImportedProfile();
  }

  return imported_profile_.get() || imported_credit_card_.get();
}

void PersonalDataManager::GetImportedFormData(AutoFillProfile** profile,
                                              CreditCard** credit_card) {
  DCHECK(profile);
  DCHECK(credit_card);

  *profile = imported_profile_.get();
  *credit_card = imported_credit_card_.get();
}

void PersonalDataManager::SetProfiles(std::vector<AutoFillProfile>* profiles) {
  if (profile_->IsOffTheRecord())
    return;

  // Remove empty profiles from input.
  profiles->erase(
      std::remove_if(profiles->begin(), profiles->end(),
                     std::mem_fun_ref(&AutoFillProfile::IsEmpty)),
      profiles->end());

  // Ensure that profile labels are up to date.  Currently, sync relies on
  // labels to identify a profile.
  // TODO(dhollowa): We need to deprecate labels and update the way sync
  // identifies profiles.
  std::vector<AutoFillProfile*> profile_pointers(profiles->size());
  std::transform(profiles->begin(), profiles->end(), profile_pointers.begin(),
      address_of<AutoFillProfile>);
  AutoFillProfile::AdjustInferredLabels(&profile_pointers);

  WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
  if (!wds)
    return;

  // Any profiles that are not in the new profile list should be removed from
  // the web database.
  for (std::vector<AutoFillProfile*>::const_iterator iter =
           web_profiles_.begin();
       iter != web_profiles_.end(); ++iter) {
    if (!FindByGUID<AutoFillProfile>(*profiles, (*iter)->guid()))
      wds->RemoveAutoFillProfileGUID((*iter)->guid());
  }

  // Update the web database with the existing profiles.
  for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
       iter != profiles->end(); ++iter) {
    if (FindByGUID<AutoFillProfile*>(web_profiles_, iter->guid()))
      wds->UpdateAutoFillProfileGUID(*iter);
  }

  // Add the new profiles to the web database.
  for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
       iter != profiles->end(); ++iter) {
    if (!FindByGUID<AutoFillProfile*>(web_profiles_, iter->guid()))
      wds->AddAutoFillProfileGUID(*iter);
  }

  // Copy in the new profiles.
  web_profiles_.reset();
  for (std::vector<AutoFillProfile>::iterator iter = profiles->begin();
       iter != profiles->end(); ++iter) {
    web_profiles_.push_back(new AutoFillProfile(*iter));
  }

  // Read our writes to ensure consistency with the database.
  Refresh();

  FOR_EACH_OBSERVER(Observer, observers_, OnPersonalDataChanged());
}

void PersonalDataManager::SetCreditCards(
    std::vector<CreditCard>* credit_cards) {
  if (profile_->IsOffTheRecord())
    return;

  // Remove empty credit cards from input.
  credit_cards->erase(
      std::remove_if(
          credit_cards->begin(), credit_cards->end(),
          std::mem_fun_ref(&CreditCard::IsEmpty)),
      credit_cards->end());

  SetUniqueCreditCardLabels(credit_cards);

  WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
  if (!wds)
    return;

  // Any credit cards that are not in the new credit card list should be
  // removed.
  for (std::vector<CreditCard*>::const_iterator iter = credit_cards_.begin();
       iter != credit_cards_.end(); ++iter) {
    if (!FindByGUID<CreditCard>(*credit_cards, (*iter)->guid()))
      wds->RemoveCreditCardGUID((*iter)->guid());
  }

  // Update the web database with the existing credit cards.
  for (std::vector<CreditCard>::iterator iter = credit_cards->begin();
       iter != credit_cards->end(); ++iter) {
    if (FindByGUID<CreditCard*>(credit_cards_, iter->guid()))
      wds->UpdateCreditCardGUID(*iter);
  }

  // Add the new credit cards to the web database.
  for (std::vector<CreditCard>::iterator iter = credit_cards->begin();
       iter != credit_cards->end(); ++iter) {
    if (!FindByGUID<CreditCard*>(credit_cards_, iter->guid()))
      wds->AddCreditCardGUID(*iter);
  }

  // Copy in the new credit cards.
  credit_cards_.reset();
  for (std::vector<CreditCard>::iterator iter = credit_cards->begin();
       iter != credit_cards->end(); ++iter) {
    credit_cards_.push_back(new CreditCard(*iter));
  }

  // Read our writes to ensure consistency with the database.
  Refresh();

  FOR_EACH_OBSERVER(Observer, observers_, OnPersonalDataChanged());
}

// TODO(jhawkins): Refactor SetProfiles so this isn't so hacky.
void PersonalDataManager::AddProfile(const AutoFillProfile& profile) {
  // Don't save a web profile if the data in the profile is a subset of an
  // auxiliary profile.
  for (std::vector<AutoFillProfile*>::const_iterator iter =
           auxiliary_profiles_.begin();
       iter != auxiliary_profiles_.end(); ++iter) {
    if (profile.IsSubsetOf(**iter))
      return;
  }

  // Set to true if |profile| is merged into the profile list.
  bool merged = false;

  // First preference is to add missing values to an existing profile.
  // Only merge with the first match.
  std::vector<AutoFillProfile> profiles;
  for (std::vector<AutoFillProfile*>::const_iterator iter =
           web_profiles_.begin();
       iter != web_profiles_.end(); ++iter) {
    if (!merged) {
      if (profile.IsSubsetOf(**iter)) {
        // In this case, the existing profile already contains all of the data
        // in |profile|, so consider the profiles already merged.
        merged = true;
      } else if ((*iter)->IntersectionOfTypesHasEqualValues(profile)) {
        // |profile| contains all of the data in this profile, plus more.
        merged = true;
        (*iter)->MergeWith(profile);
      }
    }
    profiles.push_back(**iter);
  }

  // The second preference, if not merged above, is to alter non-primary values
  // where the primary values match.
  // Again, only merge with the first match.
  if (!merged) {
    profiles.clear();
    for (std::vector<AutoFillProfile*>::const_iterator iter =
             web_profiles_.begin();
         iter != web_profiles_.end(); ++iter) {
      if (!merged) {
        if (!profile.PrimaryValue().empty() &&
            (*iter)->PrimaryValue() == profile.PrimaryValue()) {
          merged = true;
          (*iter)->OverwriteWith(profile);
        }
      }
      profiles.push_back(**iter);
    }
  }

  // Finally, if the new profile was not merged with an existing profile then
  // add the new profile to the list.
  if (!merged)
    profiles.push_back(profile);

  SetProfiles(&profiles);
}

void PersonalDataManager::UpdateProfile(const AutoFillProfile& profile) {
  WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
  if (!wds)
    return;

  // Update the cached profile.
  for (std::vector<AutoFillProfile*>::iterator iter = web_profiles_->begin();
       iter != web_profiles_->end(); ++iter) {
    if ((*iter)->guid() == profile.guid()) {
      delete *iter;
      *iter = new AutoFillProfile(profile);
      break;
    }
  }

  // Ensure that profile labels are up to date.
  AutoFillProfile::AdjustInferredLabels(&web_profiles_.get());

  wds->UpdateAutoFillProfileGUID(profile);
  FOR_EACH_OBSERVER(Observer, observers_, OnPersonalDataChanged());
}

void PersonalDataManager::RemoveProfile(const std::string& guid) {
  // TODO(jhawkins): Refactor SetProfiles so this isn't so hacky.
  std::vector<AutoFillProfile> profiles(web_profiles_.size());
  std::transform(web_profiles_.begin(), web_profiles_.end(),
                 profiles.begin(),
                 DereferenceFunctor<AutoFillProfile>());

  // Remove the profile that matches |guid|.
  profiles.erase(
      std::remove_if(profiles.begin(), profiles.end(),
                     FormGroupGUIDMatchesFunctor<AutoFillProfile>(guid)),
      profiles.end());

  SetProfiles(&profiles);
}

AutoFillProfile* PersonalDataManager::GetProfileByGUID(
    const std::string& guid) {
  for (std::vector<AutoFillProfile*>::iterator iter = web_profiles_->begin();
       iter != web_profiles_->end(); ++iter) {
    if ((*iter)->guid() == guid)
      return *iter;
  }
  return NULL;
}

// TODO(jhawkins): Refactor SetCreditCards so this isn't so hacky.
void PersonalDataManager::AddCreditCard(const CreditCard& credit_card) {
  std::vector<CreditCard> credit_cards(credit_cards_.size());
  std::transform(credit_cards_.begin(), credit_cards_.end(),
                 credit_cards.begin(),
                 DereferenceFunctor<CreditCard>());

  credit_cards.push_back(credit_card);
  SetCreditCards(&credit_cards);
}

void PersonalDataManager::UpdateCreditCard(const CreditCard& credit_card) {
  WebDataService* wds = profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
  if (!wds)
    return;

  // Update the cached credit card.
  for (std::vector<CreditCard*>::iterator iter = credit_cards_->begin();
       iter != credit_cards_->end(); ++iter) {
    if ((*iter)->guid() == credit_card.guid()) {
      delete *iter;
      *iter = new CreditCard(credit_card);
      break;
    }
  }

  wds->UpdateCreditCardGUID(credit_card);
  FOR_EACH_OBSERVER(Observer, observers_, OnPersonalDataChanged());
}

void PersonalDataManager::RemoveCreditCard(const std::string& guid) {
  // TODO(jhawkins): Refactor SetCreditCards so this isn't so hacky.
  std::vector<CreditCard> credit_cards(credit_cards_.size());
  std::transform(credit_cards_.begin(), credit_cards_.end(),
                 credit_cards.begin(),
                 DereferenceFunctor<CreditCard>());

  // Remove the credit card that matches |guid|.
  credit_cards.erase(
      std::remove_if(credit_cards.begin(), credit_cards.end(),
                     FormGroupGUIDMatchesFunctor<CreditCard>(guid)),
      credit_cards.end());

  SetCreditCards(&credit_cards);
}

CreditCard* PersonalDataManager::GetCreditCardByGUID(const std::string& guid) {
  for (std::vector<CreditCard*>::iterator iter = credit_cards_.begin();
       iter != credit_cards_.end(); ++iter) {
    if ((*iter)->guid() == guid)
      return *iter;
  }
  return NULL;
}

void PersonalDataManager::GetPossibleFieldTypes(const string16& text,
                                                FieldTypeSet* possible_types) {
  string16 clean_info = StringToLowerASCII(CollapseWhitespace(text, false));
  if (clean_info.empty()) {
    possible_types->insert(EMPTY_TYPE);
    return;
  }

  for (ScopedVector<AutoFillProfile>::iterator iter = web_profiles_.begin();
       iter != web_profiles_.end(); ++iter) {
    const FormGroup* profile = *iter;
    if (!profile) {
      DLOG(ERROR) << "NULL information in profiles list";
      continue;
    }

    profile->GetPossibleFieldTypes(clean_info, possible_types);
  }

  for (ScopedVector<CreditCard>::iterator iter = credit_cards_.begin();
       iter != credit_cards_.end(); ++iter) {
    const FormGroup* credit_card = *iter;
    if (!credit_card) {
      DLOG(ERROR) << "NULL information in credit cards list";
      continue;
    }

    credit_card->GetPossibleFieldTypes(clean_info, possible_types);
  }

  if (possible_types->size() == 0)
    possible_types->insert(UNKNOWN_TYPE);
}

bool PersonalDataManager::HasPassword() {
  return !password_hash_.empty();
}

const std::vector<AutoFillProfile*>& PersonalDataManager::profiles() {
  // |profile_| is NULL in AutoFillManagerTest.
  bool auxiliary_profiles_enabled = profile_ ? profile_->GetPrefs()->GetBoolean(
      prefs::kAutoFillAuxiliaryProfilesEnabled) : false;
  if (!auxiliary_profiles_enabled)
    return web_profiles();

#if !defined(OS_MACOSX)
  NOTREACHED() << "Auxiliary profiles supported on Mac only";
#endif

  profiles_.clear();

  // Populates |auxiliary_profiles_|.
  LoadAuxiliaryProfiles();

  profiles_.insert(profiles_.end(), web_profiles_.begin(), web_profiles_.end());
  profiles_.insert(profiles_.end(),
      auxiliary_profiles_.begin(), auxiliary_profiles_.end());
  return profiles_;
}

AutoFillProfile* PersonalDataManager::CreateNewEmptyAutoFillProfileForDBThread(
    const string16& label) {
  // See comment in header for thread details.
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
  AutoFillProfile* p = new AutoFillProfile;
  p->set_label(label);
  return p;
}

void PersonalDataManager::Refresh() {
  LoadProfiles();
  LoadCreditCards();
}

PersonalDataManager::PersonalDataManager()
    : profile_(NULL),
      is_data_loaded_(false),
      pending_profiles_query_(0),
      pending_creditcards_query_(0) {
}

void PersonalDataManager::Init(Profile* profile) {
  profile_ = profile;
  LoadProfiles();
  LoadCreditCards();
}

void PersonalDataManager::LoadProfiles() {
  WebDataService* web_data_service =
      profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
  if (!web_data_service) {
    NOTREACHED();
    return;
  }

  CancelPendingQuery(&pending_profiles_query_);

  pending_profiles_query_ = web_data_service->GetAutoFillProfiles(this);
}

// Win and Linux implementations do nothing.  Mac implementation fills in the
// contents of |auxiliary_profiles_|.
#if !defined(OS_MACOSX)
void PersonalDataManager::LoadAuxiliaryProfiles() {
}
#endif

void PersonalDataManager::LoadCreditCards() {
  WebDataService* web_data_service =
      profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
  if (!web_data_service) {
    NOTREACHED();
    return;
  }

  CancelPendingQuery(&pending_creditcards_query_);

  pending_creditcards_query_ = web_data_service->GetCreditCards(this);
}

void PersonalDataManager::ReceiveLoadedProfiles(WebDataService::Handle h,
                                                const WDTypedResult* result) {
  DCHECK_EQ(pending_profiles_query_, h);

  pending_profiles_query_ = 0;
  web_profiles_.reset();

  const WDResult<std::vector<AutoFillProfile*> >* r =
      static_cast<const WDResult<std::vector<AutoFillProfile*> >*>(result);

  std::vector<AutoFillProfile*> profiles = r->GetValue();
  for (std::vector<AutoFillProfile*>::iterator iter = profiles.begin();
       iter != profiles.end(); ++iter) {
    web_profiles_.push_back(*iter);
  }
}

void PersonalDataManager::ReceiveLoadedCreditCards(
    WebDataService::Handle h, const WDTypedResult* result) {
  DCHECK_EQ(pending_creditcards_query_, h);

  pending_creditcards_query_ = 0;
  credit_cards_.reset();

  const WDResult<std::vector<CreditCard*> >* r =
      static_cast<const WDResult<std::vector<CreditCard*> >*>(result);

  std::vector<CreditCard*> credit_cards = r->GetValue();
  for (std::vector<CreditCard*>::iterator iter = credit_cards.begin();
       iter != credit_cards.end(); ++iter) {
    credit_cards_.push_back(*iter);
  }
}

void PersonalDataManager::CancelPendingQuery(WebDataService::Handle* handle) {
  if (*handle) {
    WebDataService* web_data_service =
        profile_->GetWebDataService(Profile::EXPLICIT_ACCESS);
    if (!web_data_service) {
      NOTREACHED();
      return;
    }
    web_data_service->CancelRequest(*handle);
  }
  *handle = 0;
}

void PersonalDataManager::SetUniqueCreditCardLabels(
    std::vector<CreditCard>* credit_cards) {
  std::map<string16, std::vector<CreditCard*> > label_map;
  for (std::vector<CreditCard>::iterator iter = credit_cards->begin();
       iter != credit_cards->end(); ++iter) {
    label_map[iter->Label()].push_back(&(*iter));
  }

  for (std::map<string16, std::vector<CreditCard*> >::iterator iter =
           label_map.begin();
       iter != label_map.end(); ++iter) {
    // Start at the second element because the first label should not be
    // renamed.  The appended label number starts at 2, because the first label
    // has an implicit index of 1.
    for (size_t i = 1; i < iter->second.size(); ++i) {
      string16 newlabel = iter->second[i]->Label() +
          base::UintToString16(static_cast<unsigned int>(i + 1));
      iter->second[i]->set_label(newlabel);
    }
  }
}

void PersonalDataManager::SaveImportedProfile() {
  if (profile_->IsOffTheRecord())
    return;

  if (!imported_profile_.get())
    return;

  AddProfile(*imported_profile_);
}

// TODO(jhawkins): Refactor and merge this with SaveImportedProfile.
void PersonalDataManager::SaveImportedCreditCard() {
  if (profile_->IsOffTheRecord())
    return;

  if (!imported_credit_card_.get())
    return;

  // Set to true if |imported_credit_card_| is merged into the profile list.
  bool merged = false;

  std::vector<CreditCard> creditcards;
  for (std::vector<CreditCard*>::const_iterator iter =
           credit_cards_.begin();
       iter != credit_cards_.end(); ++iter) {
    if (imported_credit_card_->IsSubsetOf(**iter)) {
      // In this case, the existing credit card already contains all of the data
      // in |imported_credit_card_|, so consider the credit cards already
      // merged.
      merged = true;
    } else if ((*iter)->IntersectionOfTypesHasEqualValues(
        *imported_credit_card_)) {
      // |imported_profile| contains all of the data in this profile, plus more.
      merged = true;
      (*iter)->MergeWith(*imported_credit_card_);
    } else if (!imported_credit_card_->number().empty() &&
               (*iter)->number() == imported_credit_card_->number()) {
      merged = true;
      (*iter)->OverwriteWith(*imported_credit_card_);
    }

    creditcards.push_back(**iter);
  }

  if (!merged)
    creditcards.push_back(*imported_credit_card_);

  SetCreditCards(&creditcards);
}