// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/browser/extension_pref_value_map.h"

#include "base/prefs/pref_value_map.h"
#include "base/stl_util.h"
#include "base/values.h"

using extensions::ExtensionPrefsScope;

struct ExtensionPrefValueMap::ExtensionEntry {
  // Installation time of the extension.
  base::Time install_time;
  // Whether extension is enabled in the profile.
  bool enabled;
  // Whether the extension has access to the incognito profile.
  bool incognito_enabled;
  // Extension controlled preferences for the regular profile.
  PrefValueMap regular_profile_preferences;
  // Extension controlled preferences that should *only* apply to the regular
  // profile.
  PrefValueMap regular_only_profile_preferences;
  // Persistent extension controlled preferences for the incognito profile,
  // empty for regular profile ExtensionPrefStore.
  PrefValueMap incognito_profile_preferences_persistent;
  // Session only extension controlled preferences for the incognito profile.
  // These preferences are deleted when the incognito profile is destroyed.
  PrefValueMap incognito_profile_preferences_session_only;
};

ExtensionPrefValueMap::ExtensionPrefValueMap() : destroyed_(false) {
}

ExtensionPrefValueMap::~ExtensionPrefValueMap() {
  if (!destroyed_) {
    NotifyOfDestruction();
    destroyed_ = true;
  }
  STLDeleteValues(&entries_);
  entries_.clear();
}

void ExtensionPrefValueMap::Shutdown() {
  NotifyOfDestruction();
  destroyed_ = true;
}

void ExtensionPrefValueMap::SetExtensionPref(const std::string& ext_id,
                                             const std::string& key,
                                             ExtensionPrefsScope scope,
                                             base::Value* value) {
  PrefValueMap* prefs = GetExtensionPrefValueMap(ext_id, scope);

  if (prefs->SetValue(key, value))
    NotifyPrefValueChanged(key);
}

void ExtensionPrefValueMap::RemoveExtensionPref(
    const std::string& ext_id,
    const std::string& key,
    ExtensionPrefsScope scope) {
  PrefValueMap* prefs = GetExtensionPrefValueMap(ext_id, scope);
  if (prefs->RemoveValue(key))
    NotifyPrefValueChanged(key);
}

bool ExtensionPrefValueMap::CanExtensionControlPref(
    const std::string& extension_id,
    const std::string& pref_key,
    bool incognito) const {
  ExtensionEntryMap::const_iterator ext = entries_.find(extension_id);
  if (ext == entries_.end()) {
    NOTREACHED();
    return false;
  }

  if (incognito && !ext->second->incognito_enabled)
    return false;

  ExtensionEntryMap::const_iterator winner =
      GetEffectivePrefValueController(pref_key, incognito, NULL);
  if (winner == entries_.end())
    return true;

  return winner->second->install_time <= ext->second->install_time;
}

void ExtensionPrefValueMap::ClearAllIncognitoSessionOnlyPreferences() {
  typedef std::set<std::string> KeySet;
  KeySet deleted_keys;

  ExtensionEntryMap::iterator i;
  for (i = entries_.begin(); i != entries_.end(); ++i) {
    PrefValueMap& inc_prefs =
        i->second->incognito_profile_preferences_session_only;
    PrefValueMap::iterator j;
    for (j = inc_prefs.begin(); j != inc_prefs.end(); ++j)
      deleted_keys.insert(j->first);
    inc_prefs.Clear();
  }

  KeySet::iterator k;
  for (k = deleted_keys.begin(); k != deleted_keys.end(); ++k)
    NotifyPrefValueChanged(*k);
}

bool ExtensionPrefValueMap::DoesExtensionControlPref(
    const std::string& extension_id,
    const std::string& pref_key,
    bool* from_incognito) const {
  bool incognito = (from_incognito != NULL);
  ExtensionEntryMap::const_iterator winner =
      GetEffectivePrefValueController(pref_key, incognito, from_incognito);
  if (winner == entries_.end())
    return false;
  return winner->first == extension_id;
}

void ExtensionPrefValueMap::RegisterExtension(const std::string& ext_id,
                                              const base::Time& install_time,
                                              bool is_enabled,
                                              bool is_incognito_enabled) {
  if (entries_.find(ext_id) == entries_.end()) {
    entries_[ext_id] = new ExtensionEntry;

    // Only update the install time if the extension is newly installed.
    entries_[ext_id]->install_time = install_time;
  }

  entries_[ext_id]->enabled = is_enabled;
  entries_[ext_id]->incognito_enabled = is_incognito_enabled;
}

void ExtensionPrefValueMap::UnregisterExtension(const std::string& ext_id) {
  ExtensionEntryMap::iterator i = entries_.find(ext_id);
  if (i == entries_.end())
    return;
  std::set<std::string> keys;  // keys set by this extension
  GetExtensionControlledKeys(*(i->second), &keys);

  delete i->second;
  entries_.erase(i);

  NotifyPrefValueChanged(keys);
}

