1// Copyright (c) 2012 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 "base/prefs/overlay_user_pref_store.h"
6
7#include "base/memory/scoped_ptr.h"
8#include "base/values.h"
9
10OverlayUserPrefStore::OverlayUserPrefStore(
11    PersistentPrefStore* underlay)
12    : underlay_(underlay) {
13  underlay_->AddObserver(this);
14}
15
16bool OverlayUserPrefStore::IsSetInOverlay(const std::string& key) const {
17  return overlay_.GetValue(key, NULL);
18}
19
20void OverlayUserPrefStore::AddObserver(PrefStore::Observer* observer) {
21  observers_.AddObserver(observer);
22}
23
24void OverlayUserPrefStore::RemoveObserver(PrefStore::Observer* observer) {
25  observers_.RemoveObserver(observer);
26}
27
28bool OverlayUserPrefStore::HasObservers() const {
29  return observers_.might_have_observers();
30}
31
32bool OverlayUserPrefStore::IsInitializationComplete() const {
33  return underlay_->IsInitializationComplete();
34}
35
36bool OverlayUserPrefStore::GetValue(const std::string& key,
37                                    const base::Value** result) const {
38  // If the |key| shall NOT be stored in the overlay store, there must not
39  // be an entry.
40  DCHECK(ShallBeStoredInOverlay(key) || !overlay_.GetValue(key, NULL));
41
42  if (overlay_.GetValue(key, result))
43    return true;
44  return underlay_->GetValue(GetUnderlayKey(key), result);
45}
46
47bool OverlayUserPrefStore::GetMutableValue(const std::string& key,
48                                           base::Value** result) {
49  if (!ShallBeStoredInOverlay(key))
50    return underlay_->GetMutableValue(GetUnderlayKey(key), result);
51
52  if (overlay_.GetValue(key, result))
53    return true;
54
55  // Try to create copy of underlay if the overlay does not contain a value.
56  base::Value* underlay_value = NULL;
57  if (!underlay_->GetMutableValue(GetUnderlayKey(key), &underlay_value))
58    return false;
59
60  *result = underlay_value->DeepCopy();
61  overlay_.SetValue(key, *result);
62  return true;
63}
64
65void OverlayUserPrefStore::SetValue(const std::string& key,
66                                    base::Value* value) {
67  if (!ShallBeStoredInOverlay(key)) {
68    underlay_->SetValue(GetUnderlayKey(key), value);
69    return;
70  }
71
72  if (overlay_.SetValue(key, value))
73    ReportValueChanged(key);
74}
75
76void OverlayUserPrefStore::SetValueSilently(const std::string& key,
77                                            base::Value* value) {
78  if (!ShallBeStoredInOverlay(key)) {
79    underlay_->SetValueSilently(GetUnderlayKey(key), value);
80    return;
81  }
82
83  overlay_.SetValue(key, value);
84}
85
86void OverlayUserPrefStore::RemoveValue(const std::string& key) {
87  if (!ShallBeStoredInOverlay(key)) {
88    underlay_->RemoveValue(GetUnderlayKey(key));
89    return;
90  }
91
92  if (overlay_.RemoveValue(key))
93    ReportValueChanged(key);
94}
95
96bool OverlayUserPrefStore::ReadOnly() const {
97  return false;
98}
99
100PersistentPrefStore::PrefReadError OverlayUserPrefStore::GetReadError() const {
101  return PersistentPrefStore::PREF_READ_ERROR_NONE;
102}
103
104PersistentPrefStore::PrefReadError OverlayUserPrefStore::ReadPrefs() {
105  // We do not read intentionally.
106  OnInitializationCompleted(true);
107  return PersistentPrefStore::PREF_READ_ERROR_NONE;
108}
109
110void OverlayUserPrefStore::ReadPrefsAsync(
111    ReadErrorDelegate* error_delegate_raw) {
112  scoped_ptr<ReadErrorDelegate> error_delegate(error_delegate_raw);
113  // We do not read intentionally.
114  OnInitializationCompleted(true);
115}
116
117void OverlayUserPrefStore::CommitPendingWrite() {
118  underlay_->CommitPendingWrite();
119  // We do not write our content intentionally.
120}
121
122void OverlayUserPrefStore::ReportValueChanged(const std::string& key) {
123  FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
124}
125
126void OverlayUserPrefStore::OnPrefValueChanged(const std::string& key) {
127  if (!overlay_.GetValue(GetOverlayKey(key), NULL))
128    ReportValueChanged(GetOverlayKey(key));
129}
130
131void OverlayUserPrefStore::OnInitializationCompleted(bool succeeded) {
132  FOR_EACH_OBSERVER(PrefStore::Observer, observers_,
133                    OnInitializationCompleted(succeeded));
134}
135
136void OverlayUserPrefStore::RegisterOverlayPref(const std::string& key) {
137  RegisterOverlayPref(key, key);
138}
139
140void OverlayUserPrefStore::RegisterOverlayPref(
141    const std::string& overlay_key,
142    const std::string& underlay_key) {
143  DCHECK(!overlay_key.empty()) << "Overlay key is empty";
144  DCHECK(overlay_to_underlay_names_map_.find(overlay_key) ==
145         overlay_to_underlay_names_map_.end()) <<
146      "Overlay key already registered";
147  DCHECK(!underlay_key.empty()) << "Underlay key is empty";
148  DCHECK(underlay_to_overlay_names_map_.find(underlay_key) ==
149         underlay_to_overlay_names_map_.end()) <<
150      "Underlay key already registered";
151  overlay_to_underlay_names_map_[overlay_key] = underlay_key;
152  underlay_to_overlay_names_map_[underlay_key] = overlay_key;
153}
154
155OverlayUserPrefStore::~OverlayUserPrefStore() {
156  underlay_->RemoveObserver(this);
157}
158
159const std::string& OverlayUserPrefStore::GetOverlayKey(
160    const std::string& underlay_key) const {
161  NamesMap::const_iterator i =
162      underlay_to_overlay_names_map_.find(underlay_key);
163  return i != underlay_to_overlay_names_map_.end() ? i->second : underlay_key;
164}
165
166const std::string& OverlayUserPrefStore::GetUnderlayKey(
167    const std::string& overlay_key) const {
168  NamesMap::const_iterator i =
169      overlay_to_underlay_names_map_.find(overlay_key);
170  return i != overlay_to_underlay_names_map_.end() ? i->second : overlay_key;
171}
172
173bool OverlayUserPrefStore::ShallBeStoredInOverlay(
174    const std::string& key) const {
175  return overlay_to_underlay_names_map_.find(key) !=
176      overlay_to_underlay_names_map_.end();
177}
178