Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / search / history_data_store.cc
1 // Copyright 2013 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 "chrome/browser/ui/app_list/search/history_data_store.h"
6
7 #include "base/callback.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/json/json_string_value_serializer.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/values.h"
12
13 namespace app_list {
14
15 namespace {
16
17 const char kKeyVersion[] = "version";
18 const char kCurrentVersion[] = "1";
19
20 const char kKeyAssociations[] = "associations";
21 const char kKeyPrimary[] = "p";
22 const char kKeySecondary[] = "s";
23 const char kKeyUpdateTime[] = "t";
24
25 // Extracts strings from ListValue.
26 void GetSecondary(const base::ListValue* list,
27                   HistoryData::SecondaryDeque* secondary) {
28   HistoryData::SecondaryDeque results;
29   for (base::ListValue::const_iterator it = list->begin();
30        it != list->end(); ++it) {
31     std::string str;
32     if (!(*it)->GetAsString(&str))
33       return;
34
35     results.push_back(str);
36   }
37
38   secondary->swap(results);
39 }
40
41 // V1 format json dictionary:
42 //  {
43 //    "version": "1",
44 //    "associations": {
45 //      "user typed query": {
46 //        "p" : "result id of primary association",
47 //        "s" : [
48 //                "result id of 1st (oldest) secondary association",
49 //                ...
50 //                "result id of the newest secondary association"
51 //              ],
52 //        "t" : "last_update_timestamp"
53 //      },
54 //      ...
55 //    }
56 //  }
57 scoped_ptr<HistoryData::Associations> Parse(
58     scoped_ptr<base::DictionaryValue> dict) {
59   std::string version;
60   if (!dict->GetStringWithoutPathExpansion(kKeyVersion, &version) ||
61       version != kCurrentVersion) {
62     return scoped_ptr<HistoryData::Associations>();
63   }
64
65   const base::DictionaryValue* assoc_dict = NULL;
66   if (!dict->GetDictionaryWithoutPathExpansion(kKeyAssociations,
67                                                &assoc_dict) ||
68       !assoc_dict) {
69     return scoped_ptr<HistoryData::Associations>();
70   }
71
72   scoped_ptr<HistoryData::Associations> data(new HistoryData::Associations);
73   for (base::DictionaryValue::Iterator it(*assoc_dict);
74        !it.IsAtEnd(); it.Advance()) {
75     const base::DictionaryValue* entry_dict = NULL;
76     if (!it.value().GetAsDictionary(&entry_dict))
77       continue;
78
79     std::string primary;
80     std::string update_time_string;
81     if (!entry_dict->GetStringWithoutPathExpansion(kKeyPrimary, &primary) ||
82         !entry_dict->GetStringWithoutPathExpansion(kKeyUpdateTime,
83                                                    &update_time_string)) {
84       continue;
85     }
86
87     const base::ListValue* secondary_list = NULL;
88     HistoryData::SecondaryDeque secondary;
89     if (entry_dict->GetListWithoutPathExpansion(kKeySecondary, &secondary_list))
90       GetSecondary(secondary_list, &secondary);
91
92     const std::string& query = it.key();
93     HistoryData::Data& association_data = (*data.get())[query];
94     association_data.primary = primary;
95     association_data.secondary.swap(secondary);
96
97     int64 update_time_val;
98     base::StringToInt64(update_time_string, &update_time_val);
99     association_data.update_time =
100         base::Time::FromInternalValue(update_time_val);
101   }
102
103   return data.Pass();
104 }
105
106 }  // namespace
107
108 HistoryDataStore::HistoryDataStore()
109     : cached_dict_(new base::DictionaryValue()) {
110   Init(cached_dict_.get());
111 }
112
113 HistoryDataStore::HistoryDataStore(
114     scoped_refptr<DictionaryDataStore> data_store)
115     : data_store_(data_store) {
116   Init(data_store_->cached_dict());
117 }
118
119 HistoryDataStore::~HistoryDataStore() {
120 }
121
122 void HistoryDataStore::Init(base::DictionaryValue* cached_dict) {
123   DCHECK(cached_dict);
124   cached_dict->SetString(kKeyVersion, kCurrentVersion);
125   cached_dict->Set(kKeyAssociations, new base::DictionaryValue);
126 }
127
128 void HistoryDataStore::Flush(
129     const DictionaryDataStore::OnFlushedCallback& on_flushed) {
130   if (data_store_.get())
131     data_store_->Flush(on_flushed);
132   else
133     on_flushed.Run();
134 }
135
136 void HistoryDataStore::Load(
137     const HistoryDataStore::OnLoadedCallback& on_loaded) {
138   if (data_store_.get()) {
139     data_store_->Load(base::Bind(&HistoryDataStore::OnDictionaryLoadedCallback,
140                                  this,
141                                  on_loaded));
142   } else {
143     OnDictionaryLoadedCallback(
144         on_loaded, make_scoped_ptr(cached_dict_->DeepCopy()));
145   }
146 }
147
148 void HistoryDataStore::SetPrimary(const std::string& query,
149                                   const std::string& result) {
150   base::DictionaryValue* entry_dict = GetEntryDict(query);
151   entry_dict->SetWithoutPathExpansion(kKeyPrimary,
152                                       new base::StringValue(result));
153   if (data_store_.get())
154     data_store_->ScheduleWrite();
155 }
156
157 void HistoryDataStore::SetSecondary(
158     const std::string& query,
159     const HistoryData::SecondaryDeque& results) {
160   scoped_ptr<base::ListValue> results_list(new base::ListValue);
161   for (size_t i = 0; i< results.size(); ++i)
162     results_list->AppendString(results[i]);
163
164   base::DictionaryValue* entry_dict = GetEntryDict(query);
165   entry_dict->SetWithoutPathExpansion(kKeySecondary, results_list.release());
166   if (data_store_.get())
167     data_store_->ScheduleWrite();
168 }
169
170 void HistoryDataStore::SetUpdateTime(const std::string& query,
171                                      const base::Time& update_time) {
172   base::DictionaryValue* entry_dict = GetEntryDict(query);
173   entry_dict->SetWithoutPathExpansion(kKeyUpdateTime,
174                                       new base::StringValue(base::Int64ToString(
175                                           update_time.ToInternalValue())));
176   if (data_store_.get())
177     data_store_->ScheduleWrite();
178 }
179
180 void HistoryDataStore::Delete(const std::string& query) {
181   base::DictionaryValue* assoc_dict = GetAssociationDict();
182   assoc_dict->RemoveWithoutPathExpansion(query, NULL);
183   if (data_store_.get())
184     data_store_->ScheduleWrite();
185 }
186
187 base::DictionaryValue* HistoryDataStore::GetAssociationDict() {
188   base::DictionaryValue* cached_dict =
189       cached_dict_ ? cached_dict_.get() : data_store_->cached_dict();
190   DCHECK(cached_dict);
191
192   base::DictionaryValue* assoc_dict = NULL;
193   CHECK(cached_dict->GetDictionary(kKeyAssociations, &assoc_dict) &&
194         assoc_dict);
195
196   return assoc_dict;
197 }
198
199 base::DictionaryValue* HistoryDataStore::GetEntryDict(
200     const std::string& query) {
201   base::DictionaryValue* assoc_dict = GetAssociationDict();
202
203   base::DictionaryValue* entry_dict = NULL;
204   if (!assoc_dict->GetDictionaryWithoutPathExpansion(query, &entry_dict)) {
205     // Creates one if none exists. Ownership is taken in the set call after.
206     entry_dict = new base::DictionaryValue;
207     assoc_dict->SetWithoutPathExpansion(query, entry_dict);
208   }
209
210   return entry_dict;
211 }
212
213 void HistoryDataStore::OnDictionaryLoadedCallback(
214     OnLoadedCallback callback, scoped_ptr<base::DictionaryValue> dict) {
215   if (!dict) {
216     callback.Run(scoped_ptr<HistoryData::Associations>());
217   } else {
218     callback.Run(Parse(dict.Pass()).Pass());
219   }
220 }
221
222 }  // namespace app_list