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