1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/autofill/select_control_handler.h"
6
7#include <string>
8
9#include "base/basictypes.h"
10#include "base/logging.h"
11#include "base/string_number_conversions.h"
12#include "base/utf_string_conversions.h"
13#include "chrome/browser/autofill/autofill_country.h"
14#include "chrome/browser/autofill/autofill_profile.h"
15#include "chrome/browser/autofill/form_group.h"
16#include "webkit/glue/form_field.h"
17
18namespace {
19
20// TODO(jhawkins): Add more states/provinces.  See http://crbug.com/45039.
21
22class State {
23 public:
24  const char* name;
25  const char* abbreviation;
26
27  static const State all_states[];
28
29  static string16 Abbreviation(const string16& name);
30  static string16 FullName(const string16& abbreviation);
31};
32
33const State State::all_states[] = {
34  { "alabama", "al" },
35  { "alaska", "ak" },
36  { "arizona", "az" },
37  { "arkansas", "ar" },
38  { "california", "ca" },
39  { "colorado", "co" },
40  { "connecticut", "ct" },
41  { "delaware", "de" },
42  { "district of columbia", "dc" },
43  { "florida", "fl" },
44  { "georgia", "ga" },
45  { "hawaii", "hi" },
46  { "idaho", "id" },
47  { "illinois", "il" },
48  { "indiana", "in" },
49  { "iowa", "ia" },
50  { "kansas", "ks" },
51  { "kentucky", "ky" },
52  { "louisiana", "la" },
53  { "maine", "me" },
54  { "maryland", "md" },
55  { "massachusetts", "ma" },
56  { "michigan", "mi" },
57  { "minnesota", "mv" },
58  { "mississippi", "ms" },
59  { "missouri", "mo" },
60  { "montana", "mt" },
61  { "nebraska", "ne" },
62  { "nevada", "nv" },
63  { "new hampshire", "nh" },
64  { "new jersey", "nj" },
65  { "new mexico", "nm" },
66  { "new york", "ny" },
67  { "north carolina", "nc" },
68  { "north dakota", "nd" },
69  { "ohio", "oh" },
70  { "oklahoma", "ok" },
71  { "oregon", "or" },
72  { "pennsylvania", "pa" },
73  { "puerto rico", "pr" },
74  { "rhode island", "ri" },
75  { "south carolina", "sc" },
76  { "south dakota", "sd" },
77  { "tennessee", "tn" },
78  { "texas", "tx" },
79  { "utah", "ut" },
80  { "vermont", "vt" },
81  { "virginia", "va" },
82  { "washington", "wa" },
83  { "west Virginia", "wv" },
84  { "wisconsin", "wi" },
85  { "wyoming", "wy" },
86  { NULL, NULL }
87};
88
89string16 State::Abbreviation(const string16& name) {
90  for (const State *s = all_states ; s->name ; ++s)
91    if (LowerCaseEqualsASCII(name, s->name))
92      return ASCIIToUTF16(s->abbreviation);
93  return string16();
94}
95
96string16 State::FullName(const string16& abbreviation) {
97  for (const State *s = all_states ; s->name ; ++s)
98    if (LowerCaseEqualsASCII(abbreviation, s->abbreviation))
99      return ASCIIToUTF16(s->name);
100  return string16();
101}
102
103const char* const kMonthsAbbreviated[] = {
104  NULL,  // Padding so index 1 = month 1 = January.
105  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
106  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
107};
108
109const char* const kMonthsFull[] = {
110  NULL,  // Padding so index 1 = month 1 = January.
111  "January", "February", "March", "April", "May", "June",
112  "July", "August", "September", "October", "November", "December",
113};
114
115const char* const kMonthsNumeric[] = {
116  NULL,  // Padding so index 1 = month 1 = January.
117  "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
118};
119
120// Returns true if the value was successfully set, meaning |value| was found in
121// the list of select options in |field|.
122bool SetSelectControlValue(const string16& value,
123                           webkit_glue::FormField* field) {
124  string16 value_lowercase = StringToLowerASCII(value);
125
126  for (std::vector<string16>::const_iterator iter =
127           field->option_strings.begin();
128       iter != field->option_strings.end(); ++iter) {
129    if (value_lowercase == StringToLowerASCII(*iter)) {
130      field->value = *iter;
131      return true;
132    }
133  }
134
135  return false;
136}
137
138bool FillStateSelectControl(const string16& value,
139                            webkit_glue::FormField* field) {
140  string16 abbrev, full;
141  if (value.size() < 4U) {
142    abbrev = value;
143    full = State::FullName(value);
144  } else {
145    abbrev = State::Abbreviation(value);
146    full = value;
147  }
148
149  // Try the abbreviation name first.
150  if (!abbrev.empty() && SetSelectControlValue(abbrev, field))
151    return true;
152
153  if (full.empty())
154    return false;
155
156  return SetSelectControlValue(full, field);
157}
158
159bool FillCountrySelectControl(const FormGroup& form_group,
160                              webkit_glue::FormField* field) {
161  const AutofillProfile& profile =
162      static_cast<const AutofillProfile&>(form_group);
163  std::string country_code = profile.CountryCode();
164  std::string app_locale = AutofillCountry::ApplicationLocale();
165
166  for (std::vector<string16>::const_iterator iter =
167           field->option_strings.begin();
168       iter != field->option_strings.end();
169       ++iter) {
170    // Canonicalize each <option> value to a country code, and compare to the
171    // target country code.
172    if (country_code == AutofillCountry::GetCountryCode(*iter, app_locale)) {
173      field->value = *iter;
174      return true;
175    }
176  }
177
178  return false;
179}
180
181bool FillExpirationMonthSelectControl(const string16& value,
182                                      webkit_glue::FormField* field) {
183  int index = 0;
184  if (!base::StringToInt(value, &index) ||
185      index <= 0 ||
186      static_cast<size_t>(index) >= arraysize(kMonthsFull))
187    return false;
188
189  bool filled =
190      SetSelectControlValue(ASCIIToUTF16(kMonthsAbbreviated[index]), field) ||
191      SetSelectControlValue(ASCIIToUTF16(kMonthsFull[index]), field) ||
192      SetSelectControlValue(ASCIIToUTF16(kMonthsNumeric[index]), field);
193  return filled;
194}
195
196}  // namespace
197
198namespace autofill {
199
200void FillSelectControl(const FormGroup& form_group,
201                       AutofillFieldType type,
202                       webkit_glue::FormField* field) {
203  DCHECK(field);
204  DCHECK_EQ(ASCIIToUTF16("select-one"), field->form_control_type);
205
206  string16 field_text = form_group.GetInfo(type);
207  if (field_text.empty())
208    return;
209
210  string16 value;
211  for (size_t i = 0; i < field->option_strings.size(); ++i) {
212    if (field_text == field->option_strings[i]) {
213      // An exact match, use it.
214      value = field_text;
215      break;
216    }
217
218    if (StringToLowerASCII(field->option_strings[i]) ==
219        StringToLowerASCII(field_text)) {
220      // A match, but not in the same case. Save it in case an exact match is
221      // not found.
222      value = field->option_strings[i];
223    }
224  }
225
226  if (!value.empty()) {
227    field->value = value;
228    return;
229  }
230
231  if (type == ADDRESS_HOME_STATE || type == ADDRESS_BILLING_STATE)
232    FillStateSelectControl(field_text, field);
233  else if (type == ADDRESS_HOME_COUNTRY || type == ADDRESS_BILLING_COUNTRY)
234    FillCountrySelectControl(form_group, field);
235  else if (type == CREDIT_CARD_EXP_MONTH)
236    FillExpirationMonthSelectControl(field_text, field);
237
238  return;
239}
240
241bool IsValidState(const string16& value) {
242  return !State::Abbreviation(value).empty() || !State::FullName(value).empty();
243}
244
245}  // namespace autofill
246