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#ifndef THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_INPUT_SUGGESTER_H_
6#define THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_INPUT_SUGGESTER_H_
7
8#include <stdint.h>
9#include <map>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/memory/scoped_ptr.h"
14#include "third_party/icu/source/i18n/unicode/coll.h"
15#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_field.h"
16#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_input_helper.h"
17#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h"
18#include "third_party/libaddressinput/src/cpp/include/libaddressinput/region_data_builder.h"
19
20namespace i18n {
21namespace addressinput {
22class PreloadSupplier;
23class RegionData;
24struct AddressData;
25}
26}
27
28namespace autofill {
29
30// Suggests address completions for a partially entered address from the user.
31class InputSuggester {
32 public:
33  // Does not take ownership of |supplier|, which should not be NULL.
34  explicit InputSuggester(::i18n::addressinput::PreloadSupplier* supplier);
35  ~InputSuggester();
36
37  // Fills in |suggestions| for the partially typed in |user_input|, assuming
38  // the user is typing in the |focused_field|. If the number of |suggestions|
39  // is over the |suggestion_limit|, then returns no |suggestions| at all.
40  //
41  // Sample user input 1:
42  //   country code = "US"
43  //   postal code = "90066"
44  //   focused field = POSTAL_CODE
45  //   suggestions limit = 1
46  // Suggestion:
47  //   [{administrative_area: "CA"}]
48  //
49  // Sample user input 2:
50  //   country code = "CN"
51  //   dependent locality = "Zongyang"
52  //   focused field = DEPENDENT_LOCALITY
53  //   suggestions limit = 10
54  // Suggestion:
55  //   [{dependent_locality: "Zongyang Xian",
56  //     locality: "Anqing Shi",
57  //     administrative_area: "Anhui Sheng"}]
58  //
59  // Builds the index for generating suggestions lazily.
60  //
61  // The |suggestions| parameter should not be NULL. The |focused_field|
62  // parameter should be either POSTAL_CODE or between ADMIN_AREA and
63  // DEPENDENT_LOCALITY inclusively.
64  void GetSuggestions(
65      const ::i18n::addressinput::AddressData& user_input,
66      ::i18n::addressinput::AddressField focused_field,
67      size_t suggestion_limit,
68      std::vector< ::i18n::addressinput::AddressData>* suggestions);
69
70 private:
71  class SubRegionData;
72
73  // Canonicalizes strings for case and diacritic insensitive comparison.
74  class StringCanonicalizer {
75   public:
76    // Initializes the canonicalizer. This is slow, so avoid calling it more
77    // often than necessary.
78    StringCanonicalizer();
79    ~StringCanonicalizer();
80
81    // Returns a 0-terminated canonical version of the string that can be used
82    // for comparing strings regardless of diacritics and capitalization.
83    //    Canonicalize("Texas") == Canonicalize("T\u00E9xas");
84    //    Canonicalize("Texas") == Canonicalize("teXas");
85    //    Canonicalize("Texas") != Canonicalize("California");
86    //
87    // The output is not human-readable.
88    //    Canonicalize("Texas") != "Texas";
89    //
90    // The |original| parameter should not be empty.
91    const std::vector<uint8_t>& Canonicalize(const std::string& original) const;
92
93   private:
94    int32_t buffer_size() const;
95
96    mutable std::vector<uint8_t> buffer_;
97    scoped_ptr<icu::Collator> collator_;
98
99    DISALLOW_COPY_AND_ASSIGN(StringCanonicalizer);
100  };
101
102  // The method to be invoked by |validated_| callback.
103  void Validated(bool success,
104                 const ::i18n::addressinput::AddressData&,
105                 const ::i18n::addressinput::FieldProblemMap&);
106
107  // Data source for region data.
108  ::i18n::addressinput::RegionDataBuilder region_data_builder_;
109
110  // Suggests sub-regions based on postal code.
111  const ::i18n::addressinput::AddressInputHelper input_helper_;
112
113  // Verifies that suggested sub-regions match the postal code.
114  ::i18n::addressinput::AddressValidator validator_;
115
116  // The callback for |validator_| to invoke when validation finishes.
117  const scoped_ptr<const ::i18n::addressinput::AddressValidator::Callback>
118      validated_;
119
120  // A mapping from a COUNTRY level region to a collection of all of its
121  // sub-regions along with metadata used to construct suggestions.
122  std::map<const ::i18n::addressinput::RegionData*, SubRegionData> sub_regions_;
123
124  // Canonicalizes strings for case and diacritic insensitive search of
125  // sub-region names.
126  StringCanonicalizer canonicalizer_;
127
128  DISALLOW_COPY_AND_ASSIGN(InputSuggester);
129};
130
131}  // namespace autofill
132
133#endif  // THIRD_PARTY_LIBADDRESSINPUT_CHROMIUM_INPUT_SUGGESTER_H_
134