// Copyright (c) 2012 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 "components/sync_preferences/pref_model_associator.h"

#include <algorithm>
#include <iterator>
#include <memory>
#include <utility>

#include "base/auto_reset.h"
#include "base/feature_list.h"
#include "base/json/json_reader.h"
#include "base/json/json_string_value_serializer.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/prefs/persistent_pref_store.h"
#include "components/prefs/pref_service.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/model/sync_change_processor.h"
#include "components/sync/model/sync_error_factory.h"
#include "components/sync/protocol/preference_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
#include "components/sync_preferences/pref_model_associator_client.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "components/sync_preferences/synced_pref_observer.h"

using syncer::PREFERENCES;
using syncer::PRIORITY_PREFERENCES;

namespace sync_preferences {

namespace {

// Enables deleting a pref from Sync if the the user clears it on a client. If
// this feature is disabled, clearing a pref will cause setting it to the
// default value instead of deleting it from sync.
// TODO(crbug.com/943579): This has been introduced in M75 as a safety
// mechanism, should be removed in M78 if no issues are observed.
const base::Feature kSyncDeleteClearedPref{"SyncDeleteClearedPrefs",
                                           base::FEATURE_ENABLED_BY_DEFAULT};

const sync_pb::PreferenceSpecifics& GetSpecifics(const syncer::SyncData& pref) {
  DCHECK(pref.GetDataType() == syncer::PREFERENCES ||
         pref.GetDataType() == syncer::PRIORITY_PREFERENCES);
  if (pref.GetDataType() == syncer::PRIORITY_PREFERENCES) {
    return pref.GetSpecifics().priority_preference().preference();
  } else {
    return pref.GetSpecifics().preference();
  }
}

sync_pb::PreferenceSpecifics* GetMutableSpecifics(
    const syncer::ModelType type,
    sync_pb::EntitySpecifics* specifics) {
  if (type == syncer::PRIORITY_PREFERENCES) {
    DCHECK(!specifics->has_preference());
    return specifics->mutable_priority_preference()->mutable_preference();
  } else {
    DCHECK(!specifics->has_priority_preference());
    return specifics->mutable_preference();
  }
}

}  // namespace

PrefModelAssociator::PrefModelAssociator(
    const PrefModelAssociatorClient* client,
    syncer::ModelType type,
    UnknownUserPrefAccessor* accessor)
    : pref_accessor_(accessor), type_(type), client_(client) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(type_ == PREFERENCES || type_ == PRIORITY_PREFERENCES);
}

PrefModelAssociator::~PrefModelAssociator() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  pref_service_ = nullptr;

  synced_pref_observers_.clear();
}

