1// Copyright (c) 2012 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 "chrome/browser/ui/webui/options/autofill_options_handler.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/guid.h"
12#include "base/logging.h"
13#include "base/strings/string16.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/strings/utf_string_conversions.h"
16#include "base/values.h"
17#include "chrome/browser/autofill/personal_data_manager_factory.h"
18#include "chrome/browser/browser_process.h"
19#include "chrome/browser/profiles/profile.h"
20#include "chrome/browser/ui/autofill/country_combobox_model.h"
21#include "chrome/common/url_constants.h"
22#include "chrome/grit/generated_resources.h"
23#include "components/autofill/core/browser/autofill_country.h"
24#include "components/autofill/core/browser/autofill_profile.h"
25#include "components/autofill/core/browser/credit_card.h"
26#include "components/autofill/core/browser/personal_data_manager.h"
27#include "components/autofill/core/browser/phone_number_i18n.h"
28#include "components/autofill/core/common/autofill_constants.h"
29#include "content/public/browser/web_ui.h"
30#include "third_party/libaddressinput/messages.h"
31#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h"
32#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h"
33#include "third_party/libaddressinput/src/cpp/include/libaddressinput/localization.h"
34#include "ui/base/l10n/l10n_util.h"
35#include "ui/base/webui/web_ui_util.h"
36
37using autofill::AutofillCountry;
38using autofill::AutofillType;
39using autofill::ServerFieldType;
40using autofill::AutofillProfile;
41using autofill::CreditCard;
42using autofill::PersonalDataManager;
43using i18n::addressinput::AddressUiComponent;
44
45namespace {
46
47const char kSettingsOrigin[] = "Chrome settings";
48
49static const char kFullNameField[] = "fullName";
50static const char kCompanyNameField[] = "companyName";
51static const char kAddressLineField[] = "addrLines";
52static const char kDependentLocalityField[] = "dependentLocality";
53static const char kCityField[] = "city";
54static const char kStateField[] = "state";
55static const char kPostalCodeField[] = "postalCode";
56static const char kSortingCodeField[] = "sortingCode";
57static const char kCountryField[] = "country";
58
59static const char kComponents[] = "components";
60static const char kLanguageCode[] = "languageCode";
61
62// Fills |components| with the address UI components that should be used to
63// input an address for |country_code| when UI BCP 47 language code is
64// |ui_language_code|. If |components_language_code| is not NULL, then sets it
65// to the BCP 47 language code that should be used to format the address for
66// display.
67void GetAddressComponents(const std::string& country_code,
68                          const std::string& ui_language_code,
69                          base::ListValue* address_components,
70                          std::string* components_language_code) {
71  DCHECK(address_components);
72
73  i18n::addressinput::Localization localization;
74  localization.SetGetter(l10n_util::GetStringUTF8);
75  std::string not_used;
76  std::vector<AddressUiComponent> components =
77      i18n::addressinput::BuildComponents(
78          country_code,
79          localization,
80          ui_language_code,
81          components_language_code == NULL ?
82              &not_used : components_language_code);
83  if (components.empty()) {
84    static const char kDefaultCountryCode[] = "US";
85    components = i18n::addressinput::BuildComponents(
86        kDefaultCountryCode,
87        localization,
88        ui_language_code,
89        components_language_code == NULL ?
90            &not_used : components_language_code);
91  }
92  DCHECK(!components.empty());
93
94  base::ListValue* line = NULL;
95  static const char kField[] = "field";
96  static const char kLength[] = "length";
97  for (size_t i = 0; i < components.size(); ++i) {
98    if (i == 0 ||
99        components[i - 1].length_hint == AddressUiComponent::HINT_LONG ||
100        components[i].length_hint == AddressUiComponent::HINT_LONG) {
101      line = new base::ListValue;
102      address_components->Append(line);
103    }
104
105    scoped_ptr<base::DictionaryValue> component(new base::DictionaryValue);
106    component->SetString("name", components[i].name);
107
108    switch (components[i].field) {
109      case i18n::addressinput::COUNTRY:
110        component->SetString(kField, kCountryField);
111        break;
112      case i18n::addressinput::ADMIN_AREA:
113        component->SetString(kField, kStateField);
114        break;
115      case i18n::addressinput::LOCALITY:
116        component->SetString(kField, kCityField);
117        break;
118      case i18n::addressinput::DEPENDENT_LOCALITY:
119        component->SetString(kField, kDependentLocalityField);
120        break;
121      case i18n::addressinput::SORTING_CODE:
122        component->SetString(kField, kSortingCodeField);
123        break;
124      case i18n::addressinput::POSTAL_CODE:
125        component->SetString(kField, kPostalCodeField);
126        break;
127      case i18n::addressinput::STREET_ADDRESS:
128        component->SetString(kField, kAddressLineField);
129        break;
130      case i18n::addressinput::ORGANIZATION:
131        component->SetString(kField, kCompanyNameField);
132        break;
133      case i18n::addressinput::RECIPIENT:
134        component->SetString(kField, kFullNameField);
135        component->SetString(
136            "placeholder",
137            l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_ADD_NAME));
138        break;
139    }
140
141    switch (components[i].length_hint) {
142      case AddressUiComponent::HINT_LONG:
143        component->SetString(kLength, "long");
144        break;
145      case AddressUiComponent::HINT_SHORT:
146        component->SetString(kLength, "short");
147        break;
148    }
149
150    line->Append(component.release());
151  }
152}
153
154// Sets data related to the country <select>.
155void SetCountryData(const PersonalDataManager& manager,
156                    base::DictionaryValue* localized_strings) {
157  autofill::CountryComboboxModel model;
158  model.SetCountries(manager, base::Callback<bool(const std::string&)>());
159  const std::vector<AutofillCountry*>& countries = model.countries();
160  localized_strings->SetString("defaultCountryCode",
161                               countries.front()->country_code());
162
163  // An ordered list of options to show in the <select>.
164  scoped_ptr<base::ListValue> country_list(new base::ListValue());
165  for (size_t i = 0; i < countries.size(); ++i) {
166    scoped_ptr<base::DictionaryValue> option_details(
167        new base::DictionaryValue());
168    option_details->SetString("name", model.GetItemAt(i));
169    option_details->SetString(
170        "value",
171        countries[i] ? countries[i]->country_code() : "separator");
172    country_list->Append(option_details.release());
173  }
174  localized_strings->Set("autofillCountrySelectList", country_list.release());
175
176  scoped_ptr<base::ListValue> default_country_components(new base::ListValue);
177  std::string default_country_language_code;
178  GetAddressComponents(countries.front()->country_code(),
179                       g_browser_process->GetApplicationLocale(),
180                       default_country_components.get(),
181                       &default_country_language_code);
182  localized_strings->Set("autofillDefaultCountryComponents",
183                         default_country_components.release());
184  localized_strings->SetString("autofillDefaultCountryLanguageCode",
185                               default_country_language_code);
186}
187
188// Get the multi-valued element for |type| and return it in |ListValue| form.
189// Buyer beware: the type of data affects whether GetRawInfo or GetInfo is used.
190void GetValueList(const AutofillProfile& profile,
191                  ServerFieldType type,
192                  scoped_ptr<base::ListValue>* list) {
193  list->reset(new base::ListValue);
194
195  std::vector<base::string16> values;
196  if (AutofillType(type).group() == autofill::NAME) {
197    profile.GetMultiInfo(
198        AutofillType(type), g_browser_process->GetApplicationLocale(), &values);
199  } else {
200    profile.GetRawMultiInfo(type, &values);
201  }
202
203  // |Get[Raw]MultiInfo()| always returns at least one, potentially empty, item.
204  if (values.size() == 1 && values.front().empty())
205    return;
206
207  for (size_t i = 0; i < values.size(); ++i) {
208    (*list)->Set(i, new base::StringValue(values[i]));
209  }
210}
211
212// Converts a ListValue of StringValues to a vector of string16s.
213void ListValueToStringVector(const base::ListValue& list,
214                             std::vector<base::string16>* output) {
215  output->resize(list.GetSize());
216  for (size_t i = 0; i < list.GetSize(); ++i) {
217    base::string16 value;
218    if (list.GetString(i, &value))
219      (*output)[i].swap(value);
220  }
221}
222
223// Pulls the phone number |index|, |phone_number_list|, and |country_code| from
224// the |args| input.
225void ExtractPhoneNumberInformation(const base::ListValue* args,
226                                   size_t* index,
227                                   const base::ListValue** phone_number_list,
228                                   std::string* country_code) {
229  // Retrieve index as a |double|, as that is how it comes across from
230  // JavaScript.
231  double number = 0.0;
232  if (!args->GetDouble(0, &number)) {
233    NOTREACHED();
234    return;
235  }
236  *index = number;
237
238  if (!args->GetList(1, phone_number_list)) {
239    NOTREACHED();
240    return;
241  }
242
243  if (!args->GetString(2, country_code)) {
244    NOTREACHED();
245    return;
246  }
247}
248
249// Searches the |list| for the value at |index|.  If this value is present
250// in any of the rest of the list, then the item (at |index|) is removed.
251// The comparison of phone number values is done on normalized versions of the
252// phone number values.
253void RemoveDuplicatePhoneNumberAtIndex(size_t index,
254                                       const std::string& country_code,
255                                       base::ListValue* list) {
256  base::string16 new_value;
257  if (!list->GetString(index, &new_value)) {
258    NOTREACHED() << "List should have a value at index " << index;
259    return;
260  }
261
262  bool is_duplicate = false;
263  std::string app_locale = g_browser_process->GetApplicationLocale();
264  for (size_t i = 0; i < list->GetSize() && !is_duplicate; ++i) {
265    if (i == index)
266      continue;
267
268    base::string16 existing_value;
269    if (!list->GetString(i, &existing_value)) {
270      NOTREACHED() << "List should have a value at index " << i;
271      continue;
272    }
273    is_duplicate = autofill::i18n::PhoneNumbersMatch(
274        new_value, existing_value, country_code, app_locale);
275  }
276
277  if (is_duplicate)
278    list->Remove(index, NULL);
279}
280
281scoped_ptr<base::ListValue> ValidatePhoneArguments(
282    const base::ListValue* args) {
283  size_t index = 0;
284  std::string country_code;
285  const base::ListValue* extracted_list = NULL;
286  ExtractPhoneNumberInformation(args, &index, &extracted_list, &country_code);
287
288  scoped_ptr<base::ListValue> list(extracted_list->DeepCopy());
289  RemoveDuplicatePhoneNumberAtIndex(index, country_code, list.get());
290  return list.Pass();
291}
292
293}  // namespace
294
295namespace options {
296
297AutofillOptionsHandler::AutofillOptionsHandler()
298    : personal_data_(NULL) {}
299
300AutofillOptionsHandler::~AutofillOptionsHandler() {
301  if (personal_data_)
302    personal_data_->RemoveObserver(this);
303}
304
305/////////////////////////////////////////////////////////////////////////////
306// OptionsPageUIHandler implementation:
307void AutofillOptionsHandler::GetLocalizedValues(
308    base::DictionaryValue* localized_strings) {
309  DCHECK(localized_strings);
310
311  static OptionsStringResource resources[] = {
312    { "autofillAddresses", IDS_AUTOFILL_ADDRESSES_GROUP_NAME },
313    { "autofillCreditCards", IDS_AUTOFILL_CREDITCARDS_GROUP_NAME },
314    { "autofillAddAddress", IDS_AUTOFILL_ADD_ADDRESS_BUTTON },
315    { "autofillAddCreditCard", IDS_AUTOFILL_ADD_CREDITCARD_BUTTON },
316    { "autofillEditProfileButton", IDS_AUTOFILL_EDIT_PROFILE_BUTTON },
317    { "helpButton", IDS_AUTOFILL_HELP_LABEL },
318    { "addAddressTitle", IDS_AUTOFILL_ADD_ADDRESS_CAPTION },
319    { "editAddressTitle", IDS_AUTOFILL_EDIT_ADDRESS_CAPTION },
320    { "addCreditCardTitle", IDS_AUTOFILL_ADD_CREDITCARD_CAPTION },
321    { "editCreditCardTitle", IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION },
322#if defined(OS_MACOSX)
323    { "auxiliaryProfilesEnabled", IDS_AUTOFILL_USE_MAC_ADDRESS_BOOK },
324#endif  // defined(OS_MACOSX)
325  };
326
327  RegisterStrings(localized_strings, resources, arraysize(resources));
328  RegisterTitle(localized_strings, "autofillOptionsPage",
329                IDS_AUTOFILL_OPTIONS_TITLE);
330
331  localized_strings->SetString("helpUrl", autofill::kHelpURL);
332  SetAddressOverlayStrings(localized_strings);
333  SetCreditCardOverlayStrings(localized_strings);
334}
335
336void AutofillOptionsHandler::InitializeHandler() {
337  // personal_data_ is NULL in guest mode on Chrome OS.
338  if (personal_data_)
339    personal_data_->AddObserver(this);
340}
341
342void AutofillOptionsHandler::InitializePage() {
343  if (personal_data_)
344    LoadAutofillData();
345}
346
347void AutofillOptionsHandler::RegisterMessages() {
348  personal_data_ = autofill::PersonalDataManagerFactory::GetForProfile(
349      Profile::FromWebUI(web_ui()));
350
351#if defined(OS_MACOSX) && !defined(OS_IOS)
352  web_ui()->RegisterMessageCallback(
353      "accessAddressBook",
354      base::Bind(&AutofillOptionsHandler::AccessAddressBook,
355                 base::Unretained(this)));
356#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
357  web_ui()->RegisterMessageCallback(
358      "removeData",
359      base::Bind(&AutofillOptionsHandler::RemoveData,
360                 base::Unretained(this)));
361  web_ui()->RegisterMessageCallback(
362      "loadAddressEditor",
363      base::Bind(&AutofillOptionsHandler::LoadAddressEditor,
364                 base::Unretained(this)));
365  web_ui()->RegisterMessageCallback(
366      "loadAddressEditorComponents",
367      base::Bind(&AutofillOptionsHandler::LoadAddressEditorComponents,
368                 base::Unretained(this)));
369  web_ui()->RegisterMessageCallback(
370      "loadCreditCardEditor",
371      base::Bind(&AutofillOptionsHandler::LoadCreditCardEditor,
372                 base::Unretained(this)));
373  web_ui()->RegisterMessageCallback(
374      "setAddress",
375      base::Bind(&AutofillOptionsHandler::SetAddress, base::Unretained(this)));
376  web_ui()->RegisterMessageCallback(
377      "setCreditCard",
378      base::Bind(&AutofillOptionsHandler::SetCreditCard,
379                 base::Unretained(this)));
380  web_ui()->RegisterMessageCallback(
381      "validatePhoneNumbers",
382      base::Bind(&AutofillOptionsHandler::ValidatePhoneNumbers,
383                 base::Unretained(this)));
384}
385
386/////////////////////////////////////////////////////////////////////////////
387// PersonalDataManagerObserver implementation:
388void AutofillOptionsHandler::OnPersonalDataChanged() {
389  LoadAutofillData();
390}
391
392void AutofillOptionsHandler::SetAddressOverlayStrings(
393    base::DictionaryValue* localized_strings) {
394  localized_strings->SetString("autofillEditAddressTitle",
395      l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_ADDRESS_CAPTION));
396  localized_strings->SetString("autofillCountryLabel",
397      l10n_util::GetStringUTF16(IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL));
398  localized_strings->SetString("autofillPhoneLabel",
399      l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE));
400  localized_strings->SetString("autofillEmailLabel",
401      l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_EMAIL));
402  localized_strings->SetString("autofillAddPhonePlaceholder",
403      l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_ADD_PHONE));
404  localized_strings->SetString("autofillAddEmailPlaceholder",
405      l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_ADD_EMAIL));
406  SetCountryData(*personal_data_, localized_strings);
407}
408
409void AutofillOptionsHandler::SetCreditCardOverlayStrings(
410    base::DictionaryValue* localized_strings) {
411  localized_strings->SetString("autofillEditCreditCardTitle",
412      l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION));
413  localized_strings->SetString("nameOnCardLabel",
414      l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_NAME_ON_CARD));
415  localized_strings->SetString("creditCardNumberLabel",
416      l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_CREDIT_CARD_NUMBER));
417  localized_strings->SetString("creditCardExpirationDateLabel",
418      l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_EXPIRATION_DATE));
419}
420
421void AutofillOptionsHandler::LoadAutofillData() {
422  if (!IsPersonalDataLoaded())
423    return;
424
425  const std::vector<AutofillProfile*>& profiles =
426      personal_data_->web_profiles();
427  std::vector<base::string16> labels;
428  AutofillProfile::CreateDifferentiatingLabels(
429      profiles,
430      g_browser_process->GetApplicationLocale(),
431      &labels);
432  DCHECK_EQ(labels.size(), profiles.size());
433
434  base::ListValue addresses;
435  for (size_t i = 0; i < profiles.size(); ++i) {
436    base::ListValue* entry = new base::ListValue();
437    entry->Append(new base::StringValue(profiles[i]->guid()));
438    entry->Append(new base::StringValue(labels[i]));
439    addresses.Append(entry);
440  }
441
442  web_ui()->CallJavascriptFunction("AutofillOptions.setAddressList", addresses);
443
444  base::ListValue credit_cards;
445  const std::vector<CreditCard*>& cards = personal_data_->GetCreditCards();
446  for (std::vector<CreditCard*>::const_iterator iter = cards.begin();
447       iter != cards.end(); ++iter) {
448    const CreditCard* card = *iter;
449    // TODO(estade): this should be a dictionary.
450    base::ListValue* entry = new base::ListValue();
451    entry->Append(new base::StringValue(card->guid()));
452    entry->Append(new base::StringValue(card->Label()));
453    entry->Append(new base::StringValue(
454        webui::GetBitmapDataUrlFromResource(
455            CreditCard::IconResourceId(card->type()))));
456    entry->Append(new base::StringValue(card->TypeForDisplay()));
457    credit_cards.Append(entry);
458  }
459
460  web_ui()->CallJavascriptFunction("AutofillOptions.setCreditCardList",
461                                   credit_cards);
462}
463
464#if defined(OS_MACOSX) && !defined(OS_IOS)
465void AutofillOptionsHandler::AccessAddressBook(const base::ListValue* args) {
466  personal_data_->AccessAddressBook();
467}
468#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
469
470void AutofillOptionsHandler::RemoveData(const base::ListValue* args) {
471  DCHECK(IsPersonalDataLoaded());
472
473  std::string guid;
474  if (!args->GetString(0, &guid)) {
475    NOTREACHED();
476    return;
477  }
478
479  personal_data_->RemoveByGUID(guid);
480}
481
482void AutofillOptionsHandler::LoadAddressEditor(const base::ListValue* args) {
483  DCHECK(IsPersonalDataLoaded());
484
485  std::string guid;
486  if (!args->GetString(0, &guid)) {
487    NOTREACHED();
488    return;
489  }
490
491  AutofillProfile* profile = personal_data_->GetProfileByGUID(guid);
492  if (!profile) {
493    // There is a race where a user can click once on the close button and
494    // quickly click again on the list item before the item is removed (since
495    // the list is not updated until the model tells the list an item has been
496    // removed). This will activate the editor for a profile that has been
497    // removed. Do nothing in that case.
498    return;
499  }
500
501  base::DictionaryValue address;
502  AutofillProfileToDictionary(*profile, &address);
503
504  web_ui()->CallJavascriptFunction("AutofillOptions.editAddress", address);
505}
506
507void AutofillOptionsHandler::LoadAddressEditorComponents(
508    const base::ListValue* args) {
509  std::string country_code;
510  if (!args->GetString(0, &country_code)) {
511    NOTREACHED();
512    return;
513  }
514
515  base::DictionaryValue input;
516  scoped_ptr<base::ListValue> components(new base::ListValue);
517  std::string language_code;
518  GetAddressComponents(country_code, g_browser_process->GetApplicationLocale(),
519                       components.get(), &language_code);
520  input.Set(kComponents, components.release());
521  input.SetString(kLanguageCode, language_code);
522
523  web_ui()->CallJavascriptFunction(
524      "AutofillEditAddressOverlay.loadAddressComponents", input);
525}
526
527void AutofillOptionsHandler::LoadCreditCardEditor(const base::ListValue* args) {
528  DCHECK(IsPersonalDataLoaded());
529
530  std::string guid;
531  if (!args->GetString(0, &guid)) {
532    NOTREACHED();
533    return;
534  }
535
536  CreditCard* credit_card = personal_data_->GetCreditCardByGUID(guid);
537  if (!credit_card) {
538    // There is a race where a user can click once on the close button and
539    // quickly click again on the list item before the item is removed (since
540    // the list is not updated until the model tells the list an item has been
541    // removed). This will activate the editor for a profile that has been
542    // removed. Do nothing in that case.
543    return;
544  }
545
546  base::DictionaryValue credit_card_data;
547  credit_card_data.SetString("guid", credit_card->guid());
548  credit_card_data.SetString(
549      "nameOnCard",
550      credit_card->GetRawInfo(autofill::CREDIT_CARD_NAME));
551  credit_card_data.SetString(
552      "creditCardNumber",
553      credit_card->GetRawInfo(autofill::CREDIT_CARD_NUMBER));
554  credit_card_data.SetString(
555      "expirationMonth",
556      credit_card->GetRawInfo(autofill::CREDIT_CARD_EXP_MONTH));
557  credit_card_data.SetString(
558      "expirationYear",
559      credit_card->GetRawInfo(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR));
560
561  web_ui()->CallJavascriptFunction("AutofillOptions.editCreditCard",
562                                   credit_card_data);
563}
564
565void AutofillOptionsHandler::SetAddress(const base::ListValue* args) {
566  if (!IsPersonalDataLoaded())
567    return;
568
569  int arg_counter = 0;
570  std::string guid;
571  if (!args->GetString(arg_counter++, &guid)) {
572    NOTREACHED();
573    return;
574  }
575
576  AutofillProfile profile(guid, kSettingsOrigin);
577
578  base::string16 value;
579  const base::ListValue* list_value;
580  if (args->GetList(arg_counter++, &list_value)) {
581    std::vector<base::string16> values;
582    ListValueToStringVector(*list_value, &values);
583    profile.SetMultiInfo(AutofillType(autofill::NAME_FULL),
584                         values,
585                         g_browser_process->GetApplicationLocale());
586  }
587
588  if (args->GetString(arg_counter++, &value))
589    profile.SetRawInfo(autofill::COMPANY_NAME, value);
590
591  if (args->GetString(arg_counter++, &value))
592    profile.SetRawInfo(autofill::ADDRESS_HOME_STREET_ADDRESS, value);
593
594  if (args->GetString(arg_counter++, &value))
595    profile.SetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY, value);
596
597  if (args->GetString(arg_counter++, &value))
598    profile.SetRawInfo(autofill::ADDRESS_HOME_CITY, value);
599
600  if (args->GetString(arg_counter++, &value))
601    profile.SetRawInfo(autofill::ADDRESS_HOME_STATE, value);
602
603  if (args->GetString(arg_counter++, &value))
604    profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP, value);
605
606  if (args->GetString(arg_counter++, &value))
607    profile.SetRawInfo(autofill::ADDRESS_HOME_SORTING_CODE, value);
608
609  if (args->GetString(arg_counter++, &value))
610    profile.SetRawInfo(autofill::ADDRESS_HOME_COUNTRY, value);
611
612  if (args->GetList(arg_counter++, &list_value)) {
613    std::vector<base::string16> values;
614    ListValueToStringVector(*list_value, &values);
615    profile.SetRawMultiInfo(autofill::PHONE_HOME_WHOLE_NUMBER, values);
616  }
617
618  if (args->GetList(arg_counter++, &list_value)) {
619    std::vector<base::string16> values;
620    ListValueToStringVector(*list_value, &values);
621    profile.SetRawMultiInfo(autofill::EMAIL_ADDRESS, values);
622  }
623
624  if (args->GetString(arg_counter++, &value))
625    profile.set_language_code(base::UTF16ToUTF8(value));
626
627  if (!base::IsValidGUID(profile.guid())) {
628    profile.set_guid(base::GenerateGUID());
629    personal_data_->AddProfile(profile);
630  } else {
631    personal_data_->UpdateProfile(profile);
632  }
633}
634
635void AutofillOptionsHandler::SetCreditCard(const base::ListValue* args) {
636  if (!IsPersonalDataLoaded())
637    return;
638
639  std::string guid;
640  if (!args->GetString(0, &guid)) {
641    NOTREACHED();
642    return;
643  }
644
645  CreditCard credit_card(guid, kSettingsOrigin);
646
647  base::string16 value;
648  if (args->GetString(1, &value))
649    credit_card.SetRawInfo(autofill::CREDIT_CARD_NAME, value);
650
651  if (args->GetString(2, &value))
652    credit_card.SetRawInfo(autofill::CREDIT_CARD_NUMBER, value);
653
654  if (args->GetString(3, &value))
655    credit_card.SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH, value);
656
657  if (args->GetString(4, &value))
658    credit_card.SetRawInfo(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, value);
659
660  if (!base::IsValidGUID(credit_card.guid())) {
661    credit_card.set_guid(base::GenerateGUID());
662    personal_data_->AddCreditCard(credit_card);
663  } else {
664    personal_data_->UpdateCreditCard(credit_card);
665  }
666}
667
668void AutofillOptionsHandler::ValidatePhoneNumbers(const base::ListValue* args) {
669  if (!IsPersonalDataLoaded())
670    return;
671
672  scoped_ptr<base::ListValue> list_value = ValidatePhoneArguments(args);
673
674  web_ui()->CallJavascriptFunction(
675    "AutofillEditAddressOverlay.setValidatedPhoneNumbers", *list_value);
676}
677
678bool AutofillOptionsHandler::IsPersonalDataLoaded() const {
679  return personal_data_ && personal_data_->IsDataLoaded();
680}
681
682// static
683void AutofillOptionsHandler::AutofillProfileToDictionary(
684    const autofill::AutofillProfile& profile,
685    base::DictionaryValue* address) {
686  address->SetString("guid", profile.guid());
687  scoped_ptr<base::ListValue> list;
688  GetValueList(profile, autofill::NAME_FULL, &list);
689  address->Set(kFullNameField, list.release());
690  address->SetString(kCompanyNameField,
691                     profile.GetRawInfo(autofill::COMPANY_NAME));
692  address->SetString(kAddressLineField,
693                     profile.GetRawInfo(autofill::ADDRESS_HOME_STREET_ADDRESS));
694  address->SetString(kCityField,
695                     profile.GetRawInfo(autofill::ADDRESS_HOME_CITY));
696  address->SetString(kStateField,
697                     profile.GetRawInfo(autofill::ADDRESS_HOME_STATE));
698  address->SetString(
699      kDependentLocalityField,
700      profile.GetRawInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY));
701  address->SetString(kSortingCodeField,
702                     profile.GetRawInfo(autofill::ADDRESS_HOME_SORTING_CODE));
703  address->SetString(kPostalCodeField,
704                     profile.GetRawInfo(autofill::ADDRESS_HOME_ZIP));
705  address->SetString(kCountryField,
706                     profile.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
707  GetValueList(profile, autofill::PHONE_HOME_WHOLE_NUMBER, &list);
708  address->Set("phone", list.release());
709  GetValueList(profile, autofill::EMAIL_ADDRESS, &list);
710  address->Set("email", list.release());
711  address->SetString(kLanguageCode, profile.language_code());
712
713  scoped_ptr<base::ListValue> components(new base::ListValue);
714  GetAddressComponents(
715      base::UTF16ToUTF8(profile.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY)),
716      profile.language_code(),
717      components.get(),
718      NULL);
719  address->Set(kComponents, components.release());
720}
721
722}  // namespace options
723