// 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 "chrome/browser/supervised_user/supervised_user_shared_settings_service.h"

#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/values.h"
#include "chrome/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "sync/api/sync_change.h"
#include "sync/api/sync_data.h"
#include "sync/api/sync_error.h"
#include "sync/api/sync_error_factory.h"
#include "sync/api/sync_merge_result.h"
#include "sync/protocol/sync.pb.h"

using base::DictionaryValue;
using base::Value;
using syncer::SUPERVISED_USER_SHARED_SETTINGS;
using syncer::ModelType;
using syncer::SyncChange;
using syncer::SyncChangeList;
using syncer::SyncChangeProcessor;
using syncer::SyncData;
using syncer::SyncDataList;
using syncer::SyncError;
using syncer::SyncErrorFactory;
using syncer::SyncMergeResult;

namespace {

const char kAcknowledged[] = "acknowledged";
const char kValue[] = "value";

DictionaryValue* FindOrCreateDictionary(DictionaryValue* parent,
                                        const std::string& key) {
  DictionaryValue* dict = NULL;
  if (!parent->GetDictionaryWithoutPathExpansion(key, &dict)) {
    dict = new DictionaryValue;
    parent->SetWithoutPathExpansion(key, dict);
  }
  return dict;
}

class ScopedSupervisedUserSharedSettingsUpdate {
 public:
  ScopedSupervisedUserSharedSettingsUpdate(PrefService* prefs,
                                           const std::string& su_id)
      : update_(prefs, prefs::kSupervisedUserSharedSettings), su_id_(su_id) {
    DCHECK(!su_id.empty());

    // A supervised user can only modify their own settings.
    std::string id = prefs->GetString(prefs::kSupervisedUserId);
    DCHECK(id.empty() || id == su_id);
  }

  DictionaryValue* Get() {
    return FindOrCreateDictionary(update_.Get(), su_id_);
  }

 private:
  DictionaryPrefUpdate update_;
  std::string su_id_;
};

SyncData CreateSyncDataForValue(
    const std::string& su_id,
    const std::string& key,
    const Value& dict_value) {
  const DictionaryValue* dict = NULL;
  if (!dict_value.GetAsDictionary(&dict))
    return SyncData();

  const Value* value = NULL;
  if (!dict->Get(kValue, &value))
    return SyncData();

  bool acknowledged = false;
  dict->GetBoolean(kAcknowledged, &acknowledged);

  return SupervisedUserSharedSettingsService::CreateSyncDataForSetting(
      su_id, key, *value, acknowledged);
}

}  // namespace


SupervisedUserSharedSettingsService::SupervisedUserSharedSettingsService(
    PrefService* prefs)
    : prefs_(prefs) {}

SupervisedUserSharedSettingsService::~SupervisedUserSharedSettingsService() {}

void SupervisedUserSharedSettingsService::SetValueInternal(
    const std::string& su_id,
    const std::string& key,
    const Value& value,
    bool acknowledged) {
  ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id);
  DictionaryValue* update_dict = update.Get();

  DictionaryValue* dict = NULL;
  bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict);
  if (!has_key) {
    dict = new DictionaryValue;
    update_dict->SetWithoutPathExpansion(key, dict);
  }
  dict->SetWithoutPathExpansion(kValue, value.DeepCopy());
  dict->SetBooleanWithoutPathExpansion(kAcknowledged, acknowledged);

  if (!sync_processor_)
    return;

  SyncData data = CreateSyncDataForSetting(su_id, key, value, acknowledged);
  SyncChange::SyncChangeType change_type =
      has_key ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD;
  SyncChangeList changes;
  changes.push_back(SyncChange(FROM_HERE, change_type, data));
  SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
  DCHECK(!error.IsSet()) << error.ToString();
}

const Value* SupervisedUserSharedSettingsService::GetValue(
    const std::string& su_id,
    const std::string& key) {
  const DictionaryValue* data =
      prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings);
  const DictionaryValue* dict = NULL;
  if (!data->GetDictionaryWithoutPathExpansion(su_id, &dict))
    return NULL;

  const DictionaryValue* settings = NULL;
  if (!dict->GetDictionaryWithoutPathExpansion(key, &settings))
    return NULL;

  const Value* value = NULL;
  if (!settings->GetWithoutPathExpansion(kValue, &value))
    return NULL;

  return value;
}

void SupervisedUserSharedSettingsService::SetValue(
    const std::string& su_id,
    const std::string& key,
    const Value& value) {
  SetValueInternal(su_id, key, value, true);
}

scoped_ptr<
    SupervisedUserSharedSettingsService::ChangeCallbackList::Subscription>
SupervisedUserSharedSettingsService::Subscribe(
    const SupervisedUserSharedSettingsService::ChangeCallback& cb) {
  return callbacks_.Add(cb);
}