void PrefModelAssociator::InitPrefAndAssociate(
    const syncer::SyncData& sync_pref,
    const std::string& pref_name,
    syncer::SyncChangeList* sync_changes) {
  UnknownUserPrefAccessor::PreferenceState local_pref_state =
      pref_accessor_->GetPreferenceState(type_, pref_name);
  if (local_pref_state.registration_state ==
          UnknownUserPrefAccessor::RegistrationState::kUnknown ||
      local_pref_state.registration_state ==
          UnknownUserPrefAccessor::RegistrationState::kNotSyncable) {
    // Only process syncable prefs and unknown prefs if whitelisted.
    return;
  }
  VLOG(1) << "Associating preference " << pref_name;

  if (sync_pref.IsValid()) {
    const sync_pb::PreferenceSpecifics& preference = GetSpecifics(sync_pref);
    DCHECK(pref_name == preference.name());
    base::JSONReader reader;
    std::unique_ptr<base::Value> sync_value(
        reader.ReadToValueDeprecated(preference.value()));
    if (!sync_value.get()) {
      LOG(ERROR) << "Failed to deserialize value of preference '" << pref_name
                 << "': " << reader.GetErrorMessage();
      return;
    }

    if (local_pref_state.persisted_value) {
      DVLOG(1) << "Found user pref value for " << pref_name;
      // We have both server and local values. Merge them.
      std::unique_ptr<base::Value> new_value(MergePreference(
          pref_name, *local_pref_state.persisted_value, *sync_value));

      // Update the local preference based on what we got from the
      // sync server. Note: this only updates the user value store, which is
      // ignored if the preference is policy controlled.
      if (new_value->is_none()) {
        LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
        pref_accessor_->ClearPref(pref_name, local_pref_state);
      } else if (!local_pref_state.persisted_value->Equals(new_value.get())) {
        pref_accessor_->SetPref(pref_name, local_pref_state, *new_value);
      }

      // If the merge resulted in an updated value, inform the syncer.
      if (!sync_value->Equals(new_value.get())) {
        syncer::SyncData sync_data;
        if (!CreatePrefSyncData(pref_name, *new_value, &sync_data)) {
          LOG(ERROR) << "Failed to update preference.";
          return;
        }

        sync_changes->push_back(syncer::SyncChange(
            FROM_HERE, syncer::SyncChange::ACTION_UPDATE, sync_data));
      }
    } else if (!sync_value->is_none()) {
      // Only a server value exists. Just set the local user value.
      pref_accessor_->SetPref(pref_name, local_pref_state, *sync_value);
    } else {
      LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
    }
    synced_preferences_.insert(preference.name());
  } else if (local_pref_state.persisted_value) {
    DCHECK_EQ(local_pref_state.registration_state,
              UnknownUserPrefAccessor::RegistrationState::kSyncable);
    // The server does not know about this preference and should be added
    // to the syncer's database.
    syncer::SyncData sync_data;
    if (!CreatePrefSyncData(pref_name, *local_pref_state.persisted_value,
                            &sync_data)) {
      LOG(ERROR) << "Failed to update preference.";
      return;
    }
    sync_changes->push_back(syncer::SyncChange(
        FROM_HERE, syncer::SyncChange::ACTION_ADD, sync_data));
    synced_preferences_.insert(pref_name);
  }

  // Else this pref does not have a sync value but also does not have a user
  // controlled value (either it's a default value or it's policy controlled,
  // either way it's not interesting). We can ignore it. Once it gets changed,
  // we'll send the new user controlled value to the syncer.
}

void PrefModelAssociator::RegisterMergeDataFinishedCallback(
    const base::Closure& callback) {
  if (!models_associated_)
    callback_list_.push_back(callback);
  else
    callback.Run();
}

