OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (C) 2014 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 | |
15 #include "country_rules_retriever.h" | |
16 | |
17 #include <libaddressinput/address_field.h> | |
18 #include <libaddressinput/callback.h> | |
19 #include <libaddressinput/util/basictypes.h> | |
20 #include <libaddressinput/util/scoped_ptr.h> | |
21 | |
22 #include <cassert> | |
23 #include <cstddef> | |
24 #include <map> | |
25 #include <string> | |
26 #include <utility> | |
27 | |
28 #include "retriever.h" | |
29 #include "rule.h" | |
30 #include "ruleset.h" | |
31 #include "util/stl_util.h" | |
32 | |
33 namespace i18n { | |
34 namespace addressinput { | |
35 | |
36 // Information about data requests sent to Retriever. This data is not returned | |
37 // as part of the ruleset, but is useful in constructing the ruleset | |
38 // asynchronously. | |
39 struct CountryRulesRetriever::RequestData { | |
40 // Does not take ownership of |parent|. | |
41 RequestData(Ruleset* parent, | |
42 AddressField level, | |
43 bool is_language_code, | |
44 const std::string& id) | |
45 : parent(parent), | |
46 level(level), | |
47 is_language_code(is_language_code), | |
48 id(id) {} | |
49 | |
50 ~RequestData() {} | |
51 | |
52 // The parent ruleset of the data being downloaded. If NULL, then this is the | |
53 // root ruleset at the COUNTRY level. The language-specific and sub-region | |
54 // rules are added to this ruleset. Owned by |CountryRulesRetriever|. | |
55 Ruleset* parent; | |
56 | |
57 // The level of the data being requested. Ranges from COUNTRY to | |
58 // DEPENDENT_LOCALITY. If COUNTRY, then the rule should use default rules from | |
59 // Rule::GetDefault(). | |
60 AddressField level; | |
61 | |
62 // If true, then |id| is a language. The data received for this request should | |
63 // be placed into a language-specific rule. | |
64 bool is_language_code; | |
65 | |
66 // Can be a region name (e.g. "CA") or a language (e.g. "fr"). Used to add a | |
67 // sub-region or a language-specific rule to |parent|. | |
68 std::string id; | |
69 }; | |
70 | |
71 CountryRulesRetriever::CountryRulesRetriever(scoped_ptr<Retriever> retriever) | |
72 : retriever_(retriever.Pass()), | |
73 requests_(), | |
74 country_code_(), | |
75 rules_ready_(), | |
76 root_(), | |
77 success_(true), | |
78 default_language_(), | |
79 languages_() { | |
80 assert(retriever_ != NULL); | |
81 } | |
82 | |
83 void CountryRulesRetriever::RetrieveRules(const std::string& country_code, | |
84 scoped_ptr<Callback> rules_ready) { | |
85 Reset(); | |
86 country_code_ = country_code; | |
87 rules_ready_.reset(rules_ready.release()); | |
88 | |
89 // Key construction: | |
90 // https://code.google.com/p/libaddressinput/wiki/AddressValidationMetadata | |
91 // Example of a country-level key: "data/CA". | |
92 std::string key = "data/" + country_code_; | |
93 requests_.insert(std::make_pair( | |
94 key, RequestData(NULL, COUNTRY, false, std::string()))); | |
95 | |
96 retriever_->Retrieve( | |
97 key, BuildCallback(this, &CountryRulesRetriever::OnDataReady)); | |
98 } | |
99 | |
100 void CountryRulesRetriever::OnDataReady(bool success, | |
101 const std::string& key, | |
102 const std::string& data) { | |
103 std::map<std::string, RequestData>::iterator request_it = | |
104 requests_.find(key); | |
105 if (request_it == requests_.end()) { | |
106 return; // An abandoned request. | |
107 } | |
108 | |
109 RequestData request = request_it->second; | |
110 requests_.erase(request_it); | |
111 | |
112 success_ &= success; | |
113 | |
114 // All country-level rules are based on the default rule. | |
115 scoped_ptr<Rule> rule(new Rule); | |
116 if (request.level == COUNTRY) { | |
117 rule->CopyFrom(Rule::GetDefault()); | |
118 } | |
119 | |
120 success_ &= rule->ParseSerializedRule(data); | |
121 | |
122 // Place the rule in the correct location in the ruleset. | |
123 Ruleset* ruleset = NULL; | |
124 if (request.is_language_code) { | |
125 assert(request.parent != NULL); | |
126 request.parent->AddLanguageCode(request.id, rule.Pass()); | |
127 ruleset = request.parent; | |
128 } else if (request.level == COUNTRY) { | |
129 // The default language and all supported languages for the country code are | |
130 // in the country-level rule without a language code identifier. For | |
131 // example: "data/CA". | |
132 default_language_ = rule->GetLanguage(); | |
133 languages_ = rule->GetLanguages(); | |
134 | |
135 root_.reset(new Ruleset(rule.Pass())); | |
136 ruleset = root_.get(); | |
137 } else { | |
138 assert(request.parent != NULL); | |
139 ruleset = request.parent->AddSubRegion(request.id, rule.Pass()); | |
140 } | |
141 | |
142 if (!request.is_language_code) { | |
143 // Retrieve the language-specific rules for this region. | |
144 for (std::vector<std::string>::const_iterator | |
145 lang_it = languages_.begin(); | |
146 lang_it != languages_.end(); | |
147 ++lang_it) { | |
148 if (*lang_it == default_language_) { | |
149 continue; | |
150 } | |
151 // Example of a language-specific key: "data/CA--fr". | |
152 std::string language_code_key = key + "--" + *lang_it; | |
153 requests_.insert(std::make_pair( | |
154 key, RequestData(ruleset, request.level, true, *lang_it))); | |
155 retriever_->Retrieve( | |
156 language_code_key, | |
157 BuildCallback(this, &CountryRulesRetriever::OnDataReady)); | |
158 } | |
159 | |
160 if (request.level < DEPENDENT_LOCALITY) { | |
161 // Retrieve the sub-region rules for this region. | |
162 for (std::vector<std::string>::const_iterator | |
163 subkey_it = ruleset->rule().GetSubKeys().begin(); | |
164 subkey_it != ruleset->rule().GetSubKeys().end(); | |
165 ++subkey_it) { | |
166 // Example of a sub-region key: "data/CA/AB". | |
167 std::string sub_region_key = key + "/" + *subkey_it; | |
168 requests_.insert(std::make_pair( | |
169 key, | |
170 RequestData(ruleset, | |
171 static_cast<AddressField>(request.level + 1), | |
172 false, | |
173 *subkey_it))); | |
174 retriever_->Retrieve( | |
175 sub_region_key, | |
176 BuildCallback(this, &CountryRulesRetriever::OnDataReady)); | |
177 } | |
178 } | |
179 } | |
180 | |
181 if (requests_.empty()) { | |
182 (*rules_ready_)(success_, country_code_, root_.Pass()); | |
183 Reset(); | |
184 } | |
185 } | |
186 | |
187 void CountryRulesRetriever::Reset() { | |
188 requests_.clear(); | |
189 country_code_.clear(); | |
190 rules_ready_.reset(); | |
191 root_.reset(); | |
192 success_ = true; | |
193 default_language_.clear(); | |
194 languages_.clear(); | |
195 rules_ready_.reset(); | |
196 default_language_.clear(); | |
197 languages_.clear(); | |
please use gerrit instead
2014/01/07 23:00:42
Err, copy-paste error. Fix incoming.
please use gerrit instead
2014/01/07 23:03:42
Done.
| |
198 } | |
199 | |
200 } // namespace addressinput | |
201 } // namespace i18n | |
OLD | NEW |