1// Copyright (c) 2011 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/chromeos/cros_settings.h"
6
7#include "base/lazy_instance.h"
8#include "base/string_util.h"
9#include "base/values.h"
10#include "chrome/browser/chromeos/cros_settings_provider.h"
11#include "chrome/browser/chromeos/user_cros_settings_provider.h"
12#include "content/common/notification_details.h"
13#include "content/common/notification_source.h"
14#include "content/common/notification_type.h"
15
16namespace chromeos {
17
18static base::LazyInstance<CrosSettings> g_cros_settings(
19    base::LINKER_INITIALIZED);
20
21CrosSettings* CrosSettings::Get() {
22  // TODO(xiyaun): Use real stuff when underlying libcros is ready.
23  return g_cros_settings.Pointer();
24}
25
26bool CrosSettings::IsCrosSettings(const std::string& path) {
27  return StartsWithASCII(path, kCrosSettingsPrefix, true);
28}
29
30void CrosSettings::FireObservers(const char* path) {
31  DCHECK(CalledOnValidThread());
32  std::string path_str(path);
33  SettingsObserverMap::iterator observer_iterator =
34      settings_observers_.find(path_str);
35  if (observer_iterator == settings_observers_.end())
36    return;
37
38  NotificationObserverList::Iterator it(*(observer_iterator->second));
39  NotificationObserver* observer;
40  while ((observer = it.GetNext()) != NULL) {
41    observer->Observe(NotificationType::SYSTEM_SETTING_CHANGED,
42                      Source<CrosSettings>(this),
43                      Details<std::string>(&path_str));
44  }
45}
46
47void CrosSettings::Set(const std::string& path, Value* in_value) {
48  DCHECK(CalledOnValidThread());
49  CrosSettingsProvider* provider;
50  provider = GetProvider(path);
51  if (provider) {
52    provider->Set(path, in_value);
53  }
54}
55
56void CrosSettings::SetBoolean(const std::string& path, bool in_value) {
57  DCHECK(CalledOnValidThread());
58  Set(path, Value::CreateBooleanValue(in_value));
59}
60
61void CrosSettings::SetInteger(const std::string& path, int in_value) {
62  DCHECK(CalledOnValidThread());
63  Set(path, Value::CreateIntegerValue(in_value));
64}
65
66void CrosSettings::SetDouble(const std::string& path, double in_value) {
67  DCHECK(CalledOnValidThread());
68  Set(path, Value::CreateDoubleValue(in_value));
69}
70
71void CrosSettings::SetString(const std::string& path,
72                             const std::string& in_value) {
73  DCHECK(CalledOnValidThread());
74  Set(path, Value::CreateStringValue(in_value));
75}
76
77bool CrosSettings::AddSettingsProvider(CrosSettingsProvider* provider) {
78  DCHECK(CalledOnValidThread());
79  providers_.push_back(provider);
80  return true;
81}
82
83bool CrosSettings::RemoveSettingsProvider(CrosSettingsProvider* provider) {
84  DCHECK(CalledOnValidThread());
85  std::vector<CrosSettingsProvider*>::iterator it =
86      std::find(providers_.begin(), providers_.end(), provider);
87  if (it != providers_.end()) {
88    providers_.erase(it);
89    return true;
90  }
91  return false;
92}
93
94void CrosSettings::AddSettingsObserver(const char* path,
95                                       NotificationObserver* obs) {
96  DCHECK(path);
97  DCHECK(obs);
98  DCHECK(CalledOnValidThread());
99
100  if (!GetProvider(std::string(path))) {
101    NOTREACHED() << "Trying to add an observer for an unregistered setting: "
102        << path;
103    return;
104  }
105
106  // Get the settings observer list associated with the path.
107  NotificationObserverList* observer_list = NULL;
108  SettingsObserverMap::iterator observer_iterator =
109      settings_observers_.find(path);
110  if (observer_iterator == settings_observers_.end()) {
111    observer_list = new NotificationObserverList;
112    settings_observers_[path] = observer_list;
113  } else {
114    observer_list = observer_iterator->second;
115  }
116
117  // Verify that this observer doesn't already exist.
118  NotificationObserverList::Iterator it(*observer_list);
119  NotificationObserver* existing_obs;
120  while ((existing_obs = it.GetNext()) != NULL) {
121    DCHECK(existing_obs != obs) << path << " observer already registered";
122    if (existing_obs == obs)
123      return;
124  }
125
126  // Ok, safe to add the pref observer.
127  observer_list->AddObserver(obs);
128}
129
130void CrosSettings::RemoveSettingsObserver(const char* path,
131                                          NotificationObserver* obs) {
132  DCHECK(CalledOnValidThread());
133
134  SettingsObserverMap::iterator observer_iterator =
135      settings_observers_.find(path);
136  if (observer_iterator == settings_observers_.end()) {
137    return;
138  }
139
140  NotificationObserverList* observer_list = observer_iterator->second;
141  observer_list->RemoveObserver(obs);
142}
143
144CrosSettingsProvider* CrosSettings::GetProvider(
145    const std::string& path) const {
146  for (size_t i = 0; i < providers_.size(); ++i) {
147    if (providers_[i]->HandlesSetting(path)) {
148      return providers_[i];
149    }
150  }
151  return NULL;
152}
153
154bool CrosSettings::Get(const std::string& path, Value** out_value) const {
155  DCHECK(CalledOnValidThread());
156  CrosSettingsProvider* provider;
157  provider = GetProvider(path);
158  if (provider) {
159    return provider->Get(path, out_value);
160  }
161  return false;
162}
163
164bool CrosSettings::GetBoolean(const std::string& path,
165                              bool* bool_value) const {
166  DCHECK(CalledOnValidThread());
167  Value* value;
168  if (!Get(path, &value))
169    return false;
170
171  return value->GetAsBoolean(bool_value);
172}
173
174bool CrosSettings::GetInteger(const std::string& path,
175                              int* out_value) const {
176  DCHECK(CalledOnValidThread());
177  Value* value;
178  if (!Get(path, &value))
179    return false;
180
181  return value->GetAsInteger(out_value);
182}
183
184bool CrosSettings::GetDouble(const std::string& path,
185                             double* out_value) const {
186  DCHECK(CalledOnValidThread());
187  Value* value;
188  if (!Get(path, &value))
189    return false;
190
191  return value->GetAsDouble(out_value);
192}
193
194bool CrosSettings::GetString(const std::string& path,
195                             std::string* out_value) const {
196  DCHECK(CalledOnValidThread());
197  Value* value;
198  if (!Get(path, &value))
199    return false;
200
201  return value->GetAsString(out_value);
202}
203
204CrosSettings::CrosSettings() {
205}
206
207CrosSettings::~CrosSettings() {
208  DCHECK(providers_.empty());
209}
210
211}  // namespace chromeos
212