syncer::SyncMergeResult PrefModelAssociator::MergeDataAndStartSyncing(
    syncer::ModelType type,
    const syncer::SyncDataList& initial_sync_data,
    std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
    std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) {
  DCHECK_EQ(type_, type);
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(pref_service_);
  DCHECK(!sync_processor_.get());
  DCHECK(sync_processor.get());
  DCHECK(sync_error_factory.get());
  syncer::SyncMergeResult merge_result(type);
  sync_processor_ = std::move(sync_processor);
  sync_error_factory_ = std::move(sync_error_factory);

  syncer::SyncChangeList new_changes;
  std::set<std::string> remaining_preferences = registered_preferences_;

  // Go through and check for all preferences we care about that sync already
  // knows about.
  for (auto sync_iter = initial_sync_data.begin();
       sync_iter != initial_sync_data.end(); ++sync_iter) {
    DCHECK_EQ(type_, sync_iter->GetDataType());

    const sync_pb::PreferenceSpecifics& preference = GetSpecifics(*sync_iter);
    std::string sync_pref_name = preference.name();
    remaining_preferences.erase(sync_pref_name);
    InitPrefAndAssociate(*sync_iter, sync_pref_name, &new_changes);
  }

  // Go through and build sync data for any remaining preferences.
  for (auto pref_name_iter = remaining_preferences.begin();
       pref_name_iter != remaining_preferences.end(); ++pref_name_iter) {
    InitPrefAndAssociate(syncer::SyncData(), *pref_name_iter, &new_changes);
  }

  UMA_HISTOGRAM_COUNTS_1000("Sync.Preferences.SyncingUnknownPrefs",
                            pref_accessor_->GetNumberOfSyncingUnknownPrefs());

  // Push updates to sync.
  merge_result.set_error(
      sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
  if (merge_result.error().IsSet())
    return merge_result;

  for (const auto& callback : callback_list_)
    callback.Run();
  callback_list_.clear();

  models_associated_ = true;
  pref_service_->OnIsSyncingChanged();
  return merge_result;
}

void PrefModelAssociator::StopSyncing(syncer::ModelType type) {
  DCHECK_EQ(type_, type);
  models_associated_ = false;
  sync_processor_.reset();
  sync_error_factory_.reset();
  pref_service_->OnIsSyncingChanged();
}

std::unique_ptr<base::Value> PrefModelAssociator::MergePreference(
    const std::string& name,
    const base::Value& local_value,
    const base::Value& server_value) {
  // This function special cases preferences individually, so don't attempt
  // to merge for all migrated values.
  if (client_) {
    std::string new_pref_name;
    if (client_->IsMergeableListPreference(name))
      return MergeListValues(local_value, server_value);
    if (client_->IsMergeableDictionaryPreference(name)) {
      return std::make_unique<base::Value>(
          MergeDictionaryValues(local_value, server_value));
    }
    std::unique_ptr<base::Value> merged_value =
        client_->MaybeMergePreferenceValues(name, local_value, server_value);
    if (merged_value)
      return merged_value;
  }

  // If this is not a specially handled preference, server wins.
  return base::WrapUnique(server_value.DeepCopy());
}

bool PrefModelAssociator::CreatePrefSyncData(
    const std::string& name,
    const base::Value& value,
    syncer::SyncData* sync_data) const {
  if (value.is_none()) {
    LOG(ERROR) << "Attempting to sync a null pref value for " << name;
    return false;
  }

  std::string serialized;
  // TODO(zea): consider JSONWriter::Write since you don't have to check
  // failures to deserialize.
  JSONStringValueSerializer json(&serialized);
  if (!json.Serialize(value)) {
    LOG(ERROR) << "Failed to serialize preference value.";
    return false;
  }

  sync_pb::EntitySpecifics specifics;
  sync_pb::PreferenceSpecifics* pref_specifics =
      GetMutableSpecifics(type_, &specifics);

  pref_specifics->set_name(name);
  pref_specifics->set_value(serialized);
  *sync_data = syncer::SyncData::CreateLocalData(name, name, specifics);
  return true;
}

std::unique_ptr<base::Value> PrefModelAssociator::MergeListValues(
    const base::Value& from_value,
    const base::Value& to_value) {
  if (from_value.is_none())
    return base::Value::ToUniquePtrValue(to_value.Clone());
  if (to_value.is_none())
    return base::Value::ToUniquePtrValue(from_value.Clone());

  DCHECK(from_value.type() == base::Value::Type::LIST);
  DCHECK(to_value.type() == base::Value::Type::LIST);

  base::Value result = to_value.Clone();
  base::Value::ListStorage& list = result.GetList();
  for (const auto& value : from_value.GetList()) {
    if (!base::ContainsValue(list, value))
      list.emplace_back(value.Clone());
  }

  return base::Value::ToUniquePtrValue(std::move(result));
}

base::Value PrefModelAssociator::MergeDictionaryValues(
    const base::Value& from_value,
    const base::Value& to_value) {
  if (from_value.is_none())
    return to_value.Clone();
  if (to_value.is_none())
    return from_value.Clone();

  DCHECK(from_value.is_dict());
  DCHECK(to_value.is_dict());
  base::Value result = to_value.Clone();

  for (const auto& it : from_value.DictItems()) {
    const base::Value* from_key_value = &it.second;
    base::Value* to_key_value = result.FindKey(it.first);
    if (to_key_value) {
      if (from_key_value->is_dict() && to_key_value->is_dict()) {
        *to_key_value = MergeDictionaryValues(*from_key_value, *to_key_value);
      }
      // Note that for all other types we want to preserve the "to"
      // values so we do nothing here.
    } else {
      result.SetKey(it.first, from_key_value->Clone());
    }
  }
  return result;
}

syncer::SyncDataList PrefModelAssociator::GetAllSyncData(
    syncer::ModelType type) const {
  DCHECK_EQ(type_, type);
  syncer::SyncDataList current_data;
  for (auto iter = synced_preferences_.begin();
       iter != synced_preferences_.end(); ++iter) {
    std::string name = *iter;
    if (pref_accessor_->GetPreferenceState(type_, name).registration_state !=
        UnknownUserPrefAccessor::RegistrationState::kSyncable) {
      continue;
    }
    const PrefService::Preference* pref = pref_service_->FindPreference(name);
    DCHECK(pref);
    if (!pref->IsUserControlled() || pref->IsDefaultValue())
      continue;  // This is not data we care about.
    // TODO(zea): plumb a way to read the user controlled value.
    syncer::SyncData sync_data;
    if (!CreatePrefSyncData(name, *pref->GetValue(), &sync_data))
      continue;
    current_data.push_back(sync_data);
  }
  return current_data;
}

syncer::SyncError PrefModelAssociator::ProcessSyncChanges(
    const base::Location& from_here,
    const syncer::SyncChangeList& change_list) {
  if (!models_associated_) {
    syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR,
                            "Models not yet associated.", PREFERENCES);
    return error;
  }
  base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
  syncer::SyncChangeList::const_iterator iter;
  for (iter = change_list.begin(); iter != change_list.end(); ++iter) {
    DCHECK_EQ(type_, iter->sync_data().GetDataType());

    const sync_pb::PreferenceSpecifics& pref_specifics =
        GetSpecifics(iter->sync_data());

    UnknownUserPrefAccessor::PreferenceState local_pref_state =
        pref_accessor_->GetPreferenceState(type_, pref_specifics.name());
    if (local_pref_state.registration_state ==
        UnknownUserPrefAccessor::RegistrationState::kUnknown) {
      // It is possible that we may receive a change to a preference we do not
      // want to sync. For example if the user is syncing a Mac client and a
      // Windows client, the Windows client does not support
      // kConfirmToQuitEnabled. Ignore updates from these preferences.
      // We only sync such prefs if they are whitelisted.
      continue;
    }
    if (local_pref_state.registration_state ==
        UnknownUserPrefAccessor::RegistrationState::kNotSyncable) {
      // Don't process remote changes for prefs this client doesn't want synced.
      continue;
    }
    if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) {
      pref_accessor_->ClearPref(pref_specifics.name(), local_pref_state);
      continue;
    }

    std::unique_ptr<base::Value> new_value(
        ReadPreferenceSpecifics(pref_specifics));
    if (!new_value.get()) {
      // Skip values we can't deserialize.
      // TODO(zea): consider taking some further action such as erasing the
      // bad data.
      continue;
    }

    // This will only modify the user controlled value store, which takes
    // priority over the default value but is ignored if the preference is
    // policy controlled.
    pref_accessor_->SetPref(pref_specifics.name(), local_pref_state,
                            *new_value);

    NotifySyncedPrefObservers(pref_specifics.name(), true /*from_sync*/);

    // Keep track of any newly synced preferences. This can happen if a
    // preference was late registered or remotely added (ACTION_ADD).
    synced_preferences_.insert(pref_specifics.name());
  }
  return syncer::SyncError();
}

