Home | History | Annotate | Download | only in chromium
      1 // Copyright 2014 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 "third_party/libaddressinput/chromium/chrome_address_validator.h"
      6 
      7 #include <cmath>
      8 
      9 #include "base/bind.h"
     10 #include "base/location.h"
     11 #include "base/logging.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "third_party/libaddressinput/chromium/addressinput_util.h"
     14 #include "third_party/libaddressinput/chromium/input_suggester.h"
     15 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
     16 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_normalizer.h"
     17 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
     18 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
     19 
     20 namespace autofill {
     21 namespace {
     22 
     23 using ::i18n::addressinput::AddressData;
     24 using ::i18n::addressinput::AddressField;
     25 using ::i18n::addressinput::AddressNormalizer;
     26 using ::i18n::addressinput::BuildCallback;
     27 using ::i18n::addressinput::FieldProblemMap;
     28 using ::i18n::addressinput::PreloadSupplier;
     29 using ::i18n::addressinput::Source;
     30 using ::i18n::addressinput::Storage;
     31 
     32 using ::i18n::addressinput::ADMIN_AREA;
     33 using ::i18n::addressinput::DEPENDENT_LOCALITY;
     34 using ::i18n::addressinput::POSTAL_CODE;
     35 
     36 // The maximum number attempts to load rules.
     37 static const int kMaxAttemptsNumber = 8;
     38 
     39 }  // namespace
     40 
     41 AddressValidator::AddressValidator(scoped_ptr<Source> source,
     42                                    scoped_ptr<Storage> storage,
     43                                    LoadRulesListener* load_rules_listener)
     44     : supplier_(new PreloadSupplier(source.release(),
     45                                     storage.release())),
     46       input_suggester_(new InputSuggester(supplier_.get())),
     47       normalizer_(new AddressNormalizer(supplier_.get())),
     48       validator_(new ::i18n::addressinput::AddressValidator(supplier_.get())),
     49       validated_(BuildCallback(this, &AddressValidator::Validated)),
     50       rules_loaded_(BuildCallback(this, &AddressValidator::RulesLoaded)),
     51       load_rules_listener_(load_rules_listener),
     52       weak_factory_(this) {}
     53 
     54 AddressValidator::~AddressValidator() {}
     55 
     56 void AddressValidator::LoadRules(const std::string& region_code) {
     57   attempts_number_[region_code] = 0;
     58   supplier_->LoadRules(region_code, *rules_loaded_);
     59 }
     60 
     61 AddressValidator::Status AddressValidator::ValidateAddress(
     62     const AddressData& address,
     63     const FieldProblemMap* filter,
     64     FieldProblemMap* problems) const {
     65   if (supplier_->IsPending(address.region_code)) {
     66     if (problems)
     67       addressinput::ValidateRequiredFields(address, filter, problems);
     68     return RULES_NOT_READY;
     69   }
     70 
     71   if (!supplier_->IsLoaded(address.region_code)) {
     72     if (problems)
     73       addressinput::ValidateRequiredFields(address, filter, problems);
     74     return RULES_UNAVAILABLE;
     75   }
     76 
     77   if (!problems)
     78     return SUCCESS;
     79 
     80   validator_->Validate(address,
     81                        true,  // Allow postal office boxes.
     82                        true,  // Require recipient name.
     83                        filter,
     84                        problems,
     85                        *validated_);
     86 
     87   return SUCCESS;
     88 }
     89 
     90 AddressValidator::Status AddressValidator::GetSuggestions(
     91     const AddressData& user_input,
     92     AddressField focused_field,
     93     size_t suggestion_limit,
     94     std::vector<AddressData>* suggestions) const {
     95   if (supplier_->IsPending(user_input.region_code))
     96     return RULES_NOT_READY;
     97 
     98   if (!supplier_->IsLoaded(user_input.region_code))
     99     return RULES_UNAVAILABLE;
    100 
    101   if (!suggestions)
    102     return SUCCESS;
    103 
    104   suggestions->clear();
    105 
    106   if (focused_field == POSTAL_CODE ||
    107       (focused_field >= ADMIN_AREA && focused_field <= DEPENDENT_LOCALITY)) {
    108     input_suggester_->GetSuggestions(
    109         user_input, focused_field, suggestion_limit, suggestions);
    110   }
    111 
    112   return SUCCESS;
    113 }
    114 
    115 bool AddressValidator::CanonicalizeAdministrativeArea(
    116     AddressData* address) const {
    117   if (!supplier_->IsLoaded(address->region_code))
    118     return false;
    119 
    120   // TODO: It would probably be beneficial to use the full canonicalization.
    121   AddressData tmp(*address);
    122   normalizer_->Normalize(&tmp);
    123   address->administrative_area = tmp.administrative_area;
    124 
    125   return true;
    126 }
    127 
    128 AddressValidator::AddressValidator()
    129     : load_rules_listener_(NULL), weak_factory_(this) {}
    130 
    131 base::TimeDelta AddressValidator::GetBaseRetryPeriod() const {
    132   return base::TimeDelta::FromSeconds(8);
    133 }
    134 
    135 void AddressValidator::Validated(bool success,
    136                                  const AddressData&,
    137                                  const FieldProblemMap&) {
    138   DCHECK(success);
    139 }
    140 
    141 void AddressValidator::RulesLoaded(bool success,
    142                                    const std::string& region_code,
    143                                    int) {
    144   if (load_rules_listener_)
    145     load_rules_listener_->OnAddressValidationRulesLoaded(region_code, success);
    146 
    147   // Count the first failed attempt to load rules as well.
    148   if (success || attempts_number_[region_code] + 1 >= kMaxAttemptsNumber)
    149     return;
    150 
    151   base::MessageLoop::current()->PostDelayedTask(
    152       FROM_HERE,
    153       base::Bind(&AddressValidator::RetryLoadRules,
    154                  weak_factory_.GetWeakPtr(),
    155                  region_code),
    156       GetBaseRetryPeriod() * pow(2, attempts_number_[region_code]++));
    157 }
    158 
    159 void AddressValidator::RetryLoadRules(const std::string& region_code) {
    160   // Do not reset retry count.
    161   supplier_->LoadRules(region_code, *rules_loaded_);
    162 }
    163 
    164 }  // namespace autofill
    165