Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / libaddressinput / src / cpp / src / region_data_builder.cc
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 <libaddressinput/region_data_builder.h>
16
17 #include <libaddressinput/address_data.h>
18 #include <libaddressinput/preload_supplier.h>
19 #include <libaddressinput/region_data.h>
20 #include <libaddressinput/util/basictypes.h>
21
22 #include <cassert>
23 #include <cstddef>
24 #include <string>
25 #include <utility>
26 #include <vector>
27
28 #include "language.h"
29 #include "lookup_key.h"
30 #include "region_data_constants.h"
31 #include "rule.h"
32
33 namespace i18n {
34 namespace addressinput {
35
36 namespace {
37
38 // The maximum depth of lookup keys.
39 static const size_t kLookupKeysMaxDepth = arraysize(LookupKey::kHierarchy) - 1;
40
41 // Does not take ownership of |parent_region|, which is not allowed to be NULL.
42 void BuildRegionTreeRecursively(
43     const std::map<std::string, const Rule*>& rules,
44     std::map<std::string, const Rule*>::const_iterator hint,
45     const LookupKey& parent_key,
46     RegionData* parent_region,
47     const std::vector<std::string>& keys,
48     bool prefer_latin_name,
49     size_t region_max_depth) {
50   assert(parent_region != NULL);
51
52   LookupKey lookup_key;
53   for (std::vector<std::string>::const_iterator key_it = keys.begin();
54        key_it != keys.end(); ++key_it) {
55     lookup_key.FromLookupKey(parent_key, *key_it);
56     const std::string& lookup_key_string =
57         lookup_key.ToKeyString(kLookupKeysMaxDepth);
58
59     ++hint;
60     if (hint == rules.end() || hint->first != lookup_key_string) {
61       hint = rules.find(lookup_key_string);
62       if (hint == rules.end()) {
63         return;
64       }
65     }
66
67     const Rule* rule = hint->second;
68     assert(rule != NULL);
69
70     const std::string& local_name = rule->GetName().empty()
71         ? *key_it : rule->GetName();
72     const std::string& name =
73         prefer_latin_name && !rule->GetLatinName().empty()
74             ? rule->GetLatinName() : local_name;
75     RegionData* region = parent_region->AddSubRegion(*key_it, name);
76
77     if (!rule->GetSubKeys().empty() &&
78         region_max_depth > parent_key.GetDepth()) {
79       BuildRegionTreeRecursively(rules,
80                                  hint,
81                                  lookup_key,
82                                  region,
83                                  rule->GetSubKeys(),
84                                  prefer_latin_name,
85                                  region_max_depth);
86     }
87   }
88 }
89
90 // The caller owns the result.
91 RegionData* BuildRegion(const std::map<std::string, const Rule*>& rules,
92                         const std::string& region_code,
93                         const Language& language) {
94   AddressData address;
95   address.region_code = region_code;
96
97   LookupKey lookup_key;
98   lookup_key.FromAddress(address);
99
100   std::map<std::string, const Rule*>::const_iterator hint =
101       rules.find(lookup_key.ToKeyString(kLookupKeysMaxDepth));
102   assert(hint != rules.end());
103
104   const Rule* rule = hint->second;
105   assert(rule != NULL);
106
107   RegionData* region = new RegionData(region_code);
108
109   // If there're sub-keys for field X, but field X is not used in this region
110   // code, then these sub-keys are skipped over. For example, CH has sub-keys
111   // for field ADMIN_AREA, but CH does not use ADMIN_AREA field.
112   size_t region_max_depth =
113       RegionDataConstants::GetMaxLookupKeyDepth(region_code);
114   if (region_max_depth > 0) {
115     BuildRegionTreeRecursively(rules,
116                                hint,
117                                lookup_key,
118                                region,
119                                rule->GetSubKeys(),
120                                language.has_latin_script,
121                                region_max_depth);
122   }
123
124   return region;
125 }
126
127 }  // namespace
128
129 RegionDataBuilder::RegionDataBuilder(PreloadSupplier* supplier)
130     : supplier_(supplier),
131       cache_() {
132   assert(supplier_ != NULL);
133 }
134
135 RegionDataBuilder::~RegionDataBuilder() {
136   for (RegionCodeDataMap::const_iterator region_it = cache_.begin();
137        region_it != cache_.end(); ++region_it) {
138     for (LanguageRegionMap::const_iterator
139          language_it = region_it->second->begin();
140          language_it != region_it->second->end(); ++language_it) {
141       delete language_it->second;
142     }
143     delete region_it->second;
144   }
145 }
146
147 const RegionData& RegionDataBuilder::Build(
148     const std::string& region_code,
149     const std::string& ui_language_tag,
150     std::string* best_region_tree_language_tag) {
151   assert(supplier_->IsLoaded(region_code));
152   assert(best_region_tree_language_tag != NULL);
153
154   // Look up the region tree in cache first before building it.
155   RegionCodeDataMap::const_iterator region_it = cache_.find(region_code);
156   if (region_it == cache_.end()) {
157     region_it =
158         cache_.insert(std::make_pair(region_code, new LanguageRegionMap)).first;
159   }
160
161   // No need to copy from default rule first, because only languages and Latin
162   // format are going to be used, which do not exist in the default rule.
163   Rule rule;
164   rule.ParseSerializedRule(RegionDataConstants::GetRegionData(region_code));
165   static const Language kUndefinedLanguage("und");
166   const Language& best_language =
167       rule.GetLanguages().empty()
168           ? kUndefinedLanguage
169           : ChooseBestAddressLanguage(rule, Language(ui_language_tag));
170   *best_region_tree_language_tag = best_language.tag;
171
172   LanguageRegionMap::const_iterator language_it =
173       region_it->second->find(best_language.tag);
174   if (language_it == region_it->second->end()) {
175     const std::map<std::string, const Rule*>& rules =
176         supplier_->GetRulesForRegion(region_code);
177     language_it =
178         region_it->second->insert(std::make_pair(best_language.tag,
179                                                  BuildRegion(rules,
180                                                              region_code,
181                                                              best_language)))
182             .first;
183   }
184
185   return *language_it->second;
186 }
187
188 }  // namespace addressinput
189 }  // namespace i18n