// static
base::Value* PrefModelAssociator::ReadPreferenceSpecifics(
    const sync_pb::PreferenceSpecifics& preference) {
  base::JSONReader reader;
  std::unique_ptr<base::Value> value(
      reader.ReadToValueDeprecated(preference.value()));
  if (!value.get()) {
    std::string err =
        "Failed to deserialize preference value: " + reader.GetErrorMessage();
    LOG(ERROR) << err;
    return nullptr;
  }
  return value.release();
}

bool PrefModelAssociator::IsPrefSynced(const std::string& name) const {
  return synced_preferences_.find(name) != synced_preferences_.end();
}

void PrefModelAssociator::AddSyncedPrefObserver(const std::string& name,
                                                SyncedPrefObserver* observer) {
  auto& observers = synced_pref_observers_[name];
  if (!observers)
    observers = std::make_unique<SyncedPrefObserverList>();

  observers->AddObserver(observer);
}

void PrefModelAssociator::RemoveSyncedPrefObserver(
    const std::string& name,
    SyncedPrefObserver* observer) {
  auto observer_iter = synced_pref_observers_.find(name);
  if (observer_iter == synced_pref_observers_.end())
    return;
  observer_iter->second->RemoveObserver(observer);
}

void PrefModelAssociator::RegisterPref(const std::string& name) {
  DCHECK(!registered_preferences_.count(name));
  registered_preferences_.insert(name);

  // This pref might be registered after sync started. Make sure data in the
  // local store matches the registered type.
  // If this results in a modification of the local pref store, we don't want
  // to tell ChromeSync about these -- it's a local anomaly,
  base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
  pref_accessor_->EnforceRegisteredTypeInStore(name);
}

