blob: 8e75eeca85e72ac4e48c43f2e2bb8a8f0ca06b2a [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/autofill/address.h"
#include "base/basictypes.h"
#include "base/string_util.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/field_types.h"
namespace {
const char16 kAddressSplitChars[] = {'-', ',', '#', '.', ' ', 0};
const AutoFillType::FieldTypeSubGroup kAutoFillAddressTypes[] = {
AutoFillType::ADDRESS_LINE1,
AutoFillType::ADDRESS_LINE2,
AutoFillType::ADDRESS_APT_NUM,
AutoFillType::ADDRESS_CITY,
AutoFillType::ADDRESS_STATE,
AutoFillType::ADDRESS_ZIP,
AutoFillType::ADDRESS_COUNTRY,
};
const int kAutoFillAddressLength = arraysize(kAutoFillAddressTypes);
} // namespace
Address::Address() {}
Address::~Address() {}
void Address::GetPossibleFieldTypes(const string16& text,
FieldTypeSet* possible_types) const {
DCHECK(possible_types);
// If the text to match against the field types is empty, then no results will
// match.
if (text.empty())
return;
if (IsLine1(text))
possible_types->insert(GetLine1Type());
if (IsLine2(text))
possible_types->insert(GetLine2Type());
if (IsAptNum(text))
possible_types->insert(GetAptNumType());
if (IsCity(text))
possible_types->insert(GetCityType());
if (IsState(text))
possible_types->insert(GetStateType());
if (IsZipCode(text))
possible_types->insert(GetZipCodeType());
if (IsCountry(text))
possible_types->insert(GetCountryType());
}
void Address::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
DCHECK(available_types);
if (!line1().empty())
available_types->insert(GetLine1Type());
if (!line2().empty())
available_types->insert(GetLine2Type());
if (!apt_num().empty())
available_types->insert(GetAptNumType());
if (!city().empty())
available_types->insert(GetCityType());
if (!state().empty())
available_types->insert(GetStateType());
if (!zip_code().empty())
available_types->insert(GetZipCodeType());
if (!country().empty())
available_types->insert(GetCountryType());
}
void Address::FindInfoMatches(const AutoFillType& type,
const string16& info,
std::vector<string16>* matched_text) const {
DCHECK(matched_text);
string16 match;
if (type.field_type() == UNKNOWN_TYPE) {
for (int i = 0; i < kAutoFillAddressLength; ++i) {
if (FindInfoMatchesHelper(kAutoFillAddressTypes[i], info, &match))
matched_text->push_back(match);
}
} else {
if (FindInfoMatchesHelper(type.subgroup(), info, &match))
matched_text->push_back(match);
}
}
string16 Address::GetFieldText(const AutoFillType& type) const {
AutoFillFieldType field_type = type.field_type();
if (field_type == GetLine1Type())
return line1();
if (field_type == GetLine2Type())
return line2();
if (field_type == GetAptNumType())
return apt_num();
if (field_type == GetCityType())
return city();
if (field_type == GetStateType())
return state();
if (field_type == GetZipCodeType())
return zip_code();
if (field_type == GetCountryType())
return country();
return string16();
}
void Address::SetInfo(const AutoFillType& type, const string16& value) {
FieldTypeSubGroup subgroup = type.subgroup();
if (subgroup == AutoFillType::ADDRESS_LINE1)
set_line1(value);
else if (subgroup == AutoFillType::ADDRESS_LINE2)
set_line2(value);
else if (subgroup == AutoFillType::ADDRESS_APT_NUM)
set_apt_num(value);
else if (subgroup == AutoFillType::ADDRESS_CITY)
set_city(value);
else if (subgroup == AutoFillType::ADDRESS_STATE)
set_state(value);
else if (subgroup == AutoFillType::ADDRESS_COUNTRY)
set_country(value);
else if (subgroup == AutoFillType::ADDRESS_ZIP)
set_zip_code(value);
else
NOTREACHED();
}
void Address::Clear() {
line1_tokens_.clear();
line1_.clear();
line2_tokens_.clear();
line2_.clear();
apt_num_.clear();
city_.clear();
state_.clear();
country_.clear();
zip_code_.clear();
}
void Address::Clone(const Address& address) {
set_line1(address.line1());
set_line2(address.line2());
set_apt_num(address.apt_num());
set_city(address.city());
set_state(address.state());
set_country(address.country());
set_zip_code(address.zip_code());
}
Address::Address(const Address& address)
: FormGroup(),
line1_tokens_(address.line1_tokens_),
line2_tokens_(address.line2_tokens_),
line1_(address.line1_),
line2_(address.line2_),
apt_num_(address.apt_num_),
city_(address.city_),
state_(address.state_),
country_(address.country_),
zip_code_(address.zip_code_) {
}
void Address::set_line1(const string16& line1) {
line1_ = line1;
line1_tokens_.clear();
Tokenize(line1, kAddressSplitChars, &line1_tokens_);
LineTokens::iterator iter;
for (iter = line1_tokens_.begin(); iter != line1_tokens_.end(); ++iter)
*iter = StringToLowerASCII(*iter);
}
void Address::set_line2(const string16& line2) {
line2_ = line2;
line2_tokens_.clear();
Tokenize(line2, kAddressSplitChars, &line2_tokens_);
LineTokens::iterator iter;
for (iter = line2_tokens_.begin(); iter != line2_tokens_.end(); ++iter)
*iter = StringToLowerASCII(*iter);
}
bool Address::IsLine1(const string16& text) const {
return IsLineMatch(text, line1_tokens_);
}
bool Address::IsLine2(const string16& text) const {
return IsLineMatch(text, line2_tokens_);
}
bool Address::IsAptNum(const string16& text) const {
return (StringToLowerASCII(apt_num_) == StringToLowerASCII(text));
}
bool Address::IsCity(const string16& text) const {
return (StringToLowerASCII(city_) == StringToLowerASCII(text));
}
bool Address::IsState(const string16& text) const {
return (StringToLowerASCII(state_) == StringToLowerASCII(text));
}
bool Address::IsCountry(const string16& text) const {
return (StringToLowerASCII(country_) == StringToLowerASCII(text));
}
bool Address::IsZipCode(const string16& text) const {
return zip_code_ == text;
}
bool Address::FindInfoMatchesHelper(const FieldTypeSubGroup& subgroup,
const string16& info,
string16* match) const {
DCHECK(match);
match->clear();
if (subgroup == AutoFillType::ADDRESS_LINE1 &&
StartsWith(line1(), info, false)) {
*match = line1();
} else if (subgroup == AutoFillType::ADDRESS_LINE2 &&
StartsWith(line2(), info, false)) {
*match = line2();
} else if (subgroup == AutoFillType::ADDRESS_APT_NUM &&
StartsWith(apt_num(), info, false)) {
*match = apt_num();
} else if (subgroup == AutoFillType::ADDRESS_CITY &&
StartsWith(city(), info, false)) {
*match = city();
} else if (subgroup == AutoFillType::ADDRESS_STATE &&
StartsWith(state(), info, false)) {
*match = state();
} else if (subgroup == AutoFillType::ADDRESS_COUNTRY &&
StartsWith(country(), info, false)) {
*match = country();
} else if (subgroup == AutoFillType::ADDRESS_ZIP &&
StartsWith(zip_code(), info, true)) {
*match = zip_code();
}
return !match->empty();
}
bool Address::IsLineMatch(const string16& text,
const LineTokens& line_tokens) const {
size_t line_tokens_size = line_tokens.size();
if (line_tokens_size == 0)
return false;
LineTokens text_tokens;
Tokenize(text, kAddressSplitChars, &text_tokens);
size_t text_tokens_size = text_tokens.size();
if (text_tokens_size == 0)
return false;
if (text_tokens_size > line_tokens_size)
return false;
// If each of the 'words' contained in the text are also present in the line,
// then we will consider the text to match the line.
LineTokens::iterator iter;
for (iter = text_tokens.begin(); iter != text_tokens.end(); ++iter) {
if (!IsWordInLine(*iter, line_tokens))
return false;
}
return true;
}
bool Address::IsWordInLine(const string16& word,
const LineTokens& line_tokens) const {
LineTokens::const_iterator iter;
for (iter = line_tokens.begin(); iter != line_tokens.end(); ++iter) {
if (StringToLowerASCII(word) == *iter)
return true;
}
return false;
}