void ExtensionPrefValueMap::SetExtensionState(const std::string& ext_id,
                                              bool is_enabled) {
  ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
  // This may happen when sync sets the extension state for an
  // extension that is not installed.
  if (i == entries_.end())
    return;
  if (i->second->enabled == is_enabled)
    return;
  std::set<std::string> keys;  // keys set by this extension
  GetExtensionControlledKeys(*(i->second), &keys);
  i->second->enabled = is_enabled;
  NotifyPrefValueChanged(keys);
}

void ExtensionPrefValueMap::SetExtensionIncognitoState(
    const std::string& ext_id,
    bool is_incognito_enabled) {
  ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
  // This may happen when sync sets the extension state for an
  // extension that is not installed.
  if (i == entries_.end())
    return;
  if (i->second->incognito_enabled == is_incognito_enabled)
    return;
  std::set<std::string> keys;  // keys set by this extension
  GetExtensionControlledKeys(*(i->second), &keys);
  i->second->incognito_enabled = is_incognito_enabled;
  NotifyPrefValueChanged(keys);
}

PrefValueMap* ExtensionPrefValueMap::GetExtensionPrefValueMap(
    const std::string& ext_id,
    ExtensionPrefsScope scope) {
  ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
  CHECK(i != entries_.end());
  switch (scope) {
    case extensions::kExtensionPrefsScopeRegular:
      return &(i->second->regular_profile_preferences);
    case extensions::kExtensionPrefsScopeRegularOnly:
      return &(i->second->regular_only_profile_preferences);
    case extensions::kExtensionPrefsScopeIncognitoPersistent:
      return &(i->second->incognito_profile_preferences_persistent);
    case extensions::kExtensionPrefsScopeIncognitoSessionOnly:
      return &(i->second->incognito_profile_preferences_session_only);
  }
  NOTREACHED();
  return NULL;
}

const PrefValueMap* ExtensionPrefValueMap::GetExtensionPrefValueMap(
    const std::string& ext_id,
    ExtensionPrefsScope scope) const {
  ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
  CHECK(i != entries_.end());
  switch (scope) {
    case extensions::kExtensionPrefsScopeRegular:
      return &(i->second->regular_profile_preferences);
    case extensions::kExtensionPrefsScopeRegularOnly:
      return &(i->second->regular_only_profile_preferences);
    case extensions::kExtensionPrefsScopeIncognitoPersistent:
      return &(i->second->incognito_profile_preferences_persistent);
    case extensions::kExtensionPrefsScopeIncognitoSessionOnly:
      return &(i->second->incognito_profile_preferences_session_only);
  }
  NOTREACHED();
  return NULL;
}

void ExtensionPrefValueMap::GetExtensionControlledKeys(
    const ExtensionEntry& entry,
    std::set<std::string>* out) const {
  PrefValueMap::const_iterator i;

  const PrefValueMap& regular_prefs = entry.regular_profile_preferences;
  for (i = regular_prefs.begin(); i != regular_prefs.end(); ++i)
    out->insert(i->first);

  const PrefValueMap& regular_only_prefs =
      entry.regular_only_profile_preferences;
  for (i = regular_only_prefs.begin(); i != regular_only_prefs.end(); ++i)
    out->insert(i->first);

  const PrefValueMap& inc_prefs_pers =
      entry.incognito_profile_preferences_persistent;
  for (i = inc_prefs_pers.begin(); i != inc_prefs_pers.end(); ++i)
    out->insert(i->first);

  const PrefValueMap& inc_prefs_session =
      entry.incognito_profile_preferences_session_only;
  for (i = inc_prefs_session.begin(); i != inc_prefs_session.end(); ++i)
    out->insert(i->first);
}

const base::Value* ExtensionPrefValueMap::GetEffectivePrefValue(
    const std::string& key,
    bool incognito,
    bool* from_incognito) const {
  ExtensionEntryMap::const_iterator winner =
      GetEffectivePrefValueController(key, incognito, from_incognito);
  if (winner == entries_.end())
    return NULL;

  const base::Value* value = NULL;
  const std::string& ext_id = winner->first;

  // First search for incognito session only preferences.
  if (incognito) {
    DCHECK(winner->second->incognito_enabled);
    const PrefValueMap* prefs = GetExtensionPrefValueMap(
        ext_id, extensions::kExtensionPrefsScopeIncognitoSessionOnly);
    prefs->GetValue(key, &value);
    if (value)
      return value;

    // If no incognito session only preference exists, fall back to persistent
    // incognito preference.
    prefs = GetExtensionPrefValueMap(
        ext_id,
        extensions::kExtensionPrefsScopeIncognitoPersistent);
    prefs->GetValue(key, &value);
    if (value)
      return value;
  } else {
    // Regular-only preference.
    const PrefValueMap* prefs = GetExtensionPrefValueMap(
        ext_id, extensions::kExtensionPrefsScopeRegularOnly);
    prefs->GetValue(key, &value);
    if (value)
      return value;
  }

  // Regular preference.
  const PrefValueMap* prefs = GetExtensionPrefValueMap(
      ext_id, extensions::kExtensionPrefsScopeRegular);
  prefs->GetValue(key, &value);
  return value;
}