bool PrefModelAssociator::IsPrefRegistered(const std::string& name) const {
  return registered_preferences_.count(name) > 0;
}

void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
  if (processing_syncer_changes_)
    return;  // These are changes originating from us, ignore.

  // We only process changes if we've already associated models.
  // This also filters out local changes during the initial merge.
  if (!models_associated_)
    return;

  // From now on, this method does not have to deal with lazily registered
  // prefs, as local changes can only happen after they were registered.

  const PrefService::Preference* preference =
      pref_service_->FindPreference(name);
  // TODO(tschumann): When can this ever happen? Should this be a DCHECK?
  if (!preference)
    return;

  if (!IsPrefRegistered(name)) {
    // We are not syncing this preference -- this also filters out synced
    // preferences of the wrong type (priority preference are handled by a
    // separate associator).
    return;
  }

  syncer::SyncChangeList changes;

  if (!preference->IsUserModifiable()) {
    // If the preference is no longer user modifiable, it must now be
    // controlled by policy, whose values we do not sync. Just return. If the
    // preference stops being controlled by policy, it will revert back to the
    // user value (which we continue to update with sync changes).
    return;
  }

  base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);

  NotifySyncedPrefObservers(name, false /*from_sync*/);

  if (synced_preferences_.count(name) == 0) {
    // Not in synced_preferences_ means no synced data.
    // InitPrefAndAssociate(..) will determine if we care about its data (e.g.
    // if it has a default value and hasn't been changed yet we don't) and
    // take care syncing any new data.
    InitPrefAndAssociate(syncer::SyncData(), name, &changes);
  } else {
    // We are already syncing this preference, just update or delete its sync
    // node.
    syncer::SyncData sync_data;
    if (!CreatePrefSyncData(name, *preference->GetValue(), &sync_data)) {
      LOG(ERROR) << "Failed to update preference.";
      return;
    }
    if (!base::FeatureList::IsEnabled(kSyncDeleteClearedPref) ||
        pref_accessor_->GetPreferenceState(type_, name).persisted_value) {
      // If the pref was updated, update it.
      changes.push_back(syncer::SyncChange(
          FROM_HERE, syncer::SyncChange::ACTION_UPDATE, sync_data));
    } else {
      // Otherwise, the pref must have been cleared and hence delete it.
      changes.push_back(syncer::SyncChange(
          FROM_HERE, syncer::SyncChange::ACTION_DELETE, sync_data));
    }
  }

  syncer::SyncError error =
      sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
}

void PrefModelAssociator::SetPrefService(PrefServiceSyncable* pref_service) {
  DCHECK(pref_service_ == nullptr);
  pref_service_ = pref_service;
}

void PrefModelAssociator::NotifySyncedPrefObservers(const std::string& path,
                                                    bool from_sync) const {
  auto observer_iter = synced_pref_observers_.find(path);
  if (observer_iter == synced_pref_observers_.end())
    return;
  for (auto& observer : *observer_iter->second)
    observer.OnSyncedPrefChanged(path, from_sync);
}

}  // namespace sync_preferences
