Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / autofill / autofill_dialog_controller_impl.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 "chrome/browser/ui/autofill/autofill_dialog_controller_impl.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <string>
10
11 #include "apps/app_window.h"
12 #include "apps/app_window_registry.h"
13 #include "apps/ui/native_app_window.h"
14 #include "base/base64.h"
15 #include "base/bind.h"
16 #include "base/bind_helpers.h"
17 #include "base/i18n/case_conversion.h"
18 #include "base/i18n/rtl.h"
19 #include "base/logging.h"
20 #include "base/prefs/pref_registry_simple.h"
21 #include "base/prefs/pref_service.h"
22 #include "base/prefs/scoped_user_pref_update.h"
23 #include "base/rand_util.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/string_split.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "base/time/time.h"
28 #include "chrome/browser/autofill/personal_data_manager_factory.h"
29 #include "chrome/browser/autofill/validation_rules_storage_factory.h"
30 #include "chrome/browser/browser_process.h"
31 #include "chrome/browser/profiles/profile.h"
32 #include "chrome/browser/ui/autofill/autofill_dialog_common.h"
33 #include "chrome/browser/ui/autofill/autofill_dialog_i18n_input.h"
34 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
35 #include "chrome/browser/ui/autofill/data_model_wrapper.h"
36 #include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
37 #include "chrome/browser/ui/autofill/new_credit_card_bubble_controller.h"
38 #include "chrome/browser/ui/browser.h"
39 #include "chrome/browser/ui/browser_finder.h"
40 #include "chrome/browser/ui/browser_navigator.h"
41 #include "chrome/browser/ui/browser_window.h"
42 #include "chrome/common/chrome_content_client.h"
43 #include "chrome/common/chrome_version_info.h"
44 #include "chrome/common/pref_names.h"
45 #include "chrome/common/render_messages.h"
46 #include "chrome/common/url_constants.h"
47 #include "components/autofill/content/browser/risk/fingerprint.h"
48 #include "components/autofill/content/browser/risk/proto/fingerprint.pb.h"
49 #include "components/autofill/content/browser/wallet/form_field_error.h"
50 #include "components/autofill/content/browser/wallet/full_wallet.h"
51 #include "components/autofill/content/browser/wallet/gaia_account.h"
52 #include "components/autofill/content/browser/wallet/instrument.h"
53 #include "components/autofill/content/browser/wallet/wallet_address.h"
54 #include "components/autofill/content/browser/wallet/wallet_items.h"
55 #include "components/autofill/content/browser/wallet/wallet_service_url.h"
56 #include "components/autofill/content/browser/wallet/wallet_signin_helper.h"
57 #include "components/autofill/core/browser/autofill_country.h"
58 #include "components/autofill/core/browser/autofill_data_model.h"
59 #include "components/autofill/core/browser/autofill_manager.h"
60 #include "components/autofill/core/browser/autofill_type.h"
61 #include "components/autofill/core/browser/personal_data_manager.h"
62 #include "components/autofill/core/browser/phone_number_i18n.h"
63 #include "components/autofill/core/browser/validation.h"
64 #include "components/autofill/core/common/autofill_pref_names.h"
65 #include "components/autofill/core/common/form_data.h"
66 #include "components/user_prefs/pref_registry_syncable.h"
67 #include "content/public/browser/browser_thread.h"
68 #include "content/public/browser/geolocation_provider.h"
69 #include "content/public/browser/navigation_controller.h"
70 #include "content/public/browser/navigation_details.h"
71 #include "content/public/browser/navigation_entry.h"
72 #include "content/public/browser/notification_service.h"
73 #include "content/public/browser/notification_types.h"
74 #include "content/public/browser/render_view_host.h"
75 #include "content/public/browser/web_contents.h"
76 #include "content/public/common/url_constants.h"
77 #include "grit/chromium_strings.h"
78 #include "grit/component_scaled_resources.h"
79 #include "grit/component_strings.h"
80 #include "grit/generated_resources.h"
81 #include "grit/libaddressinput_strings.h"
82 #include "grit/platform_locale_settings.h"
83 #include "grit/theme_resources.h"
84 #include "net/cert/cert_status_flags.h"
85 #include "third_party/libaddressinput/chromium/chrome_downloader_impl.h"
86 #include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
87 #include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_data.h"
88 #include "third_party/libaddressinput/chromium/cpp/include/libaddressinput/address_problem.h"
89 #include "ui/base/base_window.h"
90 #include "ui/base/l10n/l10n_util.h"
91 #include "ui/base/models/combobox_model.h"
92 #include "ui/base/resource/resource_bundle.h"
93 #include "ui/gfx/canvas.h"
94 #include "ui/gfx/image/image_skia_operations.h"
95 #include "ui/gfx/skia_util.h"
96
97 using ::i18n::addressinput::AddressData;
98 using ::i18n::addressinput::AddressField;
99 using ::i18n::addressinput::AddressProblem;
100 using ::i18n::addressinput::AddressProblemFilter;
101 using ::i18n::addressinput::AddressProblems;
102 using ::i18n::addressinput::AddressValidator;
103
104 namespace autofill {
105
106 namespace {
107
108 const char kAddNewItemKey[] = "add-new-item";
109 const char kManageItemsKey[] = "manage-items";
110 const char kSameAsBillingKey[] = "same-as-billing";
111
112 // URLs for Wallet error messages.
113 const char kBuyerLegalAddressStatusUrl[] =
114     "https://wallet.google.com/manage/settings";
115 const char kKnowYourCustomerStatusUrl[] = "https://wallet.google.com/kyc";
116
117 // Keys for the kAutofillDialogAutofillDefault pref dictionary (do not change
118 // these values).
119 const char kGuidPrefKey[] = "guid";
120
121 // This string is stored along with saved addresses and credit cards in the
122 // WebDB, and hence should not be modified, so that it remains consistent over
123 // time.
124 const char kAutofillDialogOrigin[] = "Chrome Autofill dialog";
125
126 // HSL shift to gray out an image.
127 const color_utils::HSL kGrayImageShift = {-1, 0, 0.8};
128
129 // Limit Wallet items refresh rate to at most once per minute.
130 const int64 kWalletItemsRefreshRateSeconds = 60;
131
132 // The number of milliseconds to delay enabling the submit button after showing
133 // the dialog. This delay prevents users from accidentally clicking the submit
134 // button on startup.
135 const int kSubmitButtonDelayMs = 1000;
136
137 // A helper class to make sure an AutofillDialogView knows when a series of
138 // updates is incoming.
139 class ScopedViewUpdates {
140  public:
141   explicit ScopedViewUpdates(AutofillDialogView* view) : view_(view) {
142     if (view_)
143       view_->UpdatesStarted();
144   }
145
146   ~ScopedViewUpdates() {
147     if (view_)
148       view_->UpdatesFinished();
149   }
150
151  private:
152   AutofillDialogView* view_;
153
154   DISALLOW_COPY_AND_ASSIGN(ScopedViewUpdates);
155 };
156
157 base::string16 NullGetInfo(const AutofillType& type) {
158   return base::string16();
159 }
160
161 // Extract |type| from |inputs| using |section| to determine whether the info
162 // should be billing or shipping specific (for sections with address info).
163 base::string16 GetInfoFromInputs(const FieldValueMap& inputs,
164                                  DialogSection section,
165                                  const AutofillType& type) {
166   ServerFieldType field_type = type.GetStorableType();
167   if (section != SECTION_SHIPPING)
168     field_type = AutofillType::GetEquivalentBillingFieldType(field_type);
169
170   base::string16 info;
171   FieldValueMap::const_iterator it = inputs.find(field_type);
172   if (it != inputs.end())
173     info = it->second;
174
175   if (!info.empty() && type.html_type() == HTML_TYPE_COUNTRY_CODE) {
176     info = base::ASCIIToUTF16(AutofillCountry::GetCountryCode(
177         info, g_browser_process->GetApplicationLocale()));
178   }
179
180   return info;
181 }
182
183 // Returns true if |input| should be used to fill a site-requested |field| which
184 // is notated with a "shipping" tag, for use when the user has decided to use
185 // the billing address as the shipping address.
186 bool ServerTypeMatchesShippingField(ServerFieldType type,
187                                     const AutofillField& field) {
188   // Equivalent billing field type is used to support UseBillingAsShipping
189   // usecase.
190   return common::ServerTypeEncompassesFieldType(
191       type,
192       AutofillType(AutofillType::GetEquivalentBillingFieldType(
193           field.Type().GetStorableType())));
194 }
195
196 // Initializes |form_group| from user-entered data.
197 void FillFormGroupFromOutputs(const FieldValueMap& detail_outputs,
198                               FormGroup* form_group) {
199   for (FieldValueMap::const_iterator iter = detail_outputs.begin();
200        iter != detail_outputs.end(); ++iter) {
201     ServerFieldType type = iter->first;
202     if (!iter->second.empty()) {
203       if (type == ADDRESS_HOME_COUNTRY || type == ADDRESS_BILLING_COUNTRY) {
204         form_group->SetInfo(AutofillType(type),
205                             iter->second,
206                             g_browser_process->GetApplicationLocale());
207       } else {
208         form_group->SetRawInfo(
209             AutofillType(type).GetStorableType(), iter->second);
210       }
211     }
212   }
213 }
214
215 // Get billing info from |output| and put it into |card|, |cvc|, and |profile|.
216 // These outparams are required because |card|/|profile| accept different types
217 // of raw info, and CreditCard doesn't save CVCs.
218 void GetBillingInfoFromOutputs(const FieldValueMap& output,
219                                CreditCard* card,
220                                base::string16* cvc,
221                                AutofillProfile* profile) {
222   for (FieldValueMap::const_iterator it = output.begin();
223        it != output.end(); ++it) {
224     const ServerFieldType type = it->first;
225     base::string16 trimmed;
226     base::TrimWhitespace(it->second, base::TRIM_ALL, &trimmed);
227
228     // Special case CVC as CreditCard just swallows it.
229     if (type == CREDIT_CARD_VERIFICATION_CODE) {
230       if (cvc)
231         cvc->assign(trimmed);
232     } else if (type == ADDRESS_HOME_COUNTRY ||
233                type == ADDRESS_BILLING_COUNTRY) {
234       if (profile) {
235         profile->SetInfo(AutofillType(type),
236                          trimmed,
237                          g_browser_process->GetApplicationLocale());
238       }
239     } else {
240       // Copy the credit card name to |profile| in addition to |card| as
241       // wallet::Instrument requires a recipient name for its billing address.
242       if (card && type == NAME_FULL)
243         card->SetRawInfo(CREDIT_CARD_NAME, trimmed);
244
245       if (common::IsCreditCardType(type)) {
246         if (card)
247           card->SetRawInfo(type, trimmed);
248       } else if (profile) {
249         profile->SetRawInfo(AutofillType(type).GetStorableType(), trimmed);
250       }
251     }
252   }
253 }
254
255 // Returns the containing window for the given |web_contents|. The containing
256 // window might be a browser window for a Chrome tab, or it might be an app
257 // window for a platform app.
258 ui::BaseWindow* GetBaseWindowForWebContents(
259     content::WebContents* web_contents) {
260   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
261   if (browser)
262     return browser->window();
263
264   gfx::NativeWindow native_window = web_contents->GetTopLevelNativeWindow();
265   apps::AppWindow* app_window =
266       apps::AppWindowRegistry::GetAppWindowForNativeWindowAnyProfile(
267           native_window);
268   return app_window->GetBaseWindow();
269 }
270
271 // Returns a string descriptor for a DialogSection, for use with prefs (do not
272 // change these values).
273 std::string SectionToPrefString(DialogSection section) {
274   switch (section) {
275     case SECTION_CC:
276       return "cc";
277
278     case SECTION_BILLING:
279       return "billing";
280
281     case SECTION_CC_BILLING:
282       // The SECTION_CC_BILLING section isn't active when using Autofill.
283       NOTREACHED();
284       return std::string();
285
286     case SECTION_SHIPPING:
287       return "shipping";
288   }
289
290   NOTREACHED();
291   return std::string();
292 }
293
294 // Check if a given MaskedInstrument is allowed for the purchase.
295 bool IsInstrumentAllowed(
296     const wallet::WalletItems::MaskedInstrument& instrument) {
297   switch (instrument.status()) {
298     case wallet::WalletItems::MaskedInstrument::VALID:
299     case wallet::WalletItems::MaskedInstrument::PENDING:
300     case wallet::WalletItems::MaskedInstrument::EXPIRED:
301     case wallet::WalletItems::MaskedInstrument::BILLING_INCOMPLETE:
302       return true;
303     default:
304       return false;
305   }
306 }
307
308 // Signals that the user has opted in to geolocation services.  Factored out
309 // into a separate method because all interaction with the geolocation provider
310 // needs to happen on the IO thread, which is not the thread
311 // AutofillDialogViewDelegate lives on.
312 void UserDidOptIntoLocationServices() {
313   content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices();
314 }
315
316 // Loops through |addresses_| comparing to |address| ignoring ID. If a match
317 // is not found, NULL is returned.
318 const wallet::Address* FindDuplicateAddress(
319     const std::vector<wallet::Address*>& addresses,
320     const wallet::Address& address) {
321   for (size_t i = 0; i < addresses.size(); ++i) {
322     if (addresses[i]->EqualsIgnoreID(address))
323       return addresses[i];
324   }
325   return NULL;
326 }
327
328 bool IsCardHolderNameValidForWallet(const base::string16& name) {
329   base::string16 whitespace_collapsed_name =
330       base::CollapseWhitespace(name, true);
331   std::vector<base::string16> split_name;
332   base::SplitString(whitespace_collapsed_name, ' ', &split_name);
333   return split_name.size() >= 2;
334 }
335
336 DialogSection SectionFromLocation(wallet::FormFieldError::Location location) {
337   switch (location) {
338     case wallet::FormFieldError::PAYMENT_INSTRUMENT:
339     case wallet::FormFieldError::LEGAL_ADDRESS:
340       return SECTION_CC_BILLING;
341
342     case wallet::FormFieldError::SHIPPING_ADDRESS:
343       return SECTION_SHIPPING;
344
345     case wallet::FormFieldError::UNKNOWN_LOCATION:
346       NOTREACHED();
347       return SECTION_MAX;
348   }
349
350   NOTREACHED();
351   return SECTION_MAX;
352 }
353
354 scoped_ptr<DialogNotification> GetWalletError(
355     wallet::WalletClient::ErrorType error_type) {
356   base::string16 text;
357   GURL url;
358
359   switch (error_type) {
360     case wallet::WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
361       text = l10n_util::GetStringUTF16(
362           IDS_AUTOFILL_WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS);
363       url = GURL(kKnowYourCustomerStatusUrl);
364       break;
365
366     case wallet::WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
367       text = l10n_util::GetStringUTF16(
368           IDS_AUTOFILL_WALLET_BUYER_COUNTRY_NOT_SUPPORTED);
369       url = GURL(kBuyerLegalAddressStatusUrl);
370       break;
371
372     default:
373       // The notification will not have a link; it's handled in the next
374       // switch statement.
375       break;
376   }
377
378   if (!text.empty()) {
379     scoped_ptr<DialogNotification> notification(new DialogNotification(
380         DialogNotification::WALLET_ERROR,
381         text));
382     notification->set_link_url(url);
383     return notification.Pass();
384   }
385
386   int error_ids = 0;
387   int error_code = 0;
388
389   switch (error_type) {
390     case wallet::WalletClient::UNSUPPORTED_MERCHANT:
391       error_ids = IDS_AUTOFILL_WALLET_UNSUPPORTED_MERCHANT;
392       break;
393
394     case wallet::WalletClient::BAD_REQUEST:
395       error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR;
396       error_code = 71;
397       break;
398
399     case wallet::WalletClient::INVALID_PARAMS:
400       error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR;
401       error_code = 42;
402       break;
403
404     case wallet::WalletClient::BUYER_ACCOUNT_ERROR:
405       error_ids = IDS_AUTOFILL_WALLET_BUYER_ACCOUNT_ERROR;
406       error_code = 12;
407       break;
408
409     case wallet::WalletClient::UNSUPPORTED_API_VERSION:
410       error_ids = IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR;
411       error_code = 43;
412       break;
413
414     case wallet::WalletClient::SERVICE_UNAVAILABLE:
415       error_ids = IDS_AUTOFILL_WALLET_SERVICE_UNAVAILABLE_ERROR;
416       error_code = 61;
417       break;
418
419     case wallet::WalletClient::INTERNAL_ERROR:
420       error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
421       error_code = 62;
422       break;
423
424     case wallet::WalletClient::MALFORMED_RESPONSE:
425       error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
426       error_code = 72;
427       break;
428
429     case wallet::WalletClient::NETWORK_ERROR:
430       error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
431       error_code = 73;
432       break;
433
434     case wallet::WalletClient::UNKNOWN_ERROR:
435       error_ids = IDS_AUTOFILL_WALLET_UNKNOWN_ERROR;
436       error_code = 74;
437       break;
438
439     case wallet::WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
440       error_ids = IDS_AUTOFILL_WALLET_UNSUPPORTED_AGENT_OR_API_KEY;
441       error_code = 75;
442       break;
443
444     default:
445       break;
446   }
447
448   DCHECK_NE(0, error_ids);
449
450   // The other error types are strings of the form "XXX. You can pay without
451   // wallet."
452   scoped_ptr<DialogNotification> notification(new DialogNotification(
453       DialogNotification::WALLET_ERROR,
454       l10n_util::GetStringFUTF16(IDS_AUTOFILL_DIALOG_COMPLETE_WITHOUT_WALLET,
455                                  l10n_util::GetStringUTF16(error_ids))));
456
457   if (error_code) {
458     notification->set_tooltip_text(
459         l10n_util::GetStringFUTF16(IDS_AUTOFILL_WALLET_ERROR_CODE_TOOLTIP,
460                                    base::IntToString16(error_code)));
461   }
462
463   return notification.Pass();
464 }
465
466 // Returns the ID of the address or instrument that should be selected in the
467 // UI, given that the |default_id| is currently the default ID on the Wallet
468 // server, |previous_default_id| was the default ID prior to re-fetching the
469 // Wallet data, and |previously_selected_id| was the ID of the item selected in
470 // the dialog prior to re-fetching the Wallet data.
471 std::string GetIdToSelect(const std::string& default_id,
472                           const std::string& previous_default_id,
473                           const std::string& previously_selected_id) {
474   // If the default ID changed since the last fetch of the Wallet data, select
475   // it rather than the previously selected item, as the user's intention in
476   // changing the default was probably to use it.
477   if (default_id != previous_default_id)
478     return default_id;
479
480   // Otherwise, prefer the previously selected item, if there was one.
481   return !previously_selected_id.empty() ? previously_selected_id : default_id;
482 }
483
484 // Generate a random card number in a user displayable format.
485 base::string16 GenerateRandomCardNumber() {
486   std::string card_number;
487   for (size_t i = 0; i < 4; ++i) {
488     int part = base::RandInt(0, 10000);
489     base::StringAppendF(&card_number, "%04d ", part);
490   }
491   return base::ASCIIToUTF16(card_number);
492 }
493
494 gfx::Image CreditCardIconForType(const std::string& credit_card_type) {
495   const int input_card_idr = CreditCard::IconResourceId(credit_card_type);
496   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
497   gfx::Image result = rb.GetImageNamed(input_card_idr);
498   if (input_card_idr == IDR_AUTOFILL_CC_GENERIC) {
499     // When the credit card type is unknown, no image should be shown. However,
500     // to simplify the view code on Mac, save space for the credit card image by
501     // returning a transparent image of the appropriate size. Not all credit
502     // card images are the same size, but none is larger than the Visa icon.
503     result = gfx::Image(gfx::ImageSkiaOperations::CreateTransparentImage(
504         rb.GetImageNamed(IDR_AUTOFILL_CC_VISA).AsImageSkia(), 0));
505   }
506   return result;
507 }
508
509 gfx::Image CvcIconForCreditCardType(const base::string16& credit_card_type) {
510   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
511   if (credit_card_type == l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX))
512     return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT_AMEX);
513
514   return rb.GetImageNamed(IDR_CREDIT_CARD_CVC_HINT);
515 }
516
517 ServerFieldType CountryTypeForSection(DialogSection section) {
518   return section == SECTION_SHIPPING ? ADDRESS_HOME_COUNTRY :
519                                        ADDRESS_BILLING_COUNTRY;
520 }
521
522 // profile.GetInfo() thunk.
523 base::string16 GetInfoFromProfile(const AutofillProfile& profile,
524                                   const AutofillType& type) {
525   return profile.GetInfo(type, g_browser_process->GetApplicationLocale());
526 }
527
528 // Attempts to canonicalize the administrative area name in |profile| using the
529 // rules in |validator|.
530 void CanonicalizeState(const AddressValidator* validator,
531                        AutofillProfile* profile) {
532   base::string16 administrative_area;
533   AddressData address_data;
534   i18ninput::CreateAddressData(base::Bind(&GetInfoFromProfile, *profile),
535                                &address_data);
536
537   validator->CanonicalizeAdministrativeArea(&address_data);
538   administrative_area = base::UTF8ToUTF16(address_data.administrative_area);
539
540   profile->SetInfo(AutofillType(ADDRESS_HOME_STATE),
541                    administrative_area,
542                    g_browser_process->GetApplicationLocale());
543 }
544
545 ValidityMessage GetPhoneValidityMessage(const base::string16& country_name,
546                                         const base::string16& number) {
547   std::string region = AutofillCountry::GetCountryCode(
548       country_name,
549       g_browser_process->GetApplicationLocale());
550   i18n::PhoneObject phone_object(number, region);
551   ValidityMessage phone_message(base::string16(), true);
552
553   // Check if the phone number is invalid. Allow valid international
554   // numbers that don't match the address's country only if they have an
555   // international calling code.
556   if (!phone_object.IsValidNumber() ||
557       (phone_object.country_code().empty() &&
558        phone_object.region() != region)) {
559     phone_message.text = l10n_util::GetStringUTF16(
560         IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_PHONE_NUMBER);
561   }
562
563   return phone_message;
564 }
565
566 // Constructs |inputs| from template data for a given |dialog_section|.
567 // |country_country| specifies the country code that the inputs should be built
568 // for. Sets the |language_code| to be used for address formatting, if
569 // internationalized address input is enabled. The |language_code| parameter can
570 // be NULL.
571 void BuildInputsForSection(DialogSection dialog_section,
572                            const std::string& country_code,
573                            DetailInputs* inputs,
574                            std::string* language_code) {
575   using l10n_util::GetStringUTF16;
576
577   const DetailInput kCCInputs[] = {
578     { DetailInput::LONG,
579       CREDIT_CARD_NUMBER,
580       GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CARD_NUMBER) },
581     { DetailInput::SHORT,
582       CREDIT_CARD_EXP_MONTH,
583       GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_MONTH) },
584     { DetailInput::SHORT,
585       CREDIT_CARD_EXP_4_DIGIT_YEAR,
586       GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_YEAR) },
587     { DetailInput::SHORT_EOL,
588       CREDIT_CARD_VERIFICATION_CODE,
589       GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC),
590       1.5 },
591   };
592
593   const DetailInput kBillingPhoneInputs[] = {
594     { DetailInput::LONG,
595       PHONE_BILLING_WHOLE_NUMBER,
596       GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_PHONE_NUMBER) },
597   };
598
599   const DetailInput kEmailInputs[] = {
600     { DetailInput::LONG,
601       EMAIL_ADDRESS,
602       GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EMAIL) },
603   };
604
605   const DetailInput kShippingPhoneInputs[] = {
606     { DetailInput::LONG,
607       PHONE_HOME_WHOLE_NUMBER,
608       GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_PHONE_NUMBER) },
609   };
610
611   switch (dialog_section) {
612     case SECTION_CC: {
613       common::BuildInputs(kCCInputs, arraysize(kCCInputs), inputs);
614       break;
615     }
616
617     case SECTION_BILLING: {
618       i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_BILLING,
619                                     country_code, inputs, language_code);
620       common::BuildInputs(kBillingPhoneInputs, arraysize(kBillingPhoneInputs),
621                           inputs);
622       common::BuildInputs(kEmailInputs, arraysize(kEmailInputs), inputs);
623       break;
624     }
625
626     case SECTION_CC_BILLING: {
627       common::BuildInputs(kCCInputs, arraysize(kCCInputs), inputs);
628
629       // Wallet only supports US billing addresses.
630       const std::string hardcoded_country_code = "US";
631       i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_BILLING,
632                                     hardcoded_country_code,
633                                     inputs,
634                                     language_code);
635       DCHECK_EQ(inputs->back().type, ADDRESS_BILLING_COUNTRY);
636       inputs->back().length = DetailInput::NONE;
637       const std::string& app_locale =
638           g_browser_process->GetApplicationLocale();
639       inputs->back().initial_value =
640           AutofillCountry(hardcoded_country_code, app_locale).name();
641
642       common::BuildInputs(kBillingPhoneInputs, arraysize(kBillingPhoneInputs),
643                           inputs);
644       break;
645     }
646
647     case SECTION_SHIPPING: {
648       i18ninput::BuildAddressInputs(common::ADDRESS_TYPE_SHIPPING,
649                                     country_code, inputs, language_code);
650       common::BuildInputs(kShippingPhoneInputs, arraysize(kShippingPhoneInputs),
651                           inputs);
652       break;
653     }
654   }
655 }
656
657 }  // namespace
658
659 AutofillDialogViewDelegate::~AutofillDialogViewDelegate() {}
660
661 AutofillDialogControllerImpl::~AutofillDialogControllerImpl() {
662   if (popup_controller_)
663     popup_controller_->Hide();
664
665   GetMetricLogger().LogDialogInitialUserState(initial_user_state_);
666 }
667
668 bool CountryFilter(const std::set<base::string16>& possible_values,
669                    const std::string& country_code) {
670   if (!i18ninput::CountryIsFullySupported(country_code))
671     return false;
672
673   if (!possible_values.empty() &&
674       !possible_values.count(base::ASCIIToUTF16(country_code))) {
675     return false;
676   }
677
678   return true;
679 }
680
681 // static
682 base::WeakPtr<AutofillDialogControllerImpl>
683     AutofillDialogControllerImpl::Create(
684     content::WebContents* contents,
685     const FormData& form_structure,
686     const GURL& source_url,
687     const AutofillManagerDelegate::ResultCallback& callback) {
688   // AutofillDialogControllerImpl owns itself.
689   AutofillDialogControllerImpl* autofill_dialog_controller =
690       new AutofillDialogControllerImpl(contents,
691                                        form_structure,
692                                        source_url,
693                                        callback);
694   return autofill_dialog_controller->weak_ptr_factory_.GetWeakPtr();
695 }
696
697 // static
698 void AutofillDialogController::RegisterPrefs(PrefRegistrySimple* registry) {
699   registry->RegisterListPref(::prefs::kAutofillDialogWalletLocationAcceptance);
700 }
701
702 // static
703 void AutofillDialogController::RegisterProfilePrefs(
704     user_prefs::PrefRegistrySyncable* registry) {
705   registry->RegisterBooleanPref(
706       ::prefs::kAutofillDialogPayWithoutWallet,
707       false,
708       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
709   registry->RegisterDictionaryPref(
710       ::prefs::kAutofillDialogAutofillDefault,
711       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
712   registry->RegisterBooleanPref(
713       ::prefs::kAutofillDialogSaveData,
714       true,
715       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
716   registry->RegisterBooleanPref(
717       ::prefs::kAutofillDialogWalletShippingSameAsBilling,
718       false,
719       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
720 }
721
722 // static
723 base::WeakPtr<AutofillDialogController> AutofillDialogController::Create(
724     content::WebContents* contents,
725     const FormData& form_structure,
726     const GURL& source_url,
727     const AutofillManagerDelegate::ResultCallback& callback) {
728   return AutofillDialogControllerImpl::Create(contents,
729                                               form_structure,
730                                               source_url,
731                                               callback);
732 }
733
734 void AutofillDialogControllerImpl::Show() {
735   dialog_shown_timestamp_ = base::Time::Now();
736
737   // Determine what field types should be included in the dialog.
738   bool has_types = false;
739   bool has_sections = false;
740   form_structure_.ParseFieldTypesFromAutocompleteAttributes(
741       &has_types, &has_sections);
742
743   // Fail if the author didn't specify autocomplete types.
744   if (!has_types) {
745     callback_.Run(
746         AutofillManagerDelegate::AutocompleteResultErrorDisabled,
747         base::ASCIIToUTF16("Form is missing autocomplete attributes."),
748         NULL);
749     delete this;
750     return;
751   }
752
753   // Fail if the author didn't ask for at least some kind of credit card
754   // information.
755   bool has_credit_card_field = false;
756   for (size_t i = 0; i < form_structure_.field_count(); ++i) {
757     AutofillType type = form_structure_.field(i)->Type();
758     if (type.html_type() != HTML_TYPE_UNKNOWN && type.group() == CREDIT_CARD) {
759       has_credit_card_field = true;
760       break;
761     }
762   }
763
764   if (!has_credit_card_field) {
765     callback_.Run(
766         AutofillManagerDelegate::AutocompleteResultErrorDisabled,
767         base::ASCIIToUTF16("Form is not a payment form (must contain "
768                            "some autocomplete=\"cc-*\" fields). "),
769         NULL);
770     delete this;
771     return;
772   }
773
774   billing_country_combobox_model_.reset(new CountryComboboxModel(
775       *GetManager(),
776       base::Bind(CountryFilter,
777                  form_structure_.PossibleValues(ADDRESS_BILLING_COUNTRY))));
778   shipping_country_combobox_model_.reset(new CountryComboboxModel(
779       *GetManager(),
780       base::Bind(CountryFilter,
781                  form_structure_.PossibleValues(ADDRESS_HOME_COUNTRY))));
782
783   // Log any relevant UI metrics and security exceptions.
784   GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_SHOWN);
785
786   GetMetricLogger().LogDialogSecurityMetric(
787       AutofillMetrics::SECURITY_METRIC_DIALOG_SHOWN);
788
789   // The Autofill dialog is shown in response to a message from the renderer and
790   // as such, it can only be made in the context of the current document. A call
791   // to GetActiveEntry would return a pending entry, if there was one, which
792   // would be a security bug. Therefore, we use the last committed URL for the
793   // access checks.
794   const GURL& current_url = web_contents()->GetLastCommittedURL();
795   invoked_from_same_origin_ =
796       current_url.GetOrigin() == source_url_.GetOrigin();
797
798   if (!invoked_from_same_origin_) {
799     GetMetricLogger().LogDialogSecurityMetric(
800         AutofillMetrics::SECURITY_METRIC_CROSS_ORIGIN_FRAME);
801   }
802
803   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
804     DialogSection section = static_cast<DialogSection>(i);
805
806     std::string country_code;
807     CountryComboboxModel* model = CountryComboboxModelForSection(section);
808     if (model)
809       country_code = model->GetDefaultCountryCode();
810
811     DetailInputs* inputs = MutableRequestedFieldsForSection(section);
812     BuildInputsForSection(
813         section, country_code, inputs,
814         MutableAddressLanguageCodeForSection(section));
815   }
816
817   // Test whether we need to show the shipping section. If filling that section
818   // would be a no-op, don't show it.
819   cares_about_shipping_ = form_structure_.FillFields(
820       RequestedTypesForSection(SECTION_SHIPPING),
821       base::Bind(common::ServerTypeMatchesField, SECTION_SHIPPING),
822       base::Bind(NullGetInfo),
823       g_browser_process->GetApplicationLocale());
824
825   account_chooser_model_.reset(
826       new AccountChooserModel(this,
827                               profile_,
828                               !ShouldShowAccountChooser(),
829                               metric_logger_));
830
831   if (account_chooser_model_->WalletIsSelected())
832     FetchWalletCookie();
833
834   scoped_ptr< ::i18n::addressinput::Downloader> downloader(
835       new autofill::ChromeDownloaderImpl(profile_->GetRequestContext()));
836   validator_ = AddressValidator::Build(
837       downloader.Pass(),
838       ValidationRulesStorageFactory::CreateStorage(),
839       this);
840
841   SuggestionsUpdated();
842   SubmitButtonDelayBegin();
843   view_.reset(CreateView());
844   view_->Show();
845   GetManager()->AddObserver(this);
846
847   if (!account_chooser_model_->WalletIsSelected())
848     LogDialogLatencyToShow();
849 }
850
851 void AutofillDialogControllerImpl::Hide() {
852   if (view_)
853     view_->Hide();
854 }
855
856 void AutofillDialogControllerImpl::TabActivated() {
857   // If the user switched away from this tab and then switched back, reload the
858   // Wallet items, in case they've changed.
859   int64 seconds_elapsed_since_last_refresh =
860       (base::TimeTicks::Now() - last_wallet_items_fetch_timestamp_).InSeconds();
861   if (IsPayingWithWallet() && wallet_items_ &&
862       seconds_elapsed_since_last_refresh >= kWalletItemsRefreshRateSeconds) {
863     GetWalletItems();
864   }
865 }
866
867 ////////////////////////////////////////////////////////////////////////////////
868 // AutofillDialogViewDelegate implementation.
869
870 base::string16 AutofillDialogControllerImpl::DialogTitle() const {
871   if (ShouldShowSpinner())
872     return base::string16();
873
874   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TITLE);
875 }
876
877 base::string16 AutofillDialogControllerImpl::AccountChooserText() const {
878   if (!account_chooser_model_->WalletIsSelected())
879     return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PAYING_WITHOUT_WALLET);
880
881   if (SignedInState() == SIGNED_IN)
882     return account_chooser_model_->GetActiveWalletAccountName();
883
884   // In this case, the account chooser should be showing the signin link.
885   return base::string16();
886 }
887
888 base::string16 AutofillDialogControllerImpl::SignInLinkText() const {
889   int ids = SignedInState() == NOT_CHECKED ?
890       IDS_AUTOFILL_DIALOG_USE_WALLET_LINK :
891       ShouldShowSignInWebView() ? IDS_AUTOFILL_DIALOG_CANCEL_SIGN_IN :
892                                   IDS_AUTOFILL_DIALOG_SIGN_IN;
893
894   return l10n_util::GetStringUTF16(ids);
895 }
896
897 base::string16 AutofillDialogControllerImpl::SpinnerText() const {
898   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_LOADING);
899 }
900
901 base::string16 AutofillDialogControllerImpl::EditSuggestionText() const {
902   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EDIT);
903 }
904
905 base::string16 AutofillDialogControllerImpl::CancelButtonText() const {
906   return l10n_util::GetStringUTF16(IDS_CANCEL);
907 }
908
909 base::string16 AutofillDialogControllerImpl::ConfirmButtonText() const {
910   return l10n_util::GetStringUTF16(IsSubmitPausedOn(wallet::VERIFY_CVV) ?
911       IDS_AUTOFILL_DIALOG_VERIFY_BUTTON : IDS_AUTOFILL_DIALOG_SUBMIT_BUTTON);
912 }
913
914 base::string16 AutofillDialogControllerImpl::SaveLocallyText() const {
915   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX);
916 }
917
918 base::string16 AutofillDialogControllerImpl::SaveLocallyTooltip() const {
919   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_TOOLTIP);
920 }
921
922 base::string16 AutofillDialogControllerImpl::LegalDocumentsText() {
923   if (!IsPayingWithWallet() || ShouldShowSignInWebView())
924     return base::string16();
925
926   return legal_documents_text_;
927 }
928
929 bool AutofillDialogControllerImpl::ShouldShowSpinner() const {
930   return SignedInState() == REQUIRES_RESPONSE ||
931          SignedInState() == REQUIRES_PASSIVE_SIGN_IN;
932 }
933
934 bool AutofillDialogControllerImpl::ShouldShowAccountChooser() const {
935   return !ShouldShowSpinner() && GetManager()->IsCountryOfInterest("US");
936 }
937
938 bool AutofillDialogControllerImpl::ShouldShowSignInWebView() const {
939   return !signin_registrar_.IsEmpty();
940 }
941
942 GURL AutofillDialogControllerImpl::SignInUrl() const {
943   return wallet::GetSignInUrl();
944 }
945
946 bool AutofillDialogControllerImpl::ShouldOfferToSaveInChrome() const {
947   return IsAutofillEnabled() &&
948       !IsPayingWithWallet() &&
949       !profile_->IsOffTheRecord() &&
950       IsManuallyEditingAnySection() &&
951       !ShouldShowSpinner();
952 }
953
954 bool AutofillDialogControllerImpl::ShouldSaveInChrome() const {
955   return profile_->GetPrefs()->GetBoolean(::prefs::kAutofillDialogSaveData);
956 }
957
958 int AutofillDialogControllerImpl::GetDialogButtons() const {
959   if (waiting_for_explicit_sign_in_response_)
960     return ui::DIALOG_BUTTON_NONE;
961
962   if (ShouldShowSpinner() && !handling_use_wallet_link_click_)
963     return ui::DIALOG_BUTTON_CANCEL;
964
965   return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
966 }
967
968 bool AutofillDialogControllerImpl::IsDialogButtonEnabled(
969     ui::DialogButton button) const {
970   if (button == ui::DIALOG_BUTTON_OK) {
971     if (IsSubmitPausedOn(wallet::VERIFY_CVV))
972       return true;
973
974     if (ShouldShowSpinner() || is_submitting_)
975       return false;
976
977     if (submit_button_delay_timer_.IsRunning())
978       return false;
979
980     return true;
981   }
982
983   DCHECK_EQ(ui::DIALOG_BUTTON_CANCEL, button);
984   return !is_submitting_ || IsSubmitPausedOn(wallet::VERIFY_CVV);
985 }
986
987 DialogOverlayState AutofillDialogControllerImpl::GetDialogOverlay() {
988   bool show_wallet_interstitial = IsPayingWithWallet() && is_submitting_ &&
989       !(full_wallet_ && !full_wallet_->required_actions().empty());
990   if (!show_wallet_interstitial) {
991     card_scrambling_delay_.Stop();
992     card_scrambling_refresher_.Stop();
993     return DialogOverlayState();
994   }
995
996   ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
997   DialogOverlayState state;
998   state.string.font_list = rb->GetFontList(ui::ResourceBundle::MediumFont);
999
1000   const SkColor start_top_color = SkColorSetRGB(0xD6, 0xD6, 0xD6);
1001   const SkColor start_bottom_color = SkColorSetRGB(0x98, 0x98, 0x98);
1002   const SkColor final_top_color = SkColorSetRGB(0x52, 0x9F, 0xF8);
1003   const SkColor final_bottom_color = SkColorSetRGB(0x22, 0x75, 0xE5);
1004
1005   if (full_wallet_ && full_wallet_->required_actions().empty()) {
1006     card_scrambling_delay_.Stop();
1007     card_scrambling_refresher_.Stop();
1008
1009     base::string16 cc_number = base::ASCIIToUTF16(full_wallet_->GetPan());
1010     DCHECK_GE(cc_number.size(), 4U);
1011     state.image = GetGeneratedCardImage(
1012         base::ASCIIToUTF16("XXXX XXXX XXXX ") +
1013             cc_number.substr(cc_number.size() - 4),
1014         full_wallet_->billing_address()->recipient_name(),
1015         color_utils::AlphaBlend(
1016             final_top_color,
1017             start_top_color,
1018             255 * card_generated_animation_.GetCurrentValue()),
1019         color_utils::AlphaBlend(
1020             final_bottom_color,
1021             start_bottom_color,
1022             255 * card_generated_animation_.GetCurrentValue()));
1023
1024     state.string.text = l10n_util::GetStringUTF16(
1025         IDS_AUTOFILL_DIALOG_CARD_GENERATION_DONE);
1026   } else {
1027     // Start the refresher if it isn't running. Wait one second before pumping
1028     // updates to the view.
1029     if (!card_scrambling_delay_.IsRunning() &&
1030         !card_scrambling_refresher_.IsRunning()) {
1031       scrambled_card_number_ = GenerateRandomCardNumber();
1032       card_scrambling_delay_.Start(
1033           FROM_HERE,
1034           base::TimeDelta::FromSeconds(1),
1035           this,
1036           &AutofillDialogControllerImpl::StartCardScramblingRefresher);
1037     }
1038
1039     DCHECK(!scrambled_card_number_.empty());
1040     state.image = GetGeneratedCardImage(
1041         scrambled_card_number_,
1042         submitted_cardholder_name_,
1043         start_top_color,
1044         start_bottom_color);
1045
1046     // "Submitting" waiting page.
1047     state.string.text = l10n_util::GetStringUTF16(
1048         IDS_AUTOFILL_DIALOG_CARD_GENERATION_IN_PROGRESS);
1049   }
1050
1051   return state;
1052 }
1053
1054 const std::vector<gfx::Range>& AutofillDialogControllerImpl::
1055     LegalDocumentLinks() {
1056   return legal_document_link_ranges_;
1057 }
1058
1059 bool AutofillDialogControllerImpl::SectionIsActive(DialogSection section)
1060     const {
1061   if (IsSubmitPausedOn(wallet::VERIFY_CVV))
1062     return section == SECTION_CC_BILLING;
1063
1064   if (!FormStructureCaresAboutSection(section))
1065     return false;
1066
1067   if (IsPayingWithWallet())
1068     return section == SECTION_CC_BILLING || section == SECTION_SHIPPING;
1069
1070   return section != SECTION_CC_BILLING;
1071 }
1072
1073 void AutofillDialogControllerImpl::GetWalletItems() {
1074   ScopedViewUpdates updates(view_.get());
1075
1076   wallet_items_requested_ = true;
1077   wallet::WalletClient* wallet_client = GetWalletClient();
1078   wallet_client->CancelRequest();
1079
1080   previously_selected_instrument_id_.clear();
1081   previously_selected_shipping_address_id_.clear();
1082   if (wallet_items_) {
1083     previous_default_instrument_id_ = wallet_items_->default_instrument_id();
1084     previous_default_shipping_address_id_ = wallet_items_->default_address_id();
1085
1086     const wallet::WalletItems::MaskedInstrument* instrument =
1087         ActiveInstrument();
1088     if (instrument)
1089       previously_selected_instrument_id_ = instrument->object_id();
1090
1091     const wallet::Address* address = ActiveShippingAddress();
1092     if (address)
1093       previously_selected_shipping_address_id_ = address->object_id();
1094   }
1095
1096   last_wallet_items_fetch_timestamp_ = base::TimeTicks::Now();
1097   passive_failed_ = false;
1098   wallet_items_.reset();
1099
1100   // The "Loading..." page should be showing now, which should cause the
1101   // account chooser to hide.
1102   view_->UpdateAccountChooser();
1103   wallet_client->GetWalletItems();
1104 }
1105
1106 void AutofillDialogControllerImpl::HideSignIn() {
1107   ScopedViewUpdates updates(view_.get());
1108   signin_registrar_.RemoveAll();
1109   view_->HideSignIn();
1110   view_->UpdateAccountChooser();
1111 }
1112
1113 AutofillDialogControllerImpl::DialogSignedInState
1114     AutofillDialogControllerImpl::SignedInState() const {
1115   if (wallet_error_notification_)
1116     return SIGN_IN_DISABLED;
1117
1118   if (signin_helper_ || (wallet_items_requested_ && !wallet_items_))
1119     return REQUIRES_RESPONSE;
1120
1121   if (!wallet_items_requested_)
1122     return NOT_CHECKED;
1123
1124   if (wallet_items_->HasRequiredAction(wallet::GAIA_AUTH) ||
1125       passive_failed_) {
1126     return REQUIRES_SIGN_IN;
1127   }
1128
1129   if (wallet_items_->HasRequiredAction(wallet::PASSIVE_GAIA_AUTH))
1130     return REQUIRES_PASSIVE_SIGN_IN;
1131
1132   return SIGNED_IN;
1133 }
1134
1135 void AutofillDialogControllerImpl::SignedInStateUpdated() {
1136   if (!ShouldShowSpinner())
1137     waiting_for_explicit_sign_in_response_ = false;
1138
1139   switch (SignedInState()) {
1140     case SIGNED_IN:
1141       LogDialogLatencyToShow();
1142       break;
1143
1144     case REQUIRES_SIGN_IN:
1145       if (handling_use_wallet_link_click_)
1146         SignInLinkClicked();
1147       // Fall through.
1148     case SIGN_IN_DISABLED:
1149       // Switch to the local account and refresh the dialog.
1150       signin_helper_.reset();
1151       OnWalletSigninError();
1152       handling_use_wallet_link_click_ = false;
1153       break;
1154
1155     case REQUIRES_PASSIVE_SIGN_IN:
1156       // Attempt to passively sign in the user.
1157       DCHECK(!signin_helper_);
1158       signin_helper_.reset(new wallet::WalletSigninHelper(
1159           this,
1160           profile_->GetRequestContext()));
1161       signin_helper_->StartPassiveSignin(GetWalletClient()->user_index());
1162       break;
1163
1164     case NOT_CHECKED:
1165     case REQUIRES_RESPONSE:
1166       break;
1167   }
1168 }
1169
1170 void AutofillDialogControllerImpl::OnWalletOrSigninUpdate() {
1171   ScopedViewUpdates updates(view_.get());
1172   SignedInStateUpdated();
1173   SuggestionsUpdated();
1174   UpdateAccountChooserView();
1175
1176   if (view_) {
1177     view_->UpdateButtonStrip();
1178     view_->UpdateOverlay();
1179   }
1180
1181   // On the first successful response, compute the initial user state metric.
1182   if (initial_user_state_ == AutofillMetrics::DIALOG_USER_STATE_UNKNOWN)
1183     initial_user_state_ = GetInitialUserState();
1184 }
1185
1186 void AutofillDialogControllerImpl::OnWalletFormFieldError(
1187     const std::vector<wallet::FormFieldError>& form_field_errors) {
1188   if (form_field_errors.empty())
1189     return;
1190
1191   for (std::vector<wallet::FormFieldError>::const_iterator it =
1192            form_field_errors.begin();
1193        it != form_field_errors.end(); ++it) {
1194     if (it->error_type() == wallet::FormFieldError::UNKNOWN_ERROR ||
1195         it->GetAutofillType() == MAX_VALID_FIELD_TYPE ||
1196         it->location() == wallet::FormFieldError::UNKNOWN_LOCATION) {
1197       wallet_server_validation_recoverable_ = false;
1198       break;
1199     }
1200     DialogSection section = SectionFromLocation(it->location());
1201     wallet_errors_[section][it->GetAutofillType()] =
1202         std::make_pair(it->GetErrorMessage(),
1203                        GetValueFromSection(section, it->GetAutofillType()));
1204   }
1205
1206   // Unrecoverable validation errors.
1207   if (!wallet_server_validation_recoverable_)
1208     DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
1209
1210   UpdateForErrors();
1211 }
1212
1213 void AutofillDialogControllerImpl::ConstructLegalDocumentsText() {
1214   legal_documents_text_.clear();
1215   legal_document_link_ranges_.clear();
1216
1217   if (!wallet_items_)
1218     return;
1219
1220   PrefService* local_state = g_browser_process->local_state();
1221   // List of users who have accepted location sharing for fraud protection
1222   // on this device.
1223   const base::ListValue* accepted =
1224       local_state->GetList(::prefs::kAutofillDialogWalletLocationAcceptance);
1225   bool has_accepted_location_sharing =
1226       accepted->Find(base::StringValue(
1227           account_chooser_model_->GetActiveWalletAccountName())) !=
1228       accepted->end();
1229
1230   if (wallet_items_->legal_documents().empty()) {
1231     if (!has_accepted_location_sharing) {
1232       legal_documents_text_ = l10n_util::GetStringUTF16(
1233           IDS_AUTOFILL_DIALOG_LOCATION_DISCLOSURE);
1234     }
1235
1236     return;
1237   }
1238
1239   const std::vector<wallet::WalletItems::LegalDocument*>& documents =
1240       wallet_items_->legal_documents();
1241   // There should never be just one document because the privacy policy doc gets
1242   // tacked on the end of other documents.
1243   DCHECK_GE(documents.size(), 2U);
1244
1245   std::vector<base::string16> link_names;
1246   for (size_t i = 0; i < documents.size(); ++i) {
1247     link_names.push_back(documents[i]->display_name());
1248   }
1249
1250   int resource_id = 0;
1251   switch (documents.size()) {
1252     case 2U:
1253       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_2;
1254       break;
1255     case 3U:
1256       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_3;
1257       break;
1258     case 4U:
1259       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_4;
1260       break;
1261     case 5U:
1262       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_5;
1263       break;
1264     case 6U:
1265       resource_id = IDS_AUTOFILL_DIALOG_LEGAL_LINKS_6;
1266       break;
1267     default:
1268       // We can only handle so many documents. For lack of a better way of
1269       // handling document overflow, just error out if there are too many.
1270       DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
1271       return;
1272   }
1273
1274   std::vector<size_t> offsets;
1275   base::string16 text =
1276       l10n_util::GetStringFUTF16(resource_id, link_names,&offsets);
1277
1278   // Tack on the location string if need be.
1279   size_t base_offset = 0;
1280   if (!has_accepted_location_sharing) {
1281     text = l10n_util::GetStringFUTF16(
1282         IDS_AUTOFILL_DIALOG_LOCATION_DISCLOSURE_WITH_LEGAL_DOCS,
1283         text,
1284         &base_offset);
1285   }
1286
1287   for (size_t i = 0; i < documents.size(); ++i) {
1288     size_t link_start = offsets[i] + base_offset;
1289     legal_document_link_ranges_.push_back(gfx::Range(
1290         link_start, link_start + documents[i]->display_name().size()));
1291   }
1292   legal_documents_text_ = text;
1293 }
1294
1295 void AutofillDialogControllerImpl::ResetSectionInput(DialogSection section) {
1296   SetEditingExistingData(section, false);
1297   needs_validation_.erase(section);
1298
1299   CountryComboboxModel* model = CountryComboboxModelForSection(section);
1300   if (model) {
1301     base::string16 country = model->GetItemAt(model->GetDefaultIndex());
1302     RebuildInputsForCountry(section, country, false);
1303   }
1304
1305   DetailInputs* inputs = MutableRequestedFieldsForSection(section);
1306   for (DetailInputs::iterator it = inputs->begin();
1307        it != inputs->end(); ++it) {
1308     if (it->length != DetailInput::NONE) {
1309       it->initial_value.clear();
1310     } else if (!it->initial_value.empty() &&
1311                (it->type == ADDRESS_BILLING_COUNTRY ||
1312                 it->type == ADDRESS_HOME_COUNTRY)) {
1313       GetValidator()->LoadRules(AutofillCountry::GetCountryCode(
1314           it->initial_value, g_browser_process->GetApplicationLocale()));
1315     }
1316   }
1317 }
1318
1319 void AutofillDialogControllerImpl::ShowEditUiIfBadSuggestion(
1320     DialogSection section) {
1321   // |CreateWrapper()| returns an empty wrapper if |IsEditingExistingData()|, so
1322   // get the wrapper before this potentially happens below.
1323   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
1324
1325   // If the chosen item in |model| yields an empty suggestion text, it is
1326   // invalid. In this case, show the edit UI and highlight invalid fields.
1327   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1328   base::string16 unused, unused2;
1329   if (IsASuggestionItemKey(model->GetItemKeyForCheckedItem()) &&
1330       !SuggestionTextForSection(section, &unused, &unused2)) {
1331     SetEditingExistingData(section, true);
1332   }
1333
1334   if (wrapper && IsEditingExistingData(section)) {
1335     base::string16 country =
1336         wrapper->GetInfo(AutofillType(CountryTypeForSection(section)));
1337     if (!country.empty()) {
1338       // There's no user input to restore here as this is only called after
1339       // resetting all section input.
1340       if (RebuildInputsForCountry(section, country, false))
1341         UpdateSection(section);
1342     }
1343     wrapper->FillInputs(MutableRequestedFieldsForSection(section));
1344   }
1345 }
1346
1347 bool AutofillDialogControllerImpl::InputWasEdited(ServerFieldType type,
1348                                                   const base::string16& value) {
1349   if (value.empty())
1350     return false;
1351
1352   // If this is a combobox at the default value, don't preserve it.
1353   ui::ComboboxModel* model = ComboboxModelForAutofillType(type);
1354   if (model && model->GetItemAt(model->GetDefaultIndex()) == value)
1355     return false;
1356
1357   return true;
1358 }
1359
1360 FieldValueMap AutofillDialogControllerImpl::TakeUserInputSnapshot() {
1361   FieldValueMap snapshot;
1362   if (!view_)
1363     return snapshot;
1364
1365   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
1366     DialogSection section = static_cast<DialogSection>(i);
1367     SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1368     if (model->GetItemKeyForCheckedItem() != kAddNewItemKey)
1369       continue;
1370
1371     FieldValueMap outputs;
1372     view_->GetUserInput(section, &outputs);
1373     // Remove fields that are empty, at their default values, or invalid.
1374     for (FieldValueMap::iterator it = outputs.begin(); it != outputs.end();
1375          ++it) {
1376       if (InputWasEdited(it->first, it->second) &&
1377           InputValidityMessage(section, it->first, it->second).empty()) {
1378         snapshot.insert(std::make_pair(it->first, it->second));
1379       }
1380     }
1381   }
1382
1383   return snapshot;
1384 }
1385
1386 void AutofillDialogControllerImpl::RestoreUserInputFromSnapshot(
1387     const FieldValueMap& snapshot) {
1388   if (snapshot.empty())
1389     return;
1390
1391   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
1392     DialogSection section = static_cast<DialogSection>(i);
1393     if (!SectionIsActive(section))
1394       continue;
1395
1396     DetailInputs* inputs = MutableRequestedFieldsForSection(section);
1397     for (size_t i = 0; i < inputs->size(); ++i) {
1398       DetailInput* input = &(*inputs)[i];
1399       if (input->length != DetailInput::NONE) {
1400         input->initial_value =
1401             GetInfoFromInputs(snapshot, section, AutofillType(input->type));
1402       }
1403       if (InputWasEdited(input->type, input->initial_value))
1404         SuggestionsMenuModelForSection(section)->SetCheckedItem(kAddNewItemKey);
1405     }
1406   }
1407 }
1408
1409 void AutofillDialogControllerImpl::UpdateSection(DialogSection section) {
1410   if (view_)
1411     view_->UpdateSection(section);
1412 }
1413
1414 void AutofillDialogControllerImpl::UpdateForErrors() {
1415   if (!view_)
1416     return;
1417
1418   // Currently, the view should only need to be updated if there are
1419   // |wallet_errors_| or validating a suggestion that's based on existing data.
1420   bool should_update = !wallet_errors_.empty();
1421   if (!should_update) {
1422     for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
1423       if (IsEditingExistingData(static_cast<DialogSection>(i))) {
1424         should_update = true;
1425         break;
1426       }
1427     }
1428   }
1429
1430   if (should_update)
1431     view_->UpdateForErrors();
1432 }
1433
1434 gfx::Image AutofillDialogControllerImpl::GetGeneratedCardImage(
1435     const base::string16& card_number,
1436     const base::string16& name,
1437     const SkColor& gradient_top,
1438     const SkColor& gradient_bottom) {
1439   const int kCardWidthPx = 300;
1440   const int kCardHeightPx = 190;
1441   const gfx::Size size(kCardWidthPx, kCardHeightPx);
1442   ui::ScaleFactor scale_factor = ui::GetScaleFactorForNativeView(
1443       web_contents()->GetNativeView());
1444   gfx::Canvas canvas(size, ui::GetImageScale(scale_factor), false);
1445
1446   gfx::Rect display_rect(size);
1447
1448   skia::RefPtr<SkShader> shader = gfx::CreateGradientShader(
1449       0, size.height(), gradient_top, gradient_bottom);
1450   SkPaint paint;
1451   paint.setShader(shader.get());
1452   canvas.DrawRoundRect(display_rect, 8, paint);
1453
1454   display_rect.Inset(20, 0, 0, 0);
1455   gfx::Font font(l10n_util::GetStringUTF8(IDS_FIXED_FONT_FAMILY), 18);
1456   gfx::FontList font_list(font);
1457   gfx::ShadowValues shadows;
1458   shadows.push_back(gfx::ShadowValue(gfx::Point(0, 1), 1.0, SK_ColorBLACK));
1459   canvas.DrawStringRectWithShadows(
1460       card_number,
1461       font_list,
1462       SK_ColorWHITE,
1463       display_rect, 0, 0, shadows);
1464
1465   base::string16 capitalized_name = base::i18n::ToUpper(name);
1466   display_rect.Inset(0, size.height() / 2, 0, 0);
1467   canvas.DrawStringRectWithShadows(
1468       capitalized_name,
1469       font_list,
1470       SK_ColorWHITE,
1471       display_rect, 0, 0, shadows);
1472
1473   gfx::ImageSkia skia(canvas.ExtractImageRep());
1474   return gfx::Image(skia);
1475 }
1476
1477 void AutofillDialogControllerImpl::StartCardScramblingRefresher() {
1478   RefreshCardScramblingOverlay();
1479   card_scrambling_refresher_.Start(
1480       FROM_HERE,
1481       base::TimeDelta::FromMilliseconds(75),
1482       this,
1483       &AutofillDialogControllerImpl::RefreshCardScramblingOverlay);
1484 }
1485
1486 void AutofillDialogControllerImpl::RefreshCardScramblingOverlay() {
1487   scrambled_card_number_ = GenerateRandomCardNumber();
1488   PushOverlayUpdate();
1489 }
1490
1491 void AutofillDialogControllerImpl::PushOverlayUpdate() {
1492   if (view_) {
1493     ScopedViewUpdates updates(view_.get());
1494     view_->UpdateOverlay();
1495   }
1496 }
1497
1498 const DetailInputs& AutofillDialogControllerImpl::RequestedFieldsForSection(
1499     DialogSection section) const {
1500   switch (section) {
1501     case SECTION_CC:
1502       return requested_cc_fields_;
1503     case SECTION_BILLING:
1504       return requested_billing_fields_;
1505     case SECTION_CC_BILLING:
1506       return requested_cc_billing_fields_;
1507     case SECTION_SHIPPING:
1508       return requested_shipping_fields_;
1509   }
1510
1511   NOTREACHED();
1512   return requested_billing_fields_;
1513 }
1514
1515 ui::ComboboxModel* AutofillDialogControllerImpl::ComboboxModelForAutofillType(
1516     ServerFieldType type) {
1517   switch (type) {
1518     case CREDIT_CARD_EXP_MONTH:
1519       return &cc_exp_month_combobox_model_;
1520
1521     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
1522       return &cc_exp_year_combobox_model_;
1523
1524     case ADDRESS_BILLING_COUNTRY:
1525       return billing_country_combobox_model_.get();
1526
1527     case ADDRESS_HOME_COUNTRY:
1528       return shipping_country_combobox_model_.get();
1529
1530     default:
1531       return NULL;
1532   }
1533 }
1534
1535 ui::MenuModel* AutofillDialogControllerImpl::MenuModelForSection(
1536     DialogSection section) {
1537   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1538   // The shipping section menu is special. It will always show because there is
1539   // a choice between "Use billing" and "enter new".
1540   if (section == SECTION_SHIPPING)
1541     return model;
1542
1543   // For other sections, only show a menu if there's at least one suggestion.
1544   for (int i = 0; i < model->GetItemCount(); ++i) {
1545     if (IsASuggestionItemKey(model->GetItemKeyAt(i)))
1546       return model;
1547   }
1548
1549   return NULL;
1550 }
1551
1552 ui::MenuModel* AutofillDialogControllerImpl::MenuModelForAccountChooser() {
1553   // If there were unrecoverable Wallet errors, or if there are choices other
1554   // than "Pay without the wallet", show the full menu.
1555   // TODO(estade): this can present a braindead menu (only 1 option) when
1556   // there's a wallet error.
1557   if (wallet_error_notification_ ||
1558       (SignedInState() == SIGNED_IN &&
1559        account_chooser_model_->HasAccountsToChoose() &&
1560        !ShouldShowSignInWebView())) {
1561     return account_chooser_model_.get();
1562   }
1563
1564   // Otherwise, there is no menu, just a sign in link.
1565   return NULL;
1566 }
1567
1568 gfx::Image AutofillDialogControllerImpl::AccountChooserImage() {
1569   if (!MenuModelForAccountChooser() && !ShouldShowSignInWebView()) {
1570     return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1571         IDR_WALLET_ICON);
1572   }
1573
1574   return gfx::Image();
1575 }
1576
1577 gfx::Image AutofillDialogControllerImpl::ButtonStripImage() const {
1578   if (IsPayingWithWallet()) {
1579     return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1580         IDR_WALLET_LOGO);
1581   }
1582
1583   return gfx::Image();
1584 }
1585
1586 base::string16 AutofillDialogControllerImpl::LabelForSection(
1587     DialogSection section) const {
1588   switch (section) {
1589     case SECTION_CC:
1590       return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_CC);
1591     case SECTION_BILLING:
1592     case SECTION_CC_BILLING:
1593       return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_BILLING);
1594     case SECTION_SHIPPING:
1595       return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SECTION_SHIPPING);
1596   }
1597   NOTREACHED();
1598   return base::string16();
1599 }
1600
1601 SuggestionState AutofillDialogControllerImpl::SuggestionStateForSection(
1602     DialogSection section) {
1603   base::string16 vertically_compact, horizontally_compact;
1604   bool show_suggestion = SuggestionTextForSection(section,
1605                                                   &vertically_compact,
1606                                                   &horizontally_compact);
1607   return SuggestionState(show_suggestion,
1608                          vertically_compact,
1609                          horizontally_compact,
1610                          SuggestionIconForSection(section),
1611                          ExtraSuggestionTextForSection(section),
1612                          ExtraSuggestionIconForSection(section));
1613 }
1614
1615 bool AutofillDialogControllerImpl::SuggestionTextForSection(
1616     DialogSection section,
1617     base::string16* vertically_compact,
1618     base::string16* horizontally_compact) {
1619   base::string16 action_text = RequiredActionTextForSection(section);
1620   if (!action_text.empty()) {
1621     *vertically_compact = *horizontally_compact = action_text;
1622     return true;
1623   }
1624
1625   // When the user has clicked 'edit' or a suggestion is somehow invalid (e.g. a
1626   // user selects a credit card that has expired), don't show a suggestion (even
1627   // though there is a profile selected in the model).
1628   if (IsEditingExistingData(section))
1629     return false;
1630
1631   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1632   std::string item_key = model->GetItemKeyForCheckedItem();
1633   if (item_key == kSameAsBillingKey) {
1634     *vertically_compact = *horizontally_compact = l10n_util::GetStringUTF16(
1635         IDS_AUTOFILL_DIALOG_USING_BILLING_FOR_SHIPPING);
1636     return true;
1637   }
1638
1639   if (!IsASuggestionItemKey(item_key))
1640     return false;
1641
1642   if (!IsPayingWithWallet() &&
1643       (section == SECTION_BILLING || section == SECTION_SHIPPING)) {
1644     // Also check if the address is invalid (rules may have loaded since
1645     // the dialog was shown).
1646     if (HasInvalidAddress(*GetManager()->GetProfileByGUID(item_key)))
1647       return false;
1648   }
1649
1650   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
1651   return wrapper->GetDisplayText(vertically_compact, horizontally_compact);
1652 }
1653
1654 base::string16 AutofillDialogControllerImpl::RequiredActionTextForSection(
1655     DialogSection section) const {
1656   if (section == SECTION_CC_BILLING && IsSubmitPausedOn(wallet::VERIFY_CVV)) {
1657     const wallet::WalletItems::MaskedInstrument* current_instrument =
1658         wallet_items_->GetInstrumentById(active_instrument_id_);
1659     if (current_instrument)
1660       return current_instrument->TypeAndLastFourDigits();
1661
1662     FieldValueMap output;
1663     view_->GetUserInput(section, &output);
1664     CreditCard card;
1665     GetBillingInfoFromOutputs(output, &card, NULL, NULL);
1666     return card.TypeAndLastFourDigits();
1667   }
1668
1669   return base::string16();
1670 }
1671
1672 base::string16 AutofillDialogControllerImpl::ExtraSuggestionTextForSection(
1673     DialogSection section) const {
1674   if (section == SECTION_CC ||
1675       (section == SECTION_CC_BILLING && IsSubmitPausedOn(wallet::VERIFY_CVV))) {
1676     return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_CVC);
1677   }
1678
1679   return base::string16();
1680 }
1681
1682 const wallet::WalletItems::MaskedInstrument* AutofillDialogControllerImpl::
1683     ActiveInstrument() const {
1684   if (!IsPayingWithWallet())
1685     return NULL;
1686
1687   const SuggestionsMenuModel* model =
1688       SuggestionsMenuModelForSection(SECTION_CC_BILLING);
1689   const std::string item_key = model->GetItemKeyForCheckedItem();
1690   if (!IsASuggestionItemKey(item_key))
1691     return NULL;
1692
1693   int index;
1694   if (!base::StringToInt(item_key, &index) || index < 0 ||
1695       static_cast<size_t>(index) >= wallet_items_->instruments().size()) {
1696     NOTREACHED();
1697     return NULL;
1698   }
1699
1700   return wallet_items_->instruments()[index];
1701 }
1702
1703 const wallet::Address* AutofillDialogControllerImpl::
1704     ActiveShippingAddress() const {
1705   if (!IsPayingWithWallet() || !IsShippingAddressRequired())
1706     return NULL;
1707
1708   const SuggestionsMenuModel* model =
1709       SuggestionsMenuModelForSection(SECTION_SHIPPING);
1710   const std::string item_key = model->GetItemKeyForCheckedItem();
1711   if (!IsASuggestionItemKey(item_key))
1712     return NULL;
1713
1714   int index;
1715   if (!base::StringToInt(item_key, &index) || index < 0 ||
1716       static_cast<size_t>(index) >= wallet_items_->addresses().size()) {
1717     NOTREACHED();
1718     return NULL;
1719   }
1720
1721   return wallet_items_->addresses()[index];
1722 }
1723
1724 scoped_ptr<DataModelWrapper> AutofillDialogControllerImpl::CreateWrapper(
1725     DialogSection section) {
1726   if (IsPayingWithWallet() && full_wallet_ &&
1727       full_wallet_->required_actions().empty()) {
1728     if (section == SECTION_CC_BILLING) {
1729       return scoped_ptr<DataModelWrapper>(
1730           new FullWalletBillingWrapper(full_wallet_.get()));
1731     }
1732     if (section == SECTION_SHIPPING) {
1733       return scoped_ptr<DataModelWrapper>(
1734           new FullWalletShippingWrapper(full_wallet_.get()));
1735     }
1736   }
1737
1738   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
1739   std::string item_key = model->GetItemKeyForCheckedItem();
1740   if (!IsASuggestionItemKey(item_key) || IsManuallyEditingSection(section))
1741     return scoped_ptr<DataModelWrapper>();
1742
1743   if (IsPayingWithWallet()) {
1744     if (section == SECTION_CC_BILLING) {
1745       return scoped_ptr<DataModelWrapper>(
1746           new WalletInstrumentWrapper(ActiveInstrument()));
1747     }
1748
1749     if (section == SECTION_SHIPPING) {
1750       return scoped_ptr<DataModelWrapper>(
1751           new WalletAddressWrapper(ActiveShippingAddress()));
1752     }
1753
1754     return scoped_ptr<DataModelWrapper>();
1755   }
1756
1757   if (section == SECTION_CC) {
1758     CreditCard* card = GetManager()->GetCreditCardByGUID(item_key);
1759     DCHECK(card);
1760     return scoped_ptr<DataModelWrapper>(new AutofillCreditCardWrapper(card));
1761   }
1762
1763   AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
1764   DCHECK(profile);
1765   if (section == SECTION_SHIPPING) {
1766     return scoped_ptr<DataModelWrapper>(
1767         new AutofillShippingAddressWrapper(profile));
1768   }
1769   DCHECK_EQ(SECTION_BILLING, section);
1770   return scoped_ptr<DataModelWrapper>(
1771       new AutofillProfileWrapper(profile));
1772 }
1773
1774 gfx::Image AutofillDialogControllerImpl::SuggestionIconForSection(
1775     DialogSection section) {
1776   scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
1777   if (!model.get())
1778     return gfx::Image();
1779
1780   return model->GetIcon();
1781 }
1782
1783 gfx::Image AutofillDialogControllerImpl::ExtraSuggestionIconForSection(
1784     DialogSection section) {
1785   if (section != SECTION_CC && section != SECTION_CC_BILLING)
1786     return gfx::Image();
1787
1788   scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
1789   if (!model.get())
1790     return gfx::Image();
1791
1792   return CvcIconForCreditCardType(
1793       model->GetInfo(AutofillType(CREDIT_CARD_TYPE)));
1794 }
1795
1796 FieldIconMap AutofillDialogControllerImpl::IconsForFields(
1797     const FieldValueMap& user_inputs) const {
1798   FieldIconMap result;
1799   base::string16 credit_card_type;
1800
1801   FieldValueMap::const_iterator credit_card_iter =
1802       user_inputs.find(CREDIT_CARD_NUMBER);
1803   if (credit_card_iter != user_inputs.end()) {
1804     const base::string16& number = credit_card_iter->second;
1805     const std::string type = CreditCard::GetCreditCardType(number);
1806     credit_card_type = CreditCard::TypeForDisplay(type);
1807     result[CREDIT_CARD_NUMBER] = CreditCardIconForType(type);
1808   }
1809
1810   if (!user_inputs.count(CREDIT_CARD_VERIFICATION_CODE))
1811     return result;
1812
1813   result[CREDIT_CARD_VERIFICATION_CODE] =
1814       CvcIconForCreditCardType(credit_card_type);
1815
1816   return result;
1817 }
1818
1819 bool AutofillDialogControllerImpl::FieldControlsIcons(
1820     ServerFieldType type) const {
1821   return type == CREDIT_CARD_NUMBER;
1822 }
1823
1824 base::string16 AutofillDialogControllerImpl::TooltipForField(
1825     ServerFieldType type) const {
1826   if (type == PHONE_HOME_WHOLE_NUMBER || type == PHONE_BILLING_WHOLE_NUMBER)
1827     return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_TOOLTIP_PHONE_NUMBER);
1828
1829   return base::string16();
1830 }
1831
1832 bool AutofillDialogControllerImpl::InputIsEditable(
1833     const DetailInput& input,
1834     DialogSection section) {
1835   if (section != SECTION_CC_BILLING || !IsPayingWithWallet())
1836     return true;
1837
1838   if (input.type == CREDIT_CARD_NUMBER)
1839     return !IsEditingExistingData(section);
1840
1841   // For CVC, only require (allow) input if the user has edited some other
1842   // aspect of the card.
1843   if (input.type == CREDIT_CARD_VERIFICATION_CODE &&
1844       IsEditingExistingData(section)) {
1845     FieldValueMap output;
1846     view_->GetUserInput(section, &output);
1847     WalletInstrumentWrapper wrapper(ActiveInstrument());
1848
1849     for (FieldValueMap::iterator iter = output.begin(); iter != output.end();
1850          ++iter) {
1851       if (iter->first == input.type)
1852         continue;
1853
1854       AutofillType type(iter->first);
1855       if (type.group() == CREDIT_CARD &&
1856           iter->second != wrapper.GetInfo(type)) {
1857         return true;
1858       }
1859     }
1860
1861     return false;
1862   }
1863
1864   return true;
1865 }
1866
1867 // TODO(groby): Add more tests.
1868 base::string16 AutofillDialogControllerImpl::InputValidityMessage(
1869     DialogSection section,
1870     ServerFieldType type,
1871     const base::string16& value) {
1872   // If the field is edited, clear any Wallet errors.
1873   if (IsPayingWithWallet()) {
1874     WalletValidationErrors::iterator it = wallet_errors_.find(section);
1875     if (it != wallet_errors_.end()) {
1876       TypeErrorInputMap::const_iterator iter = it->second.find(type);
1877       if (iter != it->second.end()) {
1878         if (iter->second.second == value)
1879           return iter->second.first;
1880         it->second.erase(type);
1881       }
1882     }
1883   }
1884
1885   AutofillType autofill_type(type);
1886   if (autofill_type.group() == ADDRESS_HOME ||
1887       autofill_type.group() == ADDRESS_BILLING) {
1888     return base::string16();
1889   }
1890
1891   switch (autofill_type.GetStorableType()) {
1892     case EMAIL_ADDRESS:
1893       if (!value.empty() && !IsValidEmailAddress(value)) {
1894         return l10n_util::GetStringUTF16(
1895             IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_EMAIL_ADDRESS);
1896       }
1897       break;
1898
1899     case CREDIT_CARD_NUMBER: {
1900       if (!value.empty()) {
1901         base::string16 message = CreditCardNumberValidityMessage(value);
1902         if (!message.empty())
1903           return message;
1904       }
1905       break;
1906     }
1907
1908     case CREDIT_CARD_EXP_MONTH:
1909       if (!InputWasEdited(CREDIT_CARD_EXP_MONTH, value)) {
1910         return l10n_util::GetStringUTF16(
1911             IDS_LIBADDRESSINPUT_I18N_MISSING_REQUIRED_FIELD);
1912       }
1913       break;
1914
1915     case CREDIT_CARD_EXP_4_DIGIT_YEAR:
1916       if (!InputWasEdited(CREDIT_CARD_EXP_4_DIGIT_YEAR, value)) {
1917         return l10n_util::GetStringUTF16(
1918             IDS_LIBADDRESSINPUT_I18N_MISSING_REQUIRED_FIELD);
1919       }
1920       break;
1921
1922     case CREDIT_CARD_VERIFICATION_CODE:
1923       if (!value.empty() && !autofill::IsValidCreditCardSecurityCode(value)) {
1924         return l10n_util::GetStringUTF16(
1925             IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_SECURITY_CODE);
1926       }
1927       break;
1928
1929     case NAME_FULL:
1930       // Wallet requires a first and last billing name.
1931       if (IsPayingWithWallet() && !value.empty() &&
1932           !IsCardHolderNameValidForWallet(value)) {
1933         return l10n_util::GetStringUTF16(
1934             IDS_AUTOFILL_DIALOG_VALIDATION_WALLET_REQUIRES_TWO_NAMES);
1935       }
1936       break;
1937
1938     case PHONE_HOME_WHOLE_NUMBER:  // Used in shipping section.
1939       break;
1940
1941     case PHONE_BILLING_WHOLE_NUMBER:  // Used in billing section.
1942       break;
1943
1944     default:
1945       NOTREACHED();  // Trying to validate unknown field.
1946       break;
1947   }
1948
1949   return value.empty() ? l10n_util::GetStringUTF16(
1950                              IDS_LIBADDRESSINPUT_I18N_MISSING_REQUIRED_FIELD) :
1951                          base::string16();
1952 }
1953
1954 // TODO(groby): Also add tests.
1955 ValidityMessages AutofillDialogControllerImpl::InputsAreValid(
1956     DialogSection section,
1957     const FieldValueMap& inputs) {
1958   ValidityMessages messages;
1959   if (inputs.empty())
1960     return messages;
1961
1962   AddressValidator::Status status = AddressValidator::SUCCESS;
1963   if (section != SECTION_CC) {
1964     AutofillProfile profile;
1965     FillFormGroupFromOutputs(inputs, &profile);
1966     AddressData address_data;
1967     i18ninput::CreateAddressData(base::Bind(&GetInfoFromProfile, profile),
1968                                  &address_data);
1969     address_data.language_code = AddressLanguageCodeForSection(section);
1970
1971     AddressProblems problems;
1972     status = GetValidator()->ValidateAddress(address_data,
1973                                              AddressProblemFilter(),
1974                                              &problems);
1975     common::AddressType address_type = section == SECTION_SHIPPING ?
1976         common::ADDRESS_TYPE_SHIPPING : common::ADDRESS_TYPE_BILLING;
1977     for (size_t i = 0; i < problems.size(); ++i) {
1978       const AddressProblem& problem = problems[i];
1979       bool sure = problem.type != AddressProblem::MISSING_REQUIRED_FIELD;
1980       base::string16 text = l10n_util::GetStringUTF16(problem.description_id);
1981       messages.Set(i18ninput::TypeForField(problem.field, address_type),
1982                    ValidityMessage(text, sure));
1983     }
1984   }
1985
1986   for (FieldValueMap::const_iterator iter = inputs.begin();
1987        iter != inputs.end(); ++iter) {
1988     const ServerFieldType type = iter->first;
1989     base::string16 text = InputValidityMessage(section, type, iter->second);
1990
1991     // Skip empty/unchanged fields in edit mode. If the individual field does
1992     // not have validation errors, assume it to be valid unless later proven
1993     // otherwise.
1994     bool sure = InputWasEdited(type, iter->second);
1995
1996     if (sure && status == AddressValidator::RULES_NOT_READY &&
1997         !ComboboxModelForAutofillType(type) &&
1998         (AutofillType(type).group() == ADDRESS_HOME ||
1999          AutofillType(type).group() == ADDRESS_BILLING)) {
2000       DCHECK(text.empty());
2001       text = l10n_util::GetStringUTF16(
2002           IDS_AUTOFILL_DIALOG_VALIDATION_WAITING_FOR_RULES);
2003       sure = false;
2004       needs_validation_.insert(section);
2005     }
2006
2007     messages.Set(type, ValidityMessage(text, sure));
2008   }
2009
2010   // For the convenience of using operator[].
2011   FieldValueMap& field_values = const_cast<FieldValueMap&>(inputs);
2012   // Validate the date formed by month and year field. (Autofill dialog is
2013   // never supposed to have 2-digit years, so not checked).
2014   if (field_values.count(CREDIT_CARD_EXP_4_DIGIT_YEAR) &&
2015       field_values.count(CREDIT_CARD_EXP_MONTH) &&
2016       InputWasEdited(CREDIT_CARD_EXP_4_DIGIT_YEAR,
2017                      field_values[CREDIT_CARD_EXP_4_DIGIT_YEAR]) &&
2018       InputWasEdited(CREDIT_CARD_EXP_MONTH,
2019                      field_values[CREDIT_CARD_EXP_MONTH])) {
2020     ValidityMessage year_message(base::string16(), true);
2021     ValidityMessage month_message(base::string16(), true);
2022     if (!IsCreditCardExpirationValid(field_values[CREDIT_CARD_EXP_4_DIGIT_YEAR],
2023                                      field_values[CREDIT_CARD_EXP_MONTH])) {
2024       // The dialog shows the same error message for the month and year fields.
2025       year_message.text = l10n_util::GetStringUTF16(
2026           IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_DATE);
2027       month_message.text = l10n_util::GetStringUTF16(
2028           IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_EXPIRATION_DATE);
2029     }
2030     messages.Set(CREDIT_CARD_EXP_4_DIGIT_YEAR, year_message);
2031     messages.Set(CREDIT_CARD_EXP_MONTH, month_message);
2032   }
2033
2034   // If there is a credit card number and a CVC, validate them together.
2035   if (field_values.count(CREDIT_CARD_NUMBER) &&
2036       field_values.count(CREDIT_CARD_VERIFICATION_CODE)) {
2037     ValidityMessage ccv_message(base::string16(), true);
2038     if (!autofill::IsValidCreditCardSecurityCode(
2039             field_values[CREDIT_CARD_VERIFICATION_CODE],
2040             field_values[CREDIT_CARD_NUMBER])) {
2041       ccv_message.text = l10n_util::GetStringUTF16(
2042           IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_SECURITY_CODE);
2043     }
2044     messages.Set(CREDIT_CARD_VERIFICATION_CODE, ccv_message);
2045   }
2046
2047   // Validate the shipping phone number against the country code of the address.
2048   if (field_values.count(ADDRESS_HOME_COUNTRY) &&
2049       field_values.count(PHONE_HOME_WHOLE_NUMBER)) {
2050     messages.Set(
2051         PHONE_HOME_WHOLE_NUMBER,
2052         GetPhoneValidityMessage(field_values[ADDRESS_HOME_COUNTRY],
2053                                 field_values[PHONE_HOME_WHOLE_NUMBER]));
2054   }
2055
2056   // Validate the billing phone number against the country code of the address.
2057   if (field_values.count(ADDRESS_BILLING_COUNTRY) &&
2058       field_values.count(PHONE_BILLING_WHOLE_NUMBER)) {
2059     messages.Set(
2060         PHONE_BILLING_WHOLE_NUMBER,
2061         GetPhoneValidityMessage(field_values[ADDRESS_BILLING_COUNTRY],
2062                                 field_values[PHONE_BILLING_WHOLE_NUMBER]));
2063   }
2064
2065   return messages;
2066 }
2067
2068 void AutofillDialogControllerImpl::UserEditedOrActivatedInput(
2069     DialogSection section,
2070     ServerFieldType type,
2071     gfx::NativeView parent_view,
2072     const gfx::Rect& content_bounds,
2073     const base::string16& field_contents,
2074     bool was_edit) {
2075   ScopedViewUpdates updates(view_.get());
2076
2077   if (type == ADDRESS_BILLING_COUNTRY || type == ADDRESS_HOME_COUNTRY) {
2078     const FieldValueMap& snapshot = TakeUserInputSnapshot();
2079
2080     // Clobber the inputs because the view's already been updated.
2081     RebuildInputsForCountry(section, field_contents, true);
2082     RestoreUserInputFromSnapshot(snapshot);
2083     UpdateSection(section);
2084   }
2085
2086   // The rest of this method applies only to textfields while Autofill is
2087   // enabled. If a combobox or Autofill is disabled, bail.
2088   if (ComboboxModelForAutofillType(type) || !IsAutofillEnabled())
2089     return;
2090
2091   // If the field is edited down to empty, don't show a popup.
2092   if (was_edit && field_contents.empty()) {
2093     HidePopup();
2094     return;
2095   }
2096
2097   // If the user clicks while the popup is already showing, be sure to hide
2098   // it.
2099   if (!was_edit && popup_controller_.get()) {
2100     HidePopup();
2101     return;
2102   }
2103
2104   std::vector<base::string16> popup_values, popup_labels, popup_icons;
2105   if (common::IsCreditCardType(type)) {
2106     GetManager()->GetCreditCardSuggestions(AutofillType(type),
2107                                            field_contents,
2108                                            &popup_values,
2109                                            &popup_labels,
2110                                            &popup_icons,
2111                                            &popup_guids_);
2112   } else {
2113     GetManager()->GetProfileSuggestions(
2114         AutofillType(type),
2115         field_contents,
2116         false,
2117         RequestedTypesForSection(section),
2118         base::Bind(&AutofillDialogControllerImpl::ShouldSuggestProfile,
2119                    base::Unretained(this), section),
2120         &popup_values,
2121         &popup_labels,
2122         &popup_icons,
2123         &popup_guids_);
2124
2125     GetI18nValidatorSuggestions(section, type, &popup_values, &popup_labels,
2126                                 &popup_icons);
2127   }
2128
2129   if (popup_values.empty()) {
2130     HidePopup();
2131     return;
2132   }
2133
2134   // |popup_input_type_| must be set before calling |Show()|.
2135   popup_input_type_ = type;
2136
2137   // TODO(estade): do we need separators and control rows like 'Clear
2138   // Form'?
2139   std::vector<int> popup_ids;
2140   for (size_t i = 0; i < popup_values.size(); ++i) {
2141     popup_ids.push_back(i);
2142   }
2143
2144   popup_controller_ = AutofillPopupControllerImpl::GetOrCreate(
2145       popup_controller_,
2146       weak_ptr_factory_.GetWeakPtr(),
2147       NULL,
2148       parent_view,
2149       content_bounds,
2150       base::i18n::IsRTL() ?
2151           base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT);
2152   popup_controller_->Show(popup_values,
2153                           popup_labels,
2154                           popup_icons,
2155                           popup_ids);
2156 }
2157
2158 void AutofillDialogControllerImpl::FocusMoved() {
2159   HidePopup();
2160 }
2161
2162 bool AutofillDialogControllerImpl::ShouldShowErrorBubble() const {
2163   return popup_input_type_ == UNKNOWN_TYPE;
2164 }
2165
2166 void AutofillDialogControllerImpl::ViewClosed() {
2167   GetManager()->RemoveObserver(this);
2168
2169   // Called from here rather than in ~AutofillDialogControllerImpl as this
2170   // relies on virtual methods that change to their base class in the dtor.
2171   MaybeShowCreditCardBubble();
2172
2173   delete this;
2174 }
2175
2176 std::vector<DialogNotification> AutofillDialogControllerImpl::
2177     CurrentNotifications() {
2178   std::vector<DialogNotification> notifications;
2179
2180   // TODO(dbeam): figure out a way to dismiss this error after a while.
2181   if (wallet_error_notification_)
2182     notifications.push_back(*wallet_error_notification_);
2183
2184   if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
2185     notifications.push_back(DialogNotification(
2186         DialogNotification::REQUIRED_ACTION,
2187         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_VERIFY_CVV)));
2188   }
2189
2190   if (!wallet_server_validation_recoverable_) {
2191     notifications.push_back(DialogNotification(
2192         DialogNotification::REQUIRED_ACTION,
2193         l10n_util::GetStringUTF16(
2194             IDS_AUTOFILL_DIALOG_FAILED_TO_SAVE_WALLET_DATA)));
2195   }
2196
2197   if (choose_another_instrument_or_address_) {
2198     notifications.push_back(DialogNotification(
2199         DialogNotification::REQUIRED_ACTION,
2200         l10n_util::GetStringUTF16(
2201             IDS_AUTOFILL_DIALOG_CHOOSE_DIFFERENT_WALLET_INSTRUMENT)));
2202   }
2203
2204   if (notifications.empty() && MenuModelForAccountChooser()) {
2205     base::string16 text = l10n_util::GetStringUTF16(
2206         IsManuallyEditingAnySection() ?
2207             IDS_AUTOFILL_DIALOG_SAVE_DETAILS_IN_WALLET :
2208             IDS_AUTOFILL_DIALOG_USE_WALLET);
2209     DialogNotification notification(
2210         DialogNotification::WALLET_USAGE_CONFIRMATION,
2211         text);
2212     notification.set_tooltip_text(
2213         l10n_util::GetStringUTF16(
2214             IDS_AUTOFILL_DIALOG_SAVE_IN_WALLET_TOOLTIP));
2215     notification.set_checked(IsPayingWithWallet());
2216     notifications.push_back(notification);
2217   }
2218
2219   if (IsPayingWithWallet() && !wallet::IsUsingProd()) {
2220     notifications.push_back(DialogNotification(
2221         DialogNotification::DEVELOPER_WARNING,
2222         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_NOT_PROD_WARNING)));
2223   }
2224
2225   if (!invoked_from_same_origin_) {
2226     notifications.push_back(DialogNotification(
2227         DialogNotification::SECURITY_WARNING,
2228         l10n_util::GetStringFUTF16(IDS_AUTOFILL_DIALOG_SITE_WARNING,
2229                                    base::UTF8ToUTF16(source_url_.host()))));
2230   }
2231
2232   return notifications;
2233 }
2234
2235 void AutofillDialogControllerImpl::LinkClicked(const GURL& url) {
2236   OpenTabWithUrl(url);
2237 }
2238
2239 void AutofillDialogControllerImpl::SignInLinkClicked() {
2240   ScopedViewUpdates updates(view_.get());
2241
2242   if (SignedInState() == NOT_CHECKED) {
2243     handling_use_wallet_link_click_ = true;
2244     account_chooser_model_->SelectWalletAccount(0);
2245     FetchWalletCookie();
2246   } else if (signin_registrar_.IsEmpty()) {
2247     // Start sign in.
2248     waiting_for_explicit_sign_in_response_ = true;
2249     content::Source<content::NavigationController> source(view_->ShowSignIn());
2250     signin_registrar_.Add(
2251         this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source);
2252
2253     GetMetricLogger().LogDialogUiEvent(
2254         AutofillMetrics::DIALOG_UI_SIGNIN_SHOWN);
2255   } else {
2256     waiting_for_explicit_sign_in_response_ = false;
2257     HideSignIn();
2258   }
2259
2260   view_->UpdateAccountChooser();
2261   view_->UpdateButtonStrip();
2262 }
2263
2264 void AutofillDialogControllerImpl::NotificationCheckboxStateChanged(
2265     DialogNotification::Type type, bool checked) {
2266   if (type == DialogNotification::WALLET_USAGE_CONFIRMATION) {
2267     if (checked) {
2268       account_chooser_model_->SelectWalletAccount(
2269           GetWalletClient()->user_index());
2270     } else {
2271       account_chooser_model_->SelectUseAutofill();
2272     }
2273
2274     AccountChoiceChanged();
2275   }
2276 }
2277
2278 void AutofillDialogControllerImpl::LegalDocumentLinkClicked(
2279     const gfx::Range& range) {
2280   for (size_t i = 0; i < legal_document_link_ranges_.size(); ++i) {
2281     if (legal_document_link_ranges_[i] == range) {
2282       OpenTabWithUrl(wallet_items_->legal_documents()[i]->url());
2283       return;
2284     }
2285   }
2286
2287   NOTREACHED();
2288 }
2289
2290 bool AutofillDialogControllerImpl::OnCancel() {
2291   HidePopup();
2292   if (!is_submitting_)
2293     LogOnCancelMetrics();
2294   callback_.Run(AutofillManagerDelegate::AutocompleteResultErrorCancel,
2295                 base::string16(),
2296                 NULL);
2297   return true;
2298 }
2299
2300 bool AutofillDialogControllerImpl::OnAccept() {
2301   ScopedViewUpdates updates(view_.get());
2302   choose_another_instrument_or_address_ = false;
2303   wallet_server_validation_recoverable_ = true;
2304   HidePopup();
2305
2306   // This must come before SetIsSubmitting().
2307   if (IsPayingWithWallet()) {
2308     // In the VERIFY_CVV case, hold onto the previously submitted cardholder
2309     // name.
2310     if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
2311       submitted_cardholder_name_ =
2312           GetValueFromSection(SECTION_CC_BILLING, NAME_BILLING_FULL);
2313
2314       // Snag the last four digits of the backing card now as it could be wiped
2315       // out if a CVC challenge happens.
2316       if (ActiveInstrument()) {
2317         backing_card_last_four_ = ActiveInstrument()->TypeAndLastFourDigits();
2318       } else {
2319         FieldValueMap output;
2320         view_->GetUserInput(SECTION_CC_BILLING, &output);
2321         CreditCard card;
2322         GetBillingInfoFromOutputs(output, &card, NULL, NULL);
2323         backing_card_last_four_ = card.TypeAndLastFourDigits();
2324       }
2325     }
2326     DCHECK(!submitted_cardholder_name_.empty());
2327     DCHECK(!backing_card_last_four_.empty());
2328   }
2329
2330   SetIsSubmitting(true);
2331
2332   if (IsSubmitPausedOn(wallet::VERIFY_CVV)) {
2333     DCHECK(!active_instrument_id_.empty());
2334     full_wallet_.reset();
2335     GetWalletClient()->AuthenticateInstrument(
2336         active_instrument_id_,
2337         base::UTF16ToUTF8(view_->GetCvc()));
2338     view_->UpdateOverlay();
2339   } else if (IsPayingWithWallet()) {
2340     AcceptLegalTerms();
2341   } else {
2342     FinishSubmit();
2343   }
2344
2345   return false;
2346 }
2347
2348 Profile* AutofillDialogControllerImpl::profile() {
2349   return profile_;
2350 }
2351
2352 content::WebContents* AutofillDialogControllerImpl::GetWebContents() {
2353   return web_contents();
2354 }
2355
2356 ////////////////////////////////////////////////////////////////////////////////
2357 // AutofillPopupDelegate implementation.
2358
2359 void AutofillDialogControllerImpl::OnPopupShown() {
2360   ScopedViewUpdates update(view_.get());
2361   view_->UpdateErrorBubble();
2362
2363   GetMetricLogger().LogDialogPopupEvent(AutofillMetrics::DIALOG_POPUP_SHOWN);
2364 }
2365
2366 void AutofillDialogControllerImpl::OnPopupHidden() {}
2367
2368 void AutofillDialogControllerImpl::DidSelectSuggestion(
2369     const base::string16& value,
2370     int identifier) {
2371   // TODO(estade): implement.
2372 }
2373
2374 void AutofillDialogControllerImpl::DidAcceptSuggestion(
2375     const base::string16& value,
2376     int identifier) {
2377   DCHECK_NE(UNKNOWN_TYPE, popup_input_type_);
2378   // Because |HidePopup()| can be called from |UpdateSection()|, remember the
2379   // type of the input for later here.
2380   const ServerFieldType popup_input_type = popup_input_type_;
2381
2382   ScopedViewUpdates updates(view_.get());
2383   scoped_ptr<DataModelWrapper> wrapper;
2384
2385   if (static_cast<size_t>(identifier) < popup_guids_.size()) {
2386     const PersonalDataManager::GUIDPair& pair = popup_guids_[identifier];
2387     if (common::IsCreditCardType(popup_input_type)) {
2388       wrapper.reset(new AutofillCreditCardWrapper(
2389           GetManager()->GetCreditCardByGUID(pair.first)));
2390     } else {
2391       wrapper.reset(new AutofillProfileWrapper(
2392           GetManager()->GetProfileByGUID(pair.first),
2393           AutofillType(popup_input_type),
2394           pair.second));
2395     }
2396   } else {
2397     wrapper.reset(new I18nAddressDataWrapper(
2398         &i18n_validator_suggestions_[identifier - popup_guids_.size()]));
2399   }
2400
2401   // If the user hasn't switched away from the default country and |wrapper|'s
2402   // country differs from the |view_|'s, rebuild inputs and restore user data.
2403   const FieldValueMap snapshot = TakeUserInputSnapshot();
2404   bool billing_rebuilt = false, shipping_rebuilt = false;
2405
2406   base::string16 billing_country =
2407       wrapper->GetInfo(AutofillType(ADDRESS_BILLING_COUNTRY));
2408   if (!snapshot.count(ADDRESS_BILLING_COUNTRY) &&
2409       !billing_country.empty()) {
2410     billing_rebuilt = RebuildInputsForCountry(
2411         ActiveBillingSection(), billing_country, false);
2412   }
2413
2414   base::string16 shipping_country =
2415       wrapper->GetInfo(AutofillType(ADDRESS_HOME_COUNTRY));
2416   if (!snapshot.count(ADDRESS_HOME_COUNTRY) &&
2417       !shipping_country.empty()) {
2418     shipping_rebuilt = RebuildInputsForCountry(
2419         SECTION_SHIPPING, shipping_country, false);
2420   }
2421
2422   if (billing_rebuilt || shipping_rebuilt) {
2423     RestoreUserInputFromSnapshot(snapshot);
2424     if (billing_rebuilt)
2425       UpdateSection(ActiveBillingSection());
2426     if (shipping_rebuilt)
2427       UpdateSection(SECTION_SHIPPING);
2428   }
2429
2430   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
2431     DialogSection section = static_cast<DialogSection>(i);
2432     if (!SectionIsActive(section))
2433       continue;
2434
2435     wrapper->FillInputs(MutableRequestedFieldsForSection(section));
2436     view_->FillSection(section, popup_input_type);
2437   }
2438
2439   GetMetricLogger().LogDialogPopupEvent(
2440       AutofillMetrics::DIALOG_POPUP_FORM_FILLED);
2441
2442   // TODO(estade): not sure why it's necessary to do this explicitly.
2443   HidePopup();
2444 }
2445
2446 void AutofillDialogControllerImpl::RemoveSuggestion(
2447     const base::string16& value,
2448     int identifier) {
2449   // TODO(estade): implement.
2450 }
2451
2452 void AutofillDialogControllerImpl::ClearPreviewedForm() {
2453   // TODO(estade): implement.
2454 }
2455
2456 ////////////////////////////////////////////////////////////////////////////////
2457 // content::NotificationObserver implementation.
2458
2459 void AutofillDialogControllerImpl::Observe(
2460     int type,
2461     const content::NotificationSource& source,
2462     const content::NotificationDetails& details) {
2463   DCHECK_EQ(type, content::NOTIFICATION_NAV_ENTRY_COMMITTED);
2464   content::LoadCommittedDetails* load_details =
2465       content::Details<content::LoadCommittedDetails>(details).ptr();
2466   size_t user_index = 0;
2467   if (IsSignInContinueUrl(load_details->entry->GetVirtualURL(), &user_index)) {
2468     GetWalletClient()->SetUserIndex(user_index);
2469     FetchWalletCookie();
2470
2471     // NOTE: |HideSignIn()| may delete the WebContents which doesn't expect to
2472     // be deleted while committing a nav entry. Just call |HideSignIn()| later.
2473     base::MessageLoop::current()->PostTask(FROM_HERE,
2474         base::Bind(&AutofillDialogControllerImpl::HideSignIn,
2475                    base::Unretained(this)));
2476   }
2477 }
2478
2479 ////////////////////////////////////////////////////////////////////////////////
2480 // SuggestionsMenuModelDelegate implementation.
2481
2482 void AutofillDialogControllerImpl::SuggestionItemSelected(
2483     SuggestionsMenuModel* model,
2484     size_t index) {
2485   ScopedViewUpdates updates(view_.get());
2486
2487   if (model->GetItemKeyAt(index) == kManageItemsKey) {
2488     GURL url;
2489     if (!IsPayingWithWallet()) {
2490       DCHECK(IsAutofillEnabled());
2491       GURL settings_url(chrome::kChromeUISettingsURL);
2492       url = settings_url.Resolve(chrome::kAutofillSubPage);
2493     } else {
2494       // Reset |last_wallet_items_fetch_timestamp_| to ensure that the Wallet
2495       // data is refreshed as soon as the user switches back to this tab after
2496       // potentially editing his data.
2497       last_wallet_items_fetch_timestamp_ = base::TimeTicks();
2498       size_t user_index = GetWalletClient()->user_index();
2499       url = SectionForSuggestionsMenuModel(*model) == SECTION_SHIPPING ?
2500           wallet::GetManageAddressesUrl(user_index) :
2501           wallet::GetManageInstrumentsUrl(user_index);
2502     }
2503
2504     OpenTabWithUrl(url);
2505     return;
2506   }
2507
2508   model->SetCheckedIndex(index);
2509   DialogSection section = SectionForSuggestionsMenuModel(*model);
2510
2511   ResetSectionInput(section);
2512   ShowEditUiIfBadSuggestion(section);
2513   UpdateSection(section);
2514   view_->UpdateNotificationArea();
2515   UpdateForErrors();
2516
2517   LogSuggestionItemSelectedMetric(*model);
2518 }
2519
2520 ////////////////////////////////////////////////////////////////////////////////
2521 // wallet::WalletClientDelegate implementation.
2522
2523 const AutofillMetrics& AutofillDialogControllerImpl::GetMetricLogger() const {
2524   return metric_logger_;
2525 }
2526
2527 std::string AutofillDialogControllerImpl::GetRiskData() const {
2528   DCHECK(!risk_data_.empty());
2529   return risk_data_;
2530 }
2531
2532 std::string AutofillDialogControllerImpl::GetWalletCookieValue() const {
2533   return wallet_cookie_value_;
2534 }
2535
2536 bool AutofillDialogControllerImpl::IsShippingAddressRequired() const {
2537   return cares_about_shipping_;
2538 }
2539
2540 void AutofillDialogControllerImpl::OnDidAcceptLegalDocuments() {
2541   DCHECK(is_submitting_ && IsPayingWithWallet());
2542   has_accepted_legal_documents_ = true;
2543   LoadRiskFingerprintData();
2544 }
2545
2546 void AutofillDialogControllerImpl::OnDidAuthenticateInstrument(bool success) {
2547   DCHECK(is_submitting_ && IsPayingWithWallet());
2548
2549   // TODO(dbeam): use the returned full wallet. http://crbug.com/224992
2550   if (success) {
2551     GetFullWallet();
2552   } else {
2553     DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
2554     SuggestionsUpdated();
2555   }
2556 }
2557
2558 void AutofillDialogControllerImpl::OnDidGetFullWallet(
2559     scoped_ptr<wallet::FullWallet> full_wallet) {
2560   DCHECK(is_submitting_ && IsPayingWithWallet());
2561   ScopedViewUpdates updates(view_.get());
2562
2563   full_wallet_ = full_wallet.Pass();
2564
2565   if (full_wallet_->required_actions().empty()) {
2566     FinishSubmit();
2567     return;
2568   }
2569
2570   switch (full_wallet_->required_actions()[0]) {
2571     case wallet::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
2572       choose_another_instrument_or_address_ = true;
2573       SetIsSubmitting(false);
2574       GetWalletItems();
2575       break;
2576
2577     case wallet::VERIFY_CVV:
2578       SuggestionsUpdated();
2579       break;
2580
2581     default:
2582       DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
2583       return;
2584   }
2585
2586   view_->UpdateNotificationArea();
2587   view_->UpdateButtonStrip();
2588   view_->UpdateOverlay();
2589 }
2590
2591 void AutofillDialogControllerImpl::OnPassiveSigninSuccess() {
2592   FetchWalletCookie();
2593 }
2594
2595 void AutofillDialogControllerImpl::OnPassiveSigninFailure(
2596     const GoogleServiceAuthError& error) {
2597   signin_helper_.reset();
2598   passive_failed_ = true;
2599
2600   if (handling_use_wallet_link_click_ ||
2601       GetWalletClient()->user_index() != 0) {
2602     // TODO(estade): When a secondary account is selected and fails passive
2603     // auth, we show a sign in page. Currently we show the generic add account
2604     // page, but we should instead show sign in for the selected account.
2605     // http://crbug.com/323327
2606     SignInLinkClicked();
2607     handling_use_wallet_link_click_ = false;
2608   }
2609
2610   OnWalletSigninError();
2611 }
2612
2613 void AutofillDialogControllerImpl::OnDidFetchWalletCookieValue(
2614     const std::string& cookie_value) {
2615   wallet_cookie_value_ = cookie_value;
2616   signin_helper_.reset();
2617   GetWalletItems();
2618 }
2619
2620 void AutofillDialogControllerImpl::OnDidGetWalletItems(
2621     scoped_ptr<wallet::WalletItems> wallet_items) {
2622   legal_documents_text_.clear();
2623   legal_document_link_ranges_.clear();
2624   has_accepted_legal_documents_ = false;
2625
2626   wallet_items_ = wallet_items.Pass();
2627
2628   if (wallet_items_ && !wallet_items_->ObfuscatedGaiaId().empty()) {
2629     // Making sure the user index is in sync shouldn't be necessary, but is an
2630     // extra precaution. But if there is no active account (such as in the
2631     // PASSIVE_AUTH case), stick with the old active account.
2632     GetWalletClient()->SetUserIndex(wallet_items_->active_account_index());
2633
2634     std::vector<std::string> usernames;
2635     for (size_t i = 0; i < wallet_items_->gaia_accounts().size(); ++i) {
2636       usernames.push_back(wallet_items_->gaia_accounts()[i]->email_address());
2637     }
2638     account_chooser_model_->SetWalletAccounts(
2639         usernames, wallet_items_->active_account_index());
2640   }
2641
2642   ConstructLegalDocumentsText();
2643   OnWalletOrSigninUpdate();
2644 }
2645
2646 void AutofillDialogControllerImpl::OnDidSaveToWallet(
2647     const std::string& instrument_id,
2648     const std::string& address_id,
2649     const std::vector<wallet::RequiredAction>& required_actions,
2650     const std::vector<wallet::FormFieldError>& form_field_errors) {
2651   DCHECK(is_submitting_ && IsPayingWithWallet());
2652
2653   if (required_actions.empty()) {
2654     if (!address_id.empty())
2655       active_address_id_ = address_id;
2656     if (!instrument_id.empty())
2657       active_instrument_id_ = instrument_id;
2658     GetFullWallet();
2659   } else {
2660     OnWalletFormFieldError(form_field_errors);
2661     HandleSaveOrUpdateRequiredActions(required_actions);
2662   }
2663 }
2664
2665 void AutofillDialogControllerImpl::OnWalletError(
2666     wallet::WalletClient::ErrorType error_type) {
2667   DisableWallet(error_type);
2668 }
2669
2670 ////////////////////////////////////////////////////////////////////////////////
2671 // PersonalDataManagerObserver implementation.
2672
2673 void AutofillDialogControllerImpl::OnPersonalDataChanged() {
2674   if (is_submitting_)
2675     return;
2676
2677   SuggestionsUpdated();
2678 }
2679
2680 ////////////////////////////////////////////////////////////////////////////////
2681 // AccountChooserModelDelegate implementation.
2682
2683 void AutofillDialogControllerImpl::AccountChoiceChanged() {
2684   ScopedViewUpdates updates(view_.get());
2685   wallet::WalletClient* client = GetWalletClient();
2686
2687   if (is_submitting_)
2688     client->CancelRequest();
2689
2690   SetIsSubmitting(false);
2691
2692   size_t selected_user_index =
2693       account_chooser_model_->GetActiveWalletAccountIndex();
2694   if (account_chooser_model_->WalletIsSelected() &&
2695       client->user_index() != selected_user_index) {
2696     client->SetUserIndex(selected_user_index);
2697     // Clear |wallet_items_| so we don't try to restore the selected instrument
2698     // and address.
2699     wallet_items_.reset();
2700     GetWalletItems();
2701   } else {
2702     SuggestionsUpdated();
2703     UpdateAccountChooserView();
2704   }
2705 }
2706
2707 void AutofillDialogControllerImpl::AddAccount() {
2708   SignInLinkClicked();
2709 }
2710
2711 void AutofillDialogControllerImpl::UpdateAccountChooserView() {
2712   if (view_) {
2713     ScopedViewUpdates updates(view_.get());
2714     view_->UpdateAccountChooser();
2715     view_->UpdateNotificationArea();
2716   }
2717 }
2718
2719 ////////////////////////////////////////////////////////////////////////////////
2720
2721 bool AutofillDialogControllerImpl::HandleKeyPressEventInInput(
2722     const content::NativeWebKeyboardEvent& event) {
2723   if (popup_controller_.get())
2724     return popup_controller_->HandleKeyPressEvent(event);
2725
2726   return false;
2727 }
2728
2729 bool AutofillDialogControllerImpl::IsSubmitPausedOn(
2730     wallet::RequiredAction required_action) const {
2731   return full_wallet_ && full_wallet_->HasRequiredAction(required_action);
2732 }
2733
2734 void AutofillDialogControllerImpl::ShowNewCreditCardBubble(
2735     scoped_ptr<CreditCard> new_card,
2736     scoped_ptr<AutofillProfile> billing_profile) {
2737   NewCreditCardBubbleController::Show(web_contents(),
2738                                       new_card.Pass(),
2739                                       billing_profile.Pass());
2740 }
2741
2742 void AutofillDialogControllerImpl::SubmitButtonDelayBegin() {
2743   submit_button_delay_timer_.Start(
2744       FROM_HERE,
2745       base::TimeDelta::FromMilliseconds(kSubmitButtonDelayMs),
2746       this,
2747       &AutofillDialogControllerImpl::OnSubmitButtonDelayEnd);
2748 }
2749
2750 void AutofillDialogControllerImpl::SubmitButtonDelayEndForTesting() {
2751   DCHECK(submit_button_delay_timer_.IsRunning());
2752   submit_button_delay_timer_.user_task().Run();
2753   submit_button_delay_timer_.Stop();
2754 }
2755
2756 void AutofillDialogControllerImpl::
2757     ClearLastWalletItemsFetchTimestampForTesting() {
2758   last_wallet_items_fetch_timestamp_ = base::TimeTicks();
2759 }
2760
2761 AccountChooserModel* AutofillDialogControllerImpl::
2762     AccountChooserModelForTesting() {
2763   return account_chooser_model_.get();
2764 }
2765
2766 bool AutofillDialogControllerImpl::IsSignInContinueUrl(
2767     const GURL& url,
2768     size_t* user_index) const {
2769   return wallet::IsSignInContinueUrl(url, user_index);
2770 }
2771
2772 AutofillDialogControllerImpl::AutofillDialogControllerImpl(
2773     content::WebContents* contents,
2774     const FormData& form_structure,
2775     const GURL& source_url,
2776     const AutofillManagerDelegate::ResultCallback& callback)
2777     : WebContentsObserver(contents),
2778       profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
2779       initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
2780       form_structure_(form_structure),
2781       invoked_from_same_origin_(true),
2782       source_url_(source_url),
2783       callback_(callback),
2784       wallet_client_(profile_->GetRequestContext(), this, source_url),
2785       wallet_items_requested_(false),
2786       handling_use_wallet_link_click_(false),
2787       passive_failed_(false),
2788       suggested_cc_(this),
2789       suggested_billing_(this),
2790       suggested_cc_billing_(this),
2791       suggested_shipping_(this),
2792       cares_about_shipping_(true),
2793       popup_input_type_(UNKNOWN_TYPE),
2794       waiting_for_explicit_sign_in_response_(false),
2795       has_accepted_legal_documents_(false),
2796       is_submitting_(false),
2797       choose_another_instrument_or_address_(false),
2798       wallet_server_validation_recoverable_(true),
2799       data_was_passed_back_(false),
2800       was_ui_latency_logged_(false),
2801       card_generated_animation_(2000, 60, this),
2802       weak_ptr_factory_(this) {
2803   DCHECK(!callback_.is_null());
2804 }
2805
2806 AutofillDialogView* AutofillDialogControllerImpl::CreateView() {
2807   return AutofillDialogView::Create(this);
2808 }
2809
2810 PersonalDataManager* AutofillDialogControllerImpl::GetManager() const {
2811   return PersonalDataManagerFactory::GetForProfile(profile_);
2812 }
2813
2814 AddressValidator* AutofillDialogControllerImpl::GetValidator() {
2815   return validator_.get();
2816 }
2817
2818 const wallet::WalletClient* AutofillDialogControllerImpl::GetWalletClient()
2819     const {
2820   return const_cast<AutofillDialogControllerImpl*>(this)->GetWalletClient();
2821 }
2822
2823 wallet::WalletClient* AutofillDialogControllerImpl::GetWalletClient() {
2824   return &wallet_client_;
2825 }
2826
2827 bool AutofillDialogControllerImpl::IsPayingWithWallet() const {
2828   return account_chooser_model_->WalletIsSelected() &&
2829          SignedInState() == SIGNED_IN;
2830 }
2831
2832 void AutofillDialogControllerImpl::LoadRiskFingerprintData() {
2833   risk_data_.clear();
2834
2835   uint64 obfuscated_gaia_id = 0;
2836   bool success = base::StringToUint64(wallet_items_->ObfuscatedGaiaId(),
2837                                       &obfuscated_gaia_id);
2838   DCHECK(success);
2839
2840   gfx::Rect window_bounds;
2841   window_bounds = GetBaseWindowForWebContents(web_contents())->GetBounds();
2842
2843   PrefService* user_prefs = profile_->GetPrefs();
2844   std::string charset = user_prefs->GetString(::prefs::kDefaultCharset);
2845   std::string accept_languages =
2846       user_prefs->GetString(::prefs::kAcceptLanguages);
2847   base::Time install_time = base::Time::FromTimeT(
2848       g_browser_process->local_state()->GetInt64(::prefs::kInstallDate));
2849
2850   risk::GetFingerprint(
2851       obfuscated_gaia_id, window_bounds, web_contents(),
2852       chrome::VersionInfo().Version(), charset, accept_languages, install_time,
2853       g_browser_process->GetApplicationLocale(), GetUserAgent(),
2854       base::Bind(&AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData,
2855                  weak_ptr_factory_.GetWeakPtr()));
2856 }
2857
2858 void AutofillDialogControllerImpl::OnDidLoadRiskFingerprintData(
2859     scoped_ptr<risk::Fingerprint> fingerprint) {
2860   DCHECK(AreLegalDocumentsCurrent());
2861
2862   std::string proto_data;
2863   fingerprint->SerializeToString(&proto_data);
2864   base::Base64Encode(proto_data, &risk_data_);
2865
2866   SubmitWithWallet();
2867 }
2868
2869 void AutofillDialogControllerImpl::OpenTabWithUrl(const GURL& url) {
2870   chrome::NavigateParams params(
2871       chrome::FindBrowserWithWebContents(web_contents()),
2872       url,
2873       content::PAGE_TRANSITION_LINK);
2874   params.disposition = NEW_FOREGROUND_TAB;
2875   chrome::Navigate(&params);
2876 }
2877
2878 DialogSection AutofillDialogControllerImpl::ActiveBillingSection() const {
2879   return IsPayingWithWallet() ? SECTION_CC_BILLING : SECTION_BILLING;
2880 }
2881
2882 bool AutofillDialogControllerImpl::IsEditingExistingData(
2883     DialogSection section) const {
2884   return section_editing_state_.count(section) > 0;
2885 }
2886
2887 bool AutofillDialogControllerImpl::IsManuallyEditingSection(
2888     DialogSection section) const {
2889   return IsEditingExistingData(section) ||
2890          SuggestionsMenuModelForSection(section)->
2891              GetItemKeyForCheckedItem() == kAddNewItemKey;
2892 }
2893
2894 void AutofillDialogControllerImpl::OnWalletSigninError() {
2895   account_chooser_model_->SetHadWalletSigninError();
2896   GetWalletClient()->CancelRequest();
2897   LogDialogLatencyToShow();
2898 }
2899
2900 void AutofillDialogControllerImpl::DisableWallet(
2901     wallet::WalletClient::ErrorType error_type) {
2902   signin_helper_.reset();
2903   wallet_items_.reset();
2904   wallet_errors_.clear();
2905   GetWalletClient()->CancelRequest();
2906   SetIsSubmitting(false);
2907   wallet_error_notification_ = GetWalletError(error_type);
2908   account_chooser_model_->SetHadWalletError();
2909 }
2910
2911 void AutofillDialogControllerImpl::SuggestionsUpdated() {
2912   ScopedViewUpdates updates(view_.get());
2913
2914   const FieldValueMap snapshot = TakeUserInputSnapshot();
2915
2916   suggested_cc_.Reset();
2917   suggested_billing_.Reset();
2918   suggested_cc_billing_.Reset();
2919   suggested_shipping_.Reset();
2920   HidePopup();
2921
2922   suggested_shipping_.AddKeyedItem(
2923       kSameAsBillingKey,
2924       l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_USE_BILLING_FOR_SHIPPING));
2925
2926   if (IsPayingWithWallet()) {
2927     const std::vector<wallet::Address*>& addresses =
2928         wallet_items_->addresses();
2929
2930     bool shipping_same_as_billing = profile_->GetPrefs()->GetBoolean(
2931         ::prefs::kAutofillDialogWalletShippingSameAsBilling);
2932
2933     if (shipping_same_as_billing)
2934       suggested_shipping_.SetCheckedItem(kSameAsBillingKey);
2935
2936     for (size_t i = 0; i < addresses.size(); ++i) {
2937       std::string key = base::IntToString(i);
2938       suggested_shipping_.AddKeyedItemWithMinorText(
2939           key,
2940           addresses[i]->DisplayName(),
2941           addresses[i]->DisplayNameDetail());
2942       suggested_shipping_.SetEnabled(
2943           key,
2944           CanAcceptCountry(SECTION_SHIPPING,
2945                            addresses[i]->country_name_code()));
2946
2947       // TODO(scr): Move this assignment outside the loop or comment why it
2948       // can't be there.
2949       const std::string default_shipping_address_id =
2950           GetIdToSelect(wallet_items_->default_address_id(),
2951                         previous_default_shipping_address_id_,
2952                         previously_selected_shipping_address_id_);
2953
2954       if (!shipping_same_as_billing &&
2955           addresses[i]->object_id() == default_shipping_address_id) {
2956         suggested_shipping_.SetCheckedItem(key);
2957       }
2958     }
2959
2960     if (!IsSubmitPausedOn(wallet::VERIFY_CVV)) {
2961       const std::vector<wallet::WalletItems::MaskedInstrument*>& instruments =
2962           wallet_items_->instruments();
2963       std::string first_active_instrument_key;
2964       std::string default_instrument_key;
2965       for (size_t i = 0; i < instruments.size(); ++i) {
2966         bool allowed = IsInstrumentAllowed(*instruments[i]) &&
2967             CanAcceptCountry(SECTION_BILLING,
2968                              instruments[i]->address().country_name_code());
2969         gfx::Image icon = instruments[i]->CardIcon();
2970         if (!allowed && !icon.IsEmpty()) {
2971           // Create a grayed disabled icon.
2972           SkBitmap disabled_bitmap = SkBitmapOperations::CreateHSLShiftedBitmap(
2973               *icon.ToSkBitmap(), kGrayImageShift);
2974           icon = gfx::Image(
2975               gfx::ImageSkia::CreateFrom1xBitmap(disabled_bitmap));
2976         }
2977         std::string key = base::IntToString(i);
2978         suggested_cc_billing_.AddKeyedItemWithMinorTextAndIcon(
2979             key,
2980             instruments[i]->DisplayName(),
2981             instruments[i]->DisplayNameDetail(),
2982             icon);
2983         suggested_cc_billing_.SetEnabled(key, allowed);
2984
2985         if (allowed) {
2986           if (first_active_instrument_key.empty())
2987             first_active_instrument_key = key;
2988
2989           const std::string default_instrument_id =
2990               GetIdToSelect(wallet_items_->default_instrument_id(),
2991                             previous_default_instrument_id_,
2992                             previously_selected_instrument_id_);
2993           if (instruments[i]->object_id() == default_instrument_id)
2994             default_instrument_key = key;
2995         }
2996       }
2997
2998       suggested_cc_billing_.AddKeyedItem(
2999           kAddNewItemKey,
3000           l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_BILLING_DETAILS));
3001       if (!wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)) {
3002         suggested_cc_billing_.AddKeyedItemWithMinorText(
3003             kManageItemsKey,
3004             l10n_util::GetStringUTF16(
3005                 IDS_AUTOFILL_DIALOG_MANAGE_BILLING_DETAILS),
3006                 base::UTF8ToUTF16(wallet::GetManageInstrumentsUrl(0U).host()));
3007       }
3008
3009       // Determine which instrument item should be selected.
3010       if (!default_instrument_key.empty())
3011         suggested_cc_billing_.SetCheckedItem(default_instrument_key);
3012       else if (!first_active_instrument_key.empty())
3013         suggested_cc_billing_.SetCheckedItem(first_active_instrument_key);
3014       else
3015         suggested_cc_billing_.SetCheckedItem(kAddNewItemKey);
3016     }
3017   } else {
3018     if (IsAutofillEnabled()) {
3019       PersonalDataManager* manager = GetManager();
3020       const std::vector<CreditCard*>& cards = manager->GetCreditCards();
3021       ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
3022       for (size_t i = 0; i < cards.size(); ++i) {
3023         if (!i18ninput::CardHasCompleteAndVerifiedData(*cards[i]))
3024           continue;
3025
3026         suggested_cc_.AddKeyedItemWithIcon(
3027             cards[i]->guid(),
3028             cards[i]->Label(),
3029             rb.GetImageNamed(CreditCard::IconResourceId(cards[i]->type())));
3030       }
3031
3032       const std::vector<AutofillProfile*>& profiles = manager->GetProfiles();
3033       std::vector<base::string16> labels;
3034       AutofillProfile::CreateDifferentiatingLabels(profiles, &labels);
3035       DCHECK_EQ(labels.size(), profiles.size());
3036       for (size_t i = 0; i < profiles.size(); ++i) {
3037         const AutofillProfile& profile = *profiles[i];
3038         if (!i18ninput::AddressHasCompleteAndVerifiedData(profile) ||
3039             !i18ninput::CountryIsFullySupported(
3040                 base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)))) {
3041           continue;
3042         }
3043
3044         // Don't add variants for addresses: name is part of credit card and
3045         // we'll just ignore email and phone number variants.
3046         suggested_shipping_.AddKeyedItem(profile.guid(), labels[i]);
3047         suggested_shipping_.SetEnabled(
3048             profile.guid(),
3049             CanAcceptCountry(
3050                 SECTION_SHIPPING,
3051                 base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))));
3052         if (!profile.GetRawInfo(EMAIL_ADDRESS).empty() &&
3053             !profile.IsPresentButInvalid(EMAIL_ADDRESS)) {
3054           suggested_billing_.AddKeyedItem(profile.guid(), labels[i]);
3055           suggested_billing_.SetEnabled(
3056               profile.guid(),
3057               CanAcceptCountry(
3058                   SECTION_BILLING,
3059                   base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))));
3060         }
3061       }
3062     }
3063
3064     suggested_cc_.AddKeyedItem(
3065         kAddNewItemKey,
3066         l10n_util::GetStringUTF16(IsAutofillEnabled() ?
3067             IDS_AUTOFILL_DIALOG_ADD_CREDIT_CARD :
3068             IDS_AUTOFILL_DIALOG_ENTER_CREDIT_CARD));
3069     suggested_cc_.AddKeyedItem(
3070         kManageItemsKey,
3071         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_CREDIT_CARD));
3072     suggested_billing_.AddKeyedItem(
3073         kAddNewItemKey,
3074         l10n_util::GetStringUTF16(IsAutofillEnabled() ?
3075             IDS_AUTOFILL_DIALOG_ADD_BILLING_ADDRESS :
3076             IDS_AUTOFILL_DIALOG_ENTER_BILLING_DETAILS));
3077     suggested_billing_.AddKeyedItem(
3078         kManageItemsKey,
3079         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_BILLING_ADDRESS));
3080   }
3081
3082   suggested_shipping_.AddKeyedItem(
3083       kAddNewItemKey,
3084       l10n_util::GetStringUTF16(IsPayingWithWallet() || IsAutofillEnabled() ?
3085           IDS_AUTOFILL_DIALOG_ADD_SHIPPING_ADDRESS :
3086           IDS_AUTOFILL_DIALOG_USE_DIFFERENT_SHIPPING_ADDRESS));
3087
3088   if (!IsPayingWithWallet()) {
3089     if (IsAutofillEnabled()) {
3090       suggested_shipping_.AddKeyedItem(
3091           kManageItemsKey,
3092           l10n_util::GetStringUTF16(
3093               IDS_AUTOFILL_DIALOG_MANAGE_SHIPPING_ADDRESS));
3094     }
3095   } else if (!wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)) {
3096     suggested_shipping_.AddKeyedItemWithMinorText(
3097         kManageItemsKey,
3098         l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_MANAGE_SHIPPING_ADDRESS),
3099         base::UTF8ToUTF16(wallet::GetManageAddressesUrl(0U).host()));
3100   }
3101
3102   if (!IsPayingWithWallet() && IsAutofillEnabled()) {
3103     for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3104       DialogSection section = static_cast<DialogSection>(i);
3105       if (!SectionIsActive(section))
3106         continue;
3107
3108       // Set the starting choice for the menu. First set to the default in case
3109       // the GUID saved in prefs refers to a profile that no longer exists.
3110       std::string guid;
3111       GetDefaultAutofillChoice(section, &guid);
3112       SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
3113       model->SetCheckedItem(guid);
3114       if (GetAutofillChoice(section, &guid))
3115         model->SetCheckedItem(guid);
3116     }
3117   }
3118
3119   if (view_)
3120     view_->ModelChanged();
3121
3122   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3123     ResetSectionInput(static_cast<DialogSection>(i));
3124   }
3125
3126   FieldValueMap::const_iterator billing_it =
3127       snapshot.find(ADDRESS_BILLING_COUNTRY);
3128   if (billing_it != snapshot.end())
3129     RebuildInputsForCountry(ActiveBillingSection(), billing_it->second, true);
3130
3131   FieldValueMap::const_iterator shipping_it =
3132       snapshot.find(ADDRESS_HOME_COUNTRY);
3133   if (shipping_it != snapshot.end())
3134     RebuildInputsForCountry(SECTION_SHIPPING, shipping_it->second, true);
3135
3136   RestoreUserInputFromSnapshot(snapshot);
3137
3138   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3139     DialogSection section = static_cast<DialogSection>(i);
3140     if (!SectionIsActive(section))
3141       continue;
3142
3143     ShowEditUiIfBadSuggestion(section);
3144     UpdateSection(section);
3145   }
3146
3147   UpdateForErrors();
3148 }
3149
3150 void AutofillDialogControllerImpl::FillOutputForSectionWithComparator(
3151     DialogSection section,
3152     const FormStructure::InputFieldComparator& compare) {
3153   if (!SectionIsActive(section))
3154     return;
3155
3156   DetailInputs inputs;
3157   std::string country_code = CountryCodeForSection(section);
3158   BuildInputsForSection(section, country_code, &inputs,
3159                         MutableAddressLanguageCodeForSection(section));
3160   std::vector<ServerFieldType> types = common::TypesFromInputs(inputs);
3161
3162   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
3163   if (wrapper) {
3164     // Only fill in data that is associated with this section.
3165     wrapper->FillFormStructure(types, compare, &form_structure_);
3166
3167     // CVC needs special-casing because the CreditCard class doesn't store or
3168     // handle them. This isn't necessary when filling the combined CC and
3169     // billing section as CVC comes from |full_wallet_| in this case.
3170     if (section == SECTION_CC)
3171       SetOutputForFieldsOfType(CREDIT_CARD_VERIFICATION_CODE, view_->GetCvc());
3172
3173     // When filling from Wallet data, use the email address associated with the
3174     // account. There is no other email address stored as part of a Wallet
3175     // address.
3176     if (section == SECTION_CC_BILLING) {
3177       SetOutputForFieldsOfType(
3178           EMAIL_ADDRESS, account_chooser_model_->GetActiveWalletAccountName());
3179     }
3180   } else {
3181     // The user manually input data. If using Autofill, save the info as new or
3182     // edited data. Always fill local data into |form_structure_|.
3183     FieldValueMap output;
3184     view_->GetUserInput(section, &output);
3185
3186     if (section == SECTION_CC) {
3187       CreditCard card;
3188       FillFormGroupFromOutputs(output, &card);
3189
3190       // The card holder name comes from the billing address section.
3191       card.SetRawInfo(CREDIT_CARD_NAME,
3192                       GetValueFromSection(SECTION_BILLING, NAME_BILLING_FULL));
3193
3194       if (ShouldSaveDetailsLocally()) {
3195         card.set_origin(kAutofillDialogOrigin);
3196
3197         std::string guid = GetManager()->SaveImportedCreditCard(card);
3198         newly_saved_data_model_guids_[section] = guid;
3199         DCHECK(!profile()->IsOffTheRecord());
3200         newly_saved_card_.reset(new CreditCard(card));
3201       }
3202
3203       AutofillCreditCardWrapper card_wrapper(&card);
3204       card_wrapper.FillFormStructure(types, compare, &form_structure_);
3205
3206       // Again, CVC needs special-casing. Fill it in directly from |output|.
3207       SetOutputForFieldsOfType(
3208           CREDIT_CARD_VERIFICATION_CODE,
3209           output[CREDIT_CARD_VERIFICATION_CODE]);
3210     } else {
3211       AutofillProfile profile;
3212       FillFormGroupFromOutputs(output, &profile);
3213       profile.set_language_code(AddressLanguageCodeForSection(section));
3214
3215       if (ShouldSaveDetailsLocally()) {
3216         profile.set_origin(RulesAreLoaded(section) ?
3217             kAutofillDialogOrigin : source_url_.GetOrigin().spec());
3218
3219         std::string guid = GetManager()->SaveImportedProfile(profile);
3220         newly_saved_data_model_guids_[section] = guid;
3221       }
3222
3223       AutofillProfileWrapper profile_wrapper(&profile);
3224       profile_wrapper.FillFormStructure(types, compare, &form_structure_);
3225     }
3226   }
3227 }
3228
3229 void AutofillDialogControllerImpl::FillOutputForSection(DialogSection section) {
3230   FillOutputForSectionWithComparator(
3231       section, base::Bind(common::ServerTypeMatchesField, section));
3232 }
3233
3234 bool AutofillDialogControllerImpl::FormStructureCaresAboutSection(
3235     DialogSection section) const {
3236   // For now, only SECTION_SHIPPING may be omitted due to a site not asking for
3237   // any of the fields.
3238   if (section == SECTION_SHIPPING)
3239     return cares_about_shipping_;
3240
3241   return true;
3242 }
3243
3244 void AutofillDialogControllerImpl::SetOutputForFieldsOfType(
3245     ServerFieldType type,
3246     const base::string16& output) {
3247   for (size_t i = 0; i < form_structure_.field_count(); ++i) {
3248     AutofillField* field = form_structure_.field(i);
3249     if (field->Type().GetStorableType() == type)
3250       field->value = output;
3251   }
3252 }
3253
3254 base::string16 AutofillDialogControllerImpl::GetValueFromSection(
3255     DialogSection section,
3256     ServerFieldType type) {
3257   DCHECK(SectionIsActive(section));
3258
3259   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
3260   if (wrapper)
3261     return wrapper->GetInfo(AutofillType(type));
3262
3263   FieldValueMap output;
3264   view_->GetUserInput(section, &output);
3265   return output[type];
3266 }
3267
3268 bool AutofillDialogControllerImpl::CanAcceptCountry(
3269     DialogSection section,
3270     const std::string& country_code) {
3271   DCHECK_EQ(2U, country_code.size());
3272
3273   if (section == SECTION_CC_BILLING)
3274     return LowerCaseEqualsASCII(country_code, "us");
3275
3276   CountryComboboxModel* model = CountryComboboxModelForSection(section);
3277   const std::vector<AutofillCountry*>& countries = model->countries();
3278   for (size_t i = 0; i < countries.size(); ++i) {
3279     if (countries[i] && countries[i]->country_code() == country_code)
3280       return true;
3281   }
3282
3283   return false;
3284 }
3285
3286 bool AutofillDialogControllerImpl::ShouldSuggestProfile(
3287     DialogSection section,
3288     const AutofillProfile& profile) {
3289   std::string country_code =
3290       base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
3291   return country_code.empty() || CanAcceptCountry(section, country_code);
3292 }
3293
3294 SuggestionsMenuModel* AutofillDialogControllerImpl::
3295     SuggestionsMenuModelForSection(DialogSection section) {
3296   switch (section) {
3297     case SECTION_CC:
3298       return &suggested_cc_;
3299     case SECTION_BILLING:
3300       return &suggested_billing_;
3301     case SECTION_SHIPPING:
3302       return &suggested_shipping_;
3303     case SECTION_CC_BILLING:
3304       return &suggested_cc_billing_;
3305   }
3306
3307   NOTREACHED();
3308   return NULL;
3309 }
3310
3311 const SuggestionsMenuModel* AutofillDialogControllerImpl::
3312     SuggestionsMenuModelForSection(DialogSection section) const {
3313   return const_cast<AutofillDialogControllerImpl*>(this)->
3314       SuggestionsMenuModelForSection(section);
3315 }
3316
3317 DialogSection AutofillDialogControllerImpl::SectionForSuggestionsMenuModel(
3318     const SuggestionsMenuModel& model) {
3319   if (&model == &suggested_cc_)
3320     return SECTION_CC;
3321
3322   if (&model == &suggested_billing_)
3323     return SECTION_BILLING;
3324
3325   if (&model == &suggested_cc_billing_)
3326     return SECTION_CC_BILLING;
3327
3328   DCHECK_EQ(&model, &suggested_shipping_);
3329   return SECTION_SHIPPING;
3330 }
3331
3332 CountryComboboxModel* AutofillDialogControllerImpl::
3333     CountryComboboxModelForSection(DialogSection section) {
3334   if (section == SECTION_BILLING)
3335     return billing_country_combobox_model_.get();
3336
3337   if (section == SECTION_SHIPPING)
3338     return shipping_country_combobox_model_.get();
3339
3340   return NULL;
3341 }
3342
3343 void AutofillDialogControllerImpl::GetI18nValidatorSuggestions(
3344     DialogSection section,
3345     ServerFieldType type,
3346     std::vector<base::string16>* popup_values,
3347     std::vector<base::string16>* popup_labels,
3348     std::vector<base::string16>* popup_icons) {
3349   AddressField focused_field;
3350   if (!i18ninput::FieldForType(type, &focused_field))
3351     return;
3352
3353   FieldValueMap inputs;
3354   view_->GetUserInput(section, &inputs);
3355
3356   AutofillProfile profile;
3357   FillFormGroupFromOutputs(inputs, &profile);
3358
3359   AddressData user_input;
3360   i18ninput::CreateAddressData(
3361       base::Bind(&GetInfoFromProfile, profile), &user_input);
3362   user_input.language_code = AddressLanguageCodeForSection(section);
3363
3364   static const size_t kSuggestionsLimit = 10;
3365   AddressValidator::Status status = GetValidator()->GetSuggestions(
3366       user_input, focused_field, kSuggestionsLimit,
3367       &i18n_validator_suggestions_);
3368
3369   if (status != AddressValidator::SUCCESS)
3370     return;
3371
3372   for (size_t i = 0; i < i18n_validator_suggestions_.size(); ++i) {
3373     popup_values->push_back(base::UTF8ToUTF16(
3374         i18n_validator_suggestions_[i].GetFieldValue(focused_field)));
3375
3376     // Disambiguate the suggestion by showing the smallest administrative
3377     // region of the suggested address:
3378     //    ADMIN_AREA > LOCALITY > DEPENDENT_LOCALITY
3379     popup_labels->push_back(base::string16());
3380     for (int field = ::i18n::addressinput::DEPENDENT_LOCALITY;
3381          field >= ::i18n::addressinput::ADMIN_AREA;
3382          --field) {
3383       const std::string& field_value =
3384           i18n_validator_suggestions_[i].GetFieldValue(
3385               static_cast<AddressField>(field));
3386       if (focused_field != field && !field_value.empty()) {
3387         popup_labels->back().assign(base::UTF8ToUTF16(field_value));
3388         break;
3389       }
3390     }
3391   }
3392   popup_icons->resize(popup_values->size());
3393 }
3394
3395 DetailInputs* AutofillDialogControllerImpl::MutableRequestedFieldsForSection(
3396     DialogSection section) {
3397   return const_cast<DetailInputs*>(&RequestedFieldsForSection(section));
3398 }
3399
3400 std::string* AutofillDialogControllerImpl::MutableAddressLanguageCodeForSection(
3401     DialogSection section) {
3402   switch (section) {
3403     case SECTION_BILLING:
3404     case SECTION_CC_BILLING:
3405       return &billing_address_language_code_;
3406     case SECTION_SHIPPING:
3407       return &shipping_address_language_code_;
3408     case SECTION_CC:
3409       return NULL;
3410   }
3411   NOTREACHED();
3412   return NULL;
3413 }
3414
3415 std::string AutofillDialogControllerImpl::AddressLanguageCodeForSection(
3416     DialogSection section) {
3417   std::string* language_code = MutableAddressLanguageCodeForSection(section);
3418   return language_code != NULL ? *language_code : std::string();
3419 }
3420
3421 std::vector<ServerFieldType> AutofillDialogControllerImpl::
3422     RequestedTypesForSection(DialogSection section) const {
3423   return common::TypesFromInputs(RequestedFieldsForSection(section));
3424 }
3425
3426 std::string AutofillDialogControllerImpl::CountryCodeForSection(
3427     DialogSection section) {
3428   base::string16 country;
3429
3430   scoped_ptr<DataModelWrapper> wrapper = CreateWrapper(section);
3431   if (wrapper) {
3432     country = wrapper->GetInfo(AutofillType(CountryTypeForSection(section)));
3433   } else {
3434     FieldValueMap outputs;
3435     view_->GetUserInput(section, &outputs);
3436     country = outputs[CountryTypeForSection(section)];
3437   }
3438
3439   return AutofillCountry::GetCountryCode(
3440       country, g_browser_process->GetApplicationLocale());
3441 }
3442
3443 bool AutofillDialogControllerImpl::RebuildInputsForCountry(
3444     DialogSection section,
3445     const base::string16& country_name,
3446     bool should_clobber) {
3447   CountryComboboxModel* model = CountryComboboxModelForSection(section);
3448   if (!model)
3449     return false;
3450
3451   std::string country_code = AutofillCountry::GetCountryCode(
3452       country_name, g_browser_process->GetApplicationLocale());
3453   DCHECK(CanAcceptCountry(section, country_code));
3454
3455   if (view_ && !should_clobber) {
3456     FieldValueMap outputs;
3457     view_->GetUserInput(section, &outputs);
3458
3459     // If |country_name| is the same as the view, no-op and let the caller know.
3460     if (outputs[CountryTypeForSection(section)] == country_name)
3461       return false;
3462   }
3463
3464   DetailInputs* inputs = MutableRequestedFieldsForSection(section);
3465   inputs->clear();
3466   BuildInputsForSection(section, country_code, inputs,
3467                         MutableAddressLanguageCodeForSection(section));
3468
3469   if (!country_code.empty()) {
3470     GetValidator()->LoadRules(AutofillCountry::GetCountryCode(
3471         country_name, g_browser_process->GetApplicationLocale()));
3472   }
3473
3474   return true;
3475 }
3476
3477 void AutofillDialogControllerImpl::HidePopup() {
3478   if (popup_controller_)
3479     popup_controller_->Hide();
3480   popup_input_type_ = UNKNOWN_TYPE;
3481 }
3482
3483 void AutofillDialogControllerImpl::SetEditingExistingData(
3484     DialogSection section, bool editing) {
3485   if (editing)
3486     section_editing_state_.insert(section);
3487   else
3488     section_editing_state_.erase(section);
3489 }
3490
3491 bool AutofillDialogControllerImpl::IsASuggestionItemKey(
3492     const std::string& key) const {
3493   return !key.empty() &&
3494       key != kAddNewItemKey &&
3495       key != kManageItemsKey &&
3496       key != kSameAsBillingKey;
3497 }
3498
3499 bool AutofillDialogControllerImpl::IsAutofillEnabled() const {
3500   return profile_->GetPrefs()->GetBoolean(prefs::kAutofillEnabled);
3501 }
3502
3503 bool AutofillDialogControllerImpl::IsManuallyEditingAnySection() const {
3504   for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
3505     if (IsManuallyEditingSection(static_cast<DialogSection>(section)))
3506       return true;
3507   }
3508   return false;
3509 }
3510
3511 base::string16 AutofillDialogControllerImpl::CreditCardNumberValidityMessage(
3512     const base::string16& number) const {
3513   if (!number.empty() && !autofill::IsValidCreditCardNumber(number)) {
3514     return l10n_util::GetStringUTF16(
3515         IDS_AUTOFILL_DIALOG_VALIDATION_INVALID_CREDIT_CARD_NUMBER);
3516   }
3517
3518   base::string16 message;
3519   if (IsPayingWithWallet() && !wallet_items_->SupportsCard(number, &message))
3520     return message;
3521
3522   // Card number is good and supported.
3523   return base::string16();
3524 }
3525
3526 bool AutofillDialogControllerImpl::AllSectionsAreValid() {
3527   for (size_t section = SECTION_MIN; section <= SECTION_MAX; ++section) {
3528     if (!SectionIsValid(static_cast<DialogSection>(section)))
3529       return false;
3530   }
3531   return true;
3532 }
3533
3534 bool AutofillDialogControllerImpl::SectionIsValid(
3535     DialogSection section) {
3536   if (!IsManuallyEditingSection(section))
3537     return true;
3538
3539   FieldValueMap detail_outputs;
3540   view_->GetUserInput(section, &detail_outputs);
3541   return !InputsAreValid(section, detail_outputs).HasSureErrors();
3542 }
3543
3544 bool AutofillDialogControllerImpl::RulesAreLoaded(DialogSection section) {
3545   AddressData address_data;
3546   address_data.country_code = CountryCodeForSection(section);
3547   AddressValidator::Status status = GetValidator()->ValidateAddress(
3548       address_data, AddressProblemFilter(), NULL);
3549   return status == AddressValidator::SUCCESS;
3550 }
3551
3552 bool AutofillDialogControllerImpl::IsCreditCardExpirationValid(
3553     const base::string16& year,
3554     const base::string16& month) const {
3555   // If the expiration is in the past as per the local clock, it's invalid.
3556   base::Time now = base::Time::Now();
3557   if (!autofill::IsValidCreditCardExpirationDate(year, month, now))
3558     return false;
3559
3560   const wallet::WalletItems::MaskedInstrument* instrument =
3561       ActiveInstrument();
3562   if (instrument) {
3563     const std::string& locale = g_browser_process->GetApplicationLocale();
3564     int month_int;
3565     if (base::StringToInt(month, &month_int) &&
3566         instrument->status() ==
3567             wallet::WalletItems::MaskedInstrument::EXPIRED &&
3568         year ==
3569             instrument->GetInfo(
3570                 AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), locale) &&
3571         month_int == instrument->expiration_month()) {
3572       // Otherwise, if the user is editing an instrument that's deemed expired
3573       // by the Online Wallet server, mark it invalid on selection.
3574       return false;
3575     }
3576   }
3577
3578   return true;
3579 }
3580
3581 bool AutofillDialogControllerImpl::HasInvalidAddress(
3582     const AutofillProfile& profile) {
3583   AddressData address_data;
3584   i18ninput::CreateAddressData(base::Bind(&GetInfoFromProfile, profile),
3585                                &address_data);
3586
3587   AddressProblems problems;
3588   GetValidator()->ValidateAddress(address_data,
3589                                   AddressProblemFilter(),
3590                                   &problems);
3591   return !problems.empty();
3592 }
3593
3594 bool AutofillDialogControllerImpl::ShouldUseBillingForShipping() {
3595   return SectionIsActive(SECTION_SHIPPING) &&
3596       suggested_shipping_.GetItemKeyForCheckedItem() == kSameAsBillingKey;
3597 }
3598
3599 bool AutofillDialogControllerImpl::ShouldSaveDetailsLocally() {
3600   // It's possible that the user checked [X] Save details locally before
3601   // switching payment methods, so only ask the view whether to save details
3602   // locally if that checkbox is showing (currently if not paying with wallet).
3603   // Also, if the user isn't editing any sections, there's no data to save
3604   // locally.
3605   return ShouldOfferToSaveInChrome() && view_->SaveDetailsLocally();
3606 }
3607
3608 void AutofillDialogControllerImpl::SetIsSubmitting(bool submitting) {
3609   is_submitting_ = submitting;
3610
3611   if (!submitting)
3612     full_wallet_.reset();
3613
3614   if (view_) {
3615     ScopedViewUpdates updates(view_.get());
3616     view_->UpdateButtonStrip();
3617     view_->UpdateOverlay();
3618     view_->UpdateNotificationArea();
3619   }
3620 }
3621
3622 bool AutofillDialogControllerImpl::AreLegalDocumentsCurrent() const {
3623   return has_accepted_legal_documents_ ||
3624       (wallet_items_ && wallet_items_->legal_documents().empty());
3625 }
3626
3627 void AutofillDialogControllerImpl::AcceptLegalTerms() {
3628   content::BrowserThread::PostTask(
3629       content::BrowserThread::IO, FROM_HERE,
3630       base::Bind(&UserDidOptIntoLocationServices));
3631   PrefService* local_state = g_browser_process->local_state();
3632   ListPrefUpdate accepted(
3633       local_state, ::prefs::kAutofillDialogWalletLocationAcceptance);
3634   accepted->AppendIfNotPresent(new base::StringValue(
3635       account_chooser_model_->GetActiveWalletAccountName()));
3636
3637   if (AreLegalDocumentsCurrent()) {
3638     LoadRiskFingerprintData();
3639   } else {
3640     GetWalletClient()->AcceptLegalDocuments(
3641         wallet_items_->legal_documents(),
3642         wallet_items_->google_transaction_id());
3643   }
3644 }
3645
3646 void AutofillDialogControllerImpl::SubmitWithWallet() {
3647   active_instrument_id_.clear();
3648   active_address_id_.clear();
3649   full_wallet_.reset();
3650
3651   const wallet::WalletItems::MaskedInstrument* active_instrument =
3652       ActiveInstrument();
3653   if (!IsManuallyEditingSection(SECTION_CC_BILLING)) {
3654     active_instrument_id_ = active_instrument->object_id();
3655     DCHECK(!active_instrument_id_.empty());
3656   }
3657
3658   const wallet::Address* active_address = ActiveShippingAddress();
3659   if (!IsManuallyEditingSection(SECTION_SHIPPING) &&
3660       !ShouldUseBillingForShipping() &&
3661       IsShippingAddressRequired()) {
3662     active_address_id_ = active_address->object_id();
3663     DCHECK(!active_address_id_.empty());
3664   }
3665
3666   scoped_ptr<wallet::Instrument> inputted_instrument =
3667       CreateTransientInstrument();
3668
3669   scoped_ptr<wallet::Address> inputted_address;
3670   if (active_address_id_.empty() && IsShippingAddressRequired()) {
3671     if (ShouldUseBillingForShipping()) {
3672       const wallet::Address& address = inputted_instrument ?
3673           *inputted_instrument->address() : active_instrument->address();
3674       // Try to find an exact matched shipping address and use it for shipping,
3675       // otherwise save it as a new shipping address. http://crbug.com/225442
3676       const wallet::Address* duplicated_address =
3677           FindDuplicateAddress(wallet_items_->addresses(), address);
3678       if (duplicated_address) {
3679         active_address_id_ = duplicated_address->object_id();
3680         DCHECK(!active_address_id_.empty());
3681       } else {
3682         inputted_address.reset(new wallet::Address(address));
3683         DCHECK(inputted_address->object_id().empty());
3684       }
3685     } else {
3686       inputted_address = CreateTransientAddress();
3687     }
3688   }
3689
3690   // If there's neither an address nor instrument to save, |GetFullWallet()|
3691   // is called when the risk fingerprint is loaded.
3692   if (!active_instrument_id_.empty() &&
3693       (!active_address_id_.empty() || !IsShippingAddressRequired())) {
3694     GetFullWallet();
3695     return;
3696   }
3697
3698   GetWalletClient()->SaveToWallet(
3699       inputted_instrument.Pass(),
3700       inputted_address.Pass(),
3701       IsEditingExistingData(SECTION_CC_BILLING) ? active_instrument : NULL,
3702       IsEditingExistingData(SECTION_SHIPPING) ? active_address : NULL);
3703 }
3704
3705 scoped_ptr<wallet::Instrument> AutofillDialogControllerImpl::
3706     CreateTransientInstrument() {
3707   if (!active_instrument_id_.empty())
3708     return scoped_ptr<wallet::Instrument>();
3709
3710   FieldValueMap output;
3711   view_->GetUserInput(SECTION_CC_BILLING, &output);
3712
3713   CreditCard card;
3714   AutofillProfile profile;
3715   base::string16 cvc;
3716   GetBillingInfoFromOutputs(output, &card, &cvc, &profile);
3717   CanonicalizeState(validator_.get(), &profile);
3718
3719   return scoped_ptr<wallet::Instrument>(
3720       new wallet::Instrument(card, cvc, profile));
3721 }
3722
3723 scoped_ptr<wallet::Address>AutofillDialogControllerImpl::
3724     CreateTransientAddress() {
3725   // If not using billing for shipping, just scrape the view.
3726   FieldValueMap output;
3727   view_->GetUserInput(SECTION_SHIPPING, &output);
3728
3729   AutofillProfile profile;
3730   FillFormGroupFromOutputs(output, &profile);
3731   profile.set_language_code(shipping_address_language_code_);
3732   CanonicalizeState(validator_.get(), &profile);
3733
3734   return scoped_ptr<wallet::Address>(new wallet::Address(profile));
3735 }
3736
3737 void AutofillDialogControllerImpl::GetFullWallet() {
3738   DCHECK(is_submitting_);
3739   DCHECK(IsPayingWithWallet());
3740   DCHECK(wallet_items_);
3741   DCHECK(!active_instrument_id_.empty());
3742   DCHECK(!active_address_id_.empty() || !IsShippingAddressRequired());
3743
3744   std::vector<wallet::WalletClient::RiskCapability> capabilities;
3745   capabilities.push_back(wallet::WalletClient::VERIFY_CVC);
3746
3747   GetWalletClient()->GetFullWallet(wallet::WalletClient::FullWalletRequest(
3748       active_instrument_id_,
3749       active_address_id_,
3750       wallet_items_->google_transaction_id(),
3751       capabilities,
3752       wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)));
3753 }
3754
3755 void AutofillDialogControllerImpl::HandleSaveOrUpdateRequiredActions(
3756     const std::vector<wallet::RequiredAction>& required_actions) {
3757   DCHECK(!required_actions.empty());
3758
3759   // TODO(ahutter): Investigate if we need to support more generic actions on
3760   // this call such as GAIA_AUTH. See crbug.com/243457.
3761   for (std::vector<wallet::RequiredAction>::const_iterator iter =
3762            required_actions.begin();
3763        iter != required_actions.end(); ++iter) {
3764     if (*iter != wallet::INVALID_FORM_FIELD) {
3765       // TODO(dbeam): handle this more gracefully.
3766       DisableWallet(wallet::WalletClient::UNKNOWN_ERROR);
3767     }
3768   }
3769   SetIsSubmitting(false);
3770 }
3771
3772 void AutofillDialogControllerImpl::FinishSubmit() {
3773   if (IsPayingWithWallet()) {
3774     ScopedViewUpdates updates(view_.get());
3775     view_->UpdateOverlay();
3776
3777     card_generated_animation_.Start();
3778     return;
3779   }
3780   DoFinishSubmit();
3781 }
3782
3783 void AutofillDialogControllerImpl::AnimationProgressed(
3784     const gfx::Animation* animation) {
3785   DCHECK_EQ(animation, &card_generated_animation_);
3786   PushOverlayUpdate();
3787 }
3788
3789 void AutofillDialogControllerImpl::AnimationEnded(
3790     const gfx::Animation* animation) {
3791   DCHECK_EQ(animation, &card_generated_animation_);
3792   DoFinishSubmit();
3793 }
3794
3795 void AutofillDialogControllerImpl::OnAddressValidationRulesLoaded(
3796     const std::string& country_code,
3797     bool success) {
3798   // Rules may load instantly (during initialization, before the view is
3799   // even ready). We'll validate when the view is created.
3800   if (!view_)
3801     return;
3802
3803   ScopedViewUpdates updates(view_.get());
3804
3805   // TODO(dbeam): should we retry on failure?
3806   for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3807     DialogSection section = static_cast<DialogSection>(i);
3808     if (!SectionIsActive(section) ||
3809         CountryCodeForSection(section) != country_code) {
3810       continue;
3811     }
3812
3813     if (IsManuallyEditingSection(section) &&
3814         needs_validation_.count(section)) {
3815       view_->ValidateSection(section);
3816       needs_validation_.erase(section);
3817     } else if (success) {
3818       ShowEditUiIfBadSuggestion(section);
3819       UpdateSection(section);
3820     }
3821   }
3822 }
3823
3824 void AutofillDialogControllerImpl::DoFinishSubmit() {
3825   FillOutputForSection(SECTION_CC);
3826   FillOutputForSection(SECTION_BILLING);
3827   FillOutputForSection(SECTION_CC_BILLING);
3828
3829   if (ShouldUseBillingForShipping()) {
3830     FillOutputForSectionWithComparator(
3831         SECTION_BILLING,
3832         base::Bind(ServerTypeMatchesShippingField));
3833     FillOutputForSectionWithComparator(
3834         SECTION_CC,
3835         base::Bind(ServerTypeMatchesShippingField));
3836     FillOutputForSectionWithComparator(
3837         SECTION_CC_BILLING,
3838         base::Bind(ServerTypeMatchesShippingField));
3839   } else {
3840     FillOutputForSection(SECTION_SHIPPING);
3841   }
3842
3843   if (IsPayingWithWallet()) {
3844     if (SectionIsActive(SECTION_SHIPPING)) {
3845       profile_->GetPrefs()->SetBoolean(
3846           ::prefs::kAutofillDialogWalletShippingSameAsBilling,
3847           suggested_shipping_.GetItemKeyForCheckedItem() == kSameAsBillingKey);
3848     }
3849   } else if (ShouldOfferToSaveInChrome()) {
3850     for (size_t i = SECTION_MIN; i <= SECTION_MAX; ++i) {
3851       DialogSection section = static_cast<DialogSection>(i);
3852       if (!SectionIsActive(section))
3853         continue;
3854
3855       SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
3856       std::string item_key = model->GetItemKeyForCheckedItem();
3857       if (IsASuggestionItemKey(item_key) || item_key == kSameAsBillingKey) {
3858         PersistAutofillChoice(section, item_key);
3859       } else if (item_key == kAddNewItemKey && ShouldSaveDetailsLocally()) {
3860         DCHECK(newly_saved_data_model_guids_.count(section));
3861         PersistAutofillChoice(section, newly_saved_data_model_guids_[section]);
3862       }
3863     }
3864
3865     profile_->GetPrefs()->SetBoolean(::prefs::kAutofillDialogSaveData,
3866                                      view_->SaveDetailsLocally());
3867   }
3868
3869   // On a successful submit, if the user manually selected "pay without wallet",
3870   // stop trying to pay with Wallet on future runs of the dialog. On the other
3871   // hand, if there was an error that prevented the user from having the choice
3872   // of using Wallet, leave the pref alone.
3873   if (!wallet_error_notification_ &&
3874       account_chooser_model_->HasAccountsToChoose()) {
3875     profile_->GetPrefs()->SetBoolean(
3876         ::prefs::kAutofillDialogPayWithoutWallet,
3877         !account_chooser_model_->WalletIsSelected());
3878   }
3879
3880   LogOnFinishSubmitMetrics();
3881
3882   // Callback should be called as late as possible.
3883   callback_.Run(AutofillManagerDelegate::AutocompleteResultSuccess,
3884                 base::string16(),
3885                 &form_structure_);
3886   data_was_passed_back_ = true;
3887
3888   // This might delete us.
3889   Hide();
3890 }
3891
3892 void AutofillDialogControllerImpl::PersistAutofillChoice(
3893     DialogSection section,
3894     const std::string& guid) {
3895   DCHECK(!IsPayingWithWallet() && ShouldOfferToSaveInChrome());
3896   scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
3897   value->SetString(kGuidPrefKey, guid);
3898
3899   DictionaryPrefUpdate updater(profile()->GetPrefs(),
3900                                ::prefs::kAutofillDialogAutofillDefault);
3901   base::DictionaryValue* autofill_choice = updater.Get();
3902   autofill_choice->Set(SectionToPrefString(section), value.release());
3903 }
3904
3905 void AutofillDialogControllerImpl::GetDefaultAutofillChoice(
3906     DialogSection section,
3907     std::string* guid) {
3908   DCHECK(!IsPayingWithWallet() && IsAutofillEnabled());
3909   // The default choice is the first thing in the menu that is a suggestion
3910   // item.
3911   SuggestionsMenuModel* model = SuggestionsMenuModelForSection(section);
3912   for (int i = 0; i < model->GetItemCount(); ++i) {
3913     // Try the first suggestion item that is enabled.
3914     if (IsASuggestionItemKey(model->GetItemKeyAt(i)) && model->IsEnabledAt(i)) {
3915       *guid = model->GetItemKeyAt(i);
3916       return;
3917     // Fall back to the first non-suggestion key.
3918     } else if (!IsASuggestionItemKey(model->GetItemKeyAt(i)) && guid->empty()) {
3919       *guid = model->GetItemKeyAt(i);
3920     }
3921   }
3922 }
3923
3924 bool AutofillDialogControllerImpl::GetAutofillChoice(DialogSection section,
3925                                                      std::string* guid) {
3926   DCHECK(!IsPayingWithWallet() && IsAutofillEnabled());
3927   const base::DictionaryValue* choices = profile()->GetPrefs()->GetDictionary(
3928       ::prefs::kAutofillDialogAutofillDefault);
3929   if (!choices)
3930     return false;
3931
3932   const base::DictionaryValue* choice = NULL;
3933   if (!choices->GetDictionary(SectionToPrefString(section), &choice))
3934     return false;
3935
3936   choice->GetString(kGuidPrefKey, guid);
3937   return true;
3938 }
3939
3940 void AutofillDialogControllerImpl::LogOnFinishSubmitMetrics() {
3941   GetMetricLogger().LogDialogUiDuration(
3942       base::Time::Now() - dialog_shown_timestamp_,
3943       AutofillMetrics::DIALOG_ACCEPTED);
3944
3945   GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_ACCEPTED);
3946
3947   AutofillMetrics::DialogDismissalState dismissal_state;
3948   if (!IsManuallyEditingAnySection()) {
3949     dismissal_state = IsPayingWithWallet() ?
3950         AutofillMetrics::DIALOG_ACCEPTED_EXISTING_WALLET_DATA :
3951         AutofillMetrics::DIALOG_ACCEPTED_EXISTING_AUTOFILL_DATA;
3952   } else if (IsPayingWithWallet()) {
3953     dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_SAVE_TO_WALLET;
3954   } else if (ShouldSaveDetailsLocally()) {
3955     dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_SAVE_TO_AUTOFILL;
3956   } else {
3957     dismissal_state = AutofillMetrics::DIALOG_ACCEPTED_NO_SAVE;
3958   }
3959
3960   GetMetricLogger().LogDialogDismissalState(dismissal_state);
3961 }
3962
3963 void AutofillDialogControllerImpl::LogOnCancelMetrics() {
3964   GetMetricLogger().LogDialogUiEvent(AutofillMetrics::DIALOG_UI_CANCELED);
3965
3966   AutofillMetrics::DialogDismissalState dismissal_state;
3967   if (ShouldShowSignInWebView())
3968     dismissal_state = AutofillMetrics::DIALOG_CANCELED_DURING_SIGNIN;
3969   else if (!IsManuallyEditingAnySection())
3970     dismissal_state = AutofillMetrics::DIALOG_CANCELED_NO_EDITS;
3971   else if (AllSectionsAreValid())
3972     dismissal_state = AutofillMetrics::DIALOG_CANCELED_NO_INVALID_FIELDS;
3973   else
3974     dismissal_state = AutofillMetrics::DIALOG_CANCELED_WITH_INVALID_FIELDS;
3975
3976   GetMetricLogger().LogDialogDismissalState(dismissal_state);
3977
3978   GetMetricLogger().LogDialogUiDuration(
3979       base::Time::Now() - dialog_shown_timestamp_,
3980       AutofillMetrics::DIALOG_CANCELED);
3981 }
3982
3983 void AutofillDialogControllerImpl::LogSuggestionItemSelectedMetric(
3984     const SuggestionsMenuModel& model) {
3985   DialogSection section = SectionForSuggestionsMenuModel(model);
3986
3987   AutofillMetrics::DialogUiEvent dialog_ui_event;
3988   if (model.GetItemKeyForCheckedItem() == kAddNewItemKey) {
3989     // Selected to add a new item.
3990     dialog_ui_event = common::DialogSectionToUiItemAddedEvent(section);
3991   } else if (IsASuggestionItemKey(model.GetItemKeyForCheckedItem())) {
3992     // Selected an existing item.
3993     dialog_ui_event = common::DialogSectionToUiSelectionChangedEvent(section);
3994   } else {
3995     // TODO(estade): add logging for "Manage items" or "Use billing for
3996     // shipping"?
3997     return;
3998   }
3999
4000   GetMetricLogger().LogDialogUiEvent(dialog_ui_event);
4001 }
4002
4003 void AutofillDialogControllerImpl::LogDialogLatencyToShow() {
4004   if (was_ui_latency_logged_)
4005     return;
4006
4007   GetMetricLogger().LogDialogLatencyToShow(
4008       base::Time::Now() - dialog_shown_timestamp_);
4009   was_ui_latency_logged_ = true;
4010 }
4011
4012 AutofillMetrics::DialogInitialUserStateMetric
4013     AutofillDialogControllerImpl::GetInitialUserState() const {
4014   // Consider a user to be an Autofill user if the user has any credit cards
4015   // or addresses saved. Check that the item count is greater than 2 because
4016   // an "empty" menu still has the "add new" menu item and "manage" menu item.
4017   const bool has_autofill_profiles =
4018       suggested_cc_.GetItemCount() > 2 ||
4019       suggested_billing_.GetItemCount() > 2;
4020
4021   if (SignedInState() != SIGNED_IN) {
4022     // Not signed in.
4023     return has_autofill_profiles ?
4024         AutofillMetrics::DIALOG_USER_NOT_SIGNED_IN_HAS_AUTOFILL :
4025         AutofillMetrics::DIALOG_USER_NOT_SIGNED_IN_NO_AUTOFILL;
4026   }
4027
4028   // Signed in.
4029   if (wallet_items_->instruments().empty()) {
4030     // No Wallet items.
4031     return has_autofill_profiles ?
4032         AutofillMetrics::DIALOG_USER_SIGNED_IN_NO_WALLET_HAS_AUTOFILL :
4033         AutofillMetrics::DIALOG_USER_SIGNED_IN_NO_WALLET_NO_AUTOFILL;
4034   }
4035
4036   // Has Wallet items.
4037   return has_autofill_profiles ?
4038       AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_HAS_AUTOFILL :
4039       AutofillMetrics::DIALOG_USER_SIGNED_IN_HAS_WALLET_NO_AUTOFILL;
4040 }
4041
4042 void AutofillDialogControllerImpl::MaybeShowCreditCardBubble() {
4043   if (!data_was_passed_back_)
4044     return;
4045
4046   if (newly_saved_card_) {
4047     scoped_ptr<AutofillProfile> billing_profile;
4048     if (IsManuallyEditingSection(SECTION_BILLING)) {
4049       // Scrape the view as the user's entering or updating information.
4050       FieldValueMap outputs;
4051       view_->GetUserInput(SECTION_BILLING, &outputs);
4052       billing_profile.reset(new AutofillProfile);
4053       FillFormGroupFromOutputs(outputs, billing_profile.get());
4054       billing_profile->set_language_code(billing_address_language_code_);
4055     } else {
4056       // Just snag the currently suggested profile.
4057       std::string item_key = SuggestionsMenuModelForSection(SECTION_BILLING)->
4058           GetItemKeyForCheckedItem();
4059       AutofillProfile* profile = GetManager()->GetProfileByGUID(item_key);
4060       billing_profile.reset(new AutofillProfile(*profile));
4061     }
4062
4063     ShowNewCreditCardBubble(newly_saved_card_.Pass(),
4064                             billing_profile.Pass());
4065     return;
4066   }
4067
4068   if (!full_wallet_ || !full_wallet_->billing_address())
4069     return;
4070
4071   GeneratedCreditCardBubbleController::Show(
4072       web_contents(),
4073       full_wallet_->TypeAndLastFourDigits(),
4074       backing_card_last_four_);
4075 }
4076
4077 void AutofillDialogControllerImpl::OnSubmitButtonDelayEnd() {
4078   if (!view_)
4079     return;
4080   ScopedViewUpdates updates(view_.get());
4081   view_->UpdateButtonStrip();
4082 }
4083
4084 void AutofillDialogControllerImpl::FetchWalletCookie() {
4085   net::URLRequestContextGetter* request_context = profile_->GetRequestContext();
4086   signin_helper_.reset(new wallet::WalletSigninHelper(this, request_context));
4087   signin_helper_->StartWalletCookieValueFetch();
4088 }
4089
4090 }  // namespace autofill