ExtensionPrefValueMap::ExtensionEntryMap::const_iterator
ExtensionPrefValueMap::GetEffectivePrefValueController(
    const std::string& key,
    bool incognito,
    bool* from_incognito) const {
  ExtensionEntryMap::const_iterator winner = entries_.end();
  base::Time winners_install_time;

  ExtensionEntryMap::const_iterator i;
  for (i = entries_.begin(); i != entries_.end(); ++i) {
    const std::string& ext_id = i->first;
    const base::Time& install_time = i->second->install_time;
    const bool enabled = i->second->enabled;
    const bool incognito_enabled = i->second->incognito_enabled;

    if (!enabled)
      continue;
    if (install_time < winners_install_time)
      continue;
    if (incognito && !incognito_enabled)
      continue;

    const base::Value* value = NULL;
    const PrefValueMap* prefs = GetExtensionPrefValueMap(
        ext_id, extensions::kExtensionPrefsScopeRegular);
    if (prefs->GetValue(key, &value)) {
      winner = i;
      winners_install_time = install_time;
      if (from_incognito)
        *from_incognito = false;
    }

    if (!incognito) {
      const PrefValueMap* prefs = GetExtensionPrefValueMap(
          ext_id, extensions::kExtensionPrefsScopeRegularOnly);
      if (prefs->GetValue(key, &value)) {
        winner = i;
        winners_install_time = install_time;
        if (from_incognito)
          *from_incognito = false;
      }
      // Ignore the following prefs, because they're incognito-only.
      continue;
    }

    prefs = GetExtensionPrefValueMap(
        ext_id, extensions::kExtensionPrefsScopeIncognitoPersistent);
    if (prefs->GetValue(key, &value)) {
      winner = i;
      winners_install_time = install_time;
      if (from_incognito)
        *from_incognito = true;
    }

    prefs = GetExtensionPrefValueMap(
        ext_id, extensions::kExtensionPrefsScopeIncognitoSessionOnly);
    if (prefs->GetValue(key, &value)) {
      winner = i;
      winners_install_time = install_time;
      if (from_incognito)
        *from_incognito = true;
    }
  }
  return winner;
}

void ExtensionPrefValueMap::AddObserver(
    ExtensionPrefValueMap::Observer* observer) {
  observers_.AddObserver(observer);

  // Collect all currently used keys and notify the new observer.
  std::set<std::string> keys;
  ExtensionEntryMap::const_iterator i;
  for (i = entries_.begin(); i != entries_.end(); ++i)
    GetExtensionControlledKeys(*(i->second), &keys);

  std::set<std::string>::const_iterator j;
  for (j = keys.begin(); j != keys.end(); ++j)
    observer->OnPrefValueChanged(*j);
}

void ExtensionPrefValueMap::RemoveObserver(
    ExtensionPrefValueMap::Observer* observer) {
  observers_.RemoveObserver(observer);
}

std::string ExtensionPrefValueMap::GetExtensionControllingPref(
    const std::string& pref_key) const {
  ExtensionEntryMap::const_iterator winner =
      GetEffectivePrefValueController(pref_key, false, NULL);
  if (winner == entries_.end())
    return std::string();
  return winner->first;
}

void ExtensionPrefValueMap::NotifyInitializationCompleted() {
  FOR_EACH_OBSERVER(ExtensionPrefValueMap::Observer, observers_,
                    OnInitializationCompleted());
}

void ExtensionPrefValueMap::NotifyPrefValueChanged(
    const std::set<std::string>& keys) {
  std::set<std::string>::const_iterator i;
  for (i = keys.begin(); i != keys.end(); ++i)
    NotifyPrefValueChanged(*i);
}

void ExtensionPrefValueMap::NotifyPrefValueChanged(const std::string& key) {
  FOR_EACH_OBSERVER(ExtensionPrefValueMap::Observer, observers_,
                    OnPrefValueChanged(key));
}

void ExtensionPrefValueMap::NotifyOfDestruction() {
  FOR_EACH_OBSERVER(ExtensionPrefValueMap::Observer, observers_,
                    OnExtensionPrefValueMapDestruction());
}