// static
void SupervisedUserSharedSettingsService::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* registry) {
  registry->RegisterDictionaryPref(
      prefs::kSupervisedUserSharedSettings,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}

// static
SyncData SupervisedUserSharedSettingsService::CreateSyncDataForSetting(
    const std::string& su_id,
    const std::string& key,
    const Value& value,
    bool acknowledged) {
  std::string json_value;
  base::JSONWriter::Write(&value, &json_value);
  ::sync_pb::EntitySpecifics specifics;
  specifics.mutable_managed_user_shared_setting()->set_mu_id(su_id);
  specifics.mutable_managed_user_shared_setting()->set_key(key);
  specifics.mutable_managed_user_shared_setting()->set_value(json_value);
  specifics.mutable_managed_user_shared_setting()->set_acknowledged(
      acknowledged);
  std::string title = su_id + ":" + key;
  return SyncData::CreateLocalData(title, title, specifics);
}

void SupervisedUserSharedSettingsService::Shutdown() {}

syncer::SyncMergeResult
SupervisedUserSharedSettingsService::MergeDataAndStartSyncing(
    syncer::ModelType type,
    const syncer::SyncDataList& initial_sync_data,
    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
    scoped_ptr<syncer::SyncErrorFactory> error_handler) {
  DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
  sync_processor_ = sync_processor.Pass();
  error_handler_ = error_handler.Pass();

  // We keep a map from MU ID to the set of keys that we have seen in the
  // initial sync data.
  std::map<std::string, std::set<std::string> > seen_keys;

  // Iterate over all initial sync data, and update it locally. This means that
  // the value from the server always wins over a local value.
  for (SyncDataList::const_iterator it = initial_sync_data.begin();
       it != initial_sync_data.end();
       ++it) {
    DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, it->GetDataType());
    const ::sync_pb::ManagedUserSharedSettingSpecifics&
        supervised_user_shared_setting =
            it->GetSpecifics().managed_user_shared_setting();
    scoped_ptr<Value> value(
        base::JSONReader::Read(supervised_user_shared_setting.value()));
    const std::string& su_id = supervised_user_shared_setting.mu_id();
    ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id);
    const std::string& key = supervised_user_shared_setting.key();
    DictionaryValue* dict = FindOrCreateDictionary(update.Get(), key);
    dict->SetWithoutPathExpansion(kValue, value.release());

    // Every setting we get from the server should have the acknowledged flag
    // set.
    DCHECK(supervised_user_shared_setting.acknowledged());
    dict->SetBooleanWithoutPathExpansion(
        kAcknowledged, supervised_user_shared_setting.acknowledged());
    callbacks_.Notify(su_id, key);

    seen_keys[su_id].insert(key);
  }

  // Iterate over all settings that we have locally, which includes settings
  // that were just synced down. We filter those out using |seen_keys|.
  SyncChangeList change_list;
  const DictionaryValue* all_settings =
      prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings);
  for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd();
       it.Advance()) {
    const DictionaryValue* dict = NULL;
    bool success = it.value().GetAsDictionary(&dict);
    DCHECK(success);

    const std::set<std::string>& seen = seen_keys[it.key()];
    for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) {
      // We only need to upload settings that we haven't seen in the initial
      // sync data (which means they were added locally).
      if (seen.count(jt.key()) > 0)
        continue;

      SyncData data = CreateSyncDataForValue(it.key(), jt.key(), jt.value());
      DCHECK(data.IsValid());
      change_list.push_back(
          SyncChange(FROM_HERE, SyncChange::ACTION_ADD, data));
    }
  }

  SyncMergeResult result(SUPERVISED_USER_SHARED_SETTINGS);
  // Process all the accumulated changes.
  if (change_list.size() > 0) {
    result.set_error(
        sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
  }

  // TODO(bauerb): Statistics?
  return result;
}

void SupervisedUserSharedSettingsService::StopSyncing(syncer::ModelType type) {
  DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
  sync_processor_.reset();
  error_handler_.reset();
}

syncer::SyncDataList SupervisedUserSharedSettingsService::GetAllSyncData(
    syncer::ModelType type) const {
  DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type);
  SyncDataList data;
  const DictionaryValue* all_settings =
      prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings);
  for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd();
       it.Advance()) {
    const DictionaryValue* dict = NULL;
    bool success = it.value().GetAsDictionary(&dict);
    DCHECK(success);
    for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) {
      data.push_back(CreateSyncDataForValue(it.key(), jt.key(), jt.value()));
    }
  }
  return data;
}

syncer::SyncError SupervisedUserSharedSettingsService::ProcessSyncChanges(
    const tracked_objects::Location& from_here,
    const syncer::SyncChangeList& change_list) {
  for (SyncChangeList::const_iterator it = change_list.begin();
       it != change_list.end();
       ++it) {
    SyncData data = it->sync_data();
    DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, data.GetDataType());
    const ::sync_pb::ManagedUserSharedSettingSpecifics&
        supervised_user_shared_setting =
            data.GetSpecifics().managed_user_shared_setting();
    const std::string& key = supervised_user_shared_setting.key();
    const std::string& su_id = supervised_user_shared_setting.mu_id();
    ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id);
    DictionaryValue* update_dict = update.Get();
    DictionaryValue* dict = NULL;
    bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict);
    switch (it->change_type()) {
      case SyncChange::ACTION_ADD:
      case SyncChange::ACTION_UPDATE: {
        // Every setting we get from the server should have the acknowledged
        // flag set.
        DCHECK(supervised_user_shared_setting.acknowledged());

        if (has_key) {
          // If the supervised user already exists, it should be an update
          // action.
          DCHECK_EQ(SyncChange::ACTION_UPDATE, it->change_type());
        } else {
          // Otherwise, it should be an add action.
          DCHECK_EQ(SyncChange::ACTION_ADD, it->change_type());
          dict = new DictionaryValue;
          update_dict->SetWithoutPathExpansion(key, dict);
        }
        scoped_ptr<Value> value(
            base::JSONReader::Read(supervised_user_shared_setting.value()));
        dict->SetWithoutPathExpansion(kValue, value.release());
        dict->SetBooleanWithoutPathExpansion(
            kAcknowledged, supervised_user_shared_setting.acknowledged());
        break;
      }
      case SyncChange::ACTION_DELETE: {
        if (has_key)
          update_dict->RemoveWithoutPathExpansion(key, NULL);
        else
          NOTREACHED() << "Trying to delete nonexistent key " << key;
        break;
      }
      case SyncChange::ACTION_INVALID: {
        NOTREACHED();
        break;
      }
    }
    callbacks_.Notify(su_id, key);
  }

  SyncError error;
  return error;
}
