// Copyright 2013 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 "sync/notifier/object_id_invalidation_map.h"

#include "base/json/json_string_value_serializer.h"

namespace syncer {

// static
ObjectIdInvalidationMap ObjectIdInvalidationMap::InvalidateAll(
    const ObjectIdSet& ids) {
  ObjectIdInvalidationMap invalidate_all;
  for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
    invalidate_all.Insert(Invalidation::InitUnknownVersion(*it));
  }
  return invalidate_all;
}

ObjectIdInvalidationMap::ObjectIdInvalidationMap() {}

ObjectIdInvalidationMap::~ObjectIdInvalidationMap() {}

ObjectIdSet ObjectIdInvalidationMap::GetObjectIds() const {
  ObjectIdSet ret;
  for (IdToListMap::const_iterator it = map_.begin(); it != map_.end(); ++it) {
    ret.insert(it->first);
  }
  return ret;
}

bool ObjectIdInvalidationMap::Empty() const {
  return map_.empty();
}

void ObjectIdInvalidationMap::Insert(const Invalidation& invalidation) {
  map_[invalidation.object_id()].Insert(invalidation);
}

ObjectIdInvalidationMap ObjectIdInvalidationMap::GetSubsetWithObjectIds(
    const ObjectIdSet& ids) const {
  IdToListMap new_map;
  for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
    IdToListMap::const_iterator lookup = map_.find(*it);
    if (lookup != map_.end()) {
      new_map[*it] = lookup->second;
    }
  }
  return ObjectIdInvalidationMap(new_map);
}

const SingleObjectInvalidationSet& ObjectIdInvalidationMap::ForObject(
    invalidation::ObjectId id) const {
  IdToListMap::const_iterator lookup = map_.find(id);
  DCHECK(lookup != map_.end());
  DCHECK(!lookup->second.IsEmpty());
  return lookup->second;
}

void ObjectIdInvalidationMap::GetAllInvalidations(
    std::vector<syncer::Invalidation>* out) const {
  for (IdToListMap::const_iterator it = map_.begin(); it != map_.end(); ++it) {
    out->insert(out->begin(), it->second.begin(), it->second.end());
  }
}
void ObjectIdInvalidationMap::AcknowledgeAll() const {
  for (IdToListMap::const_iterator it1 = map_.begin();
       it1 != map_.end(); ++it1) {
    for (SingleObjectInvalidationSet::const_iterator it2 = it1->second.begin();
         it2 != it1->second.end(); ++it2) {
      it2->Acknowledge();
    }
  }
}

bool ObjectIdInvalidationMap::operator==(
    const ObjectIdInvalidationMap& other) const {
  return map_ == other.map_;
}

scoped_ptr<base::ListValue> ObjectIdInvalidationMap::ToValue() const {
  scoped_ptr<base::ListValue> value(new base::ListValue());
  for (IdToListMap::const_iterator it1 = map_.begin();
       it1 != map_.end(); ++it1) {
    for (SingleObjectInvalidationSet::const_iterator it2 =
         it1->second.begin(); it2 != it1->second.end(); ++it2) {
      value->Append(it2->ToValue().release());
    }
  }
  return value.Pass();
}

bool ObjectIdInvalidationMap::ResetFromValue(const base::ListValue& value) {
  map_.clear();
  for (size_t i = 0; i < value.GetSize(); ++i) {
    const DictionaryValue* dict;
    if (!value.GetDictionary(i, &dict)) {
      return false;
    }
    scoped_ptr<Invalidation> invalidation = Invalidation::InitFromValue(*dict);
    if (!invalidation) {
      return false;
    }
    Insert(*invalidation.get());
  }
  return true;
}

std::string ObjectIdInvalidationMap::ToString() const {
  std::string output;
  JSONStringValueSerializer serializer(&output);
  serializer.set_pretty_print(true);
  serializer.Serialize(*ToValue().get());
  return output;
}

ObjectIdInvalidationMap::ObjectIdInvalidationMap(const IdToListMap& map)
  : map_(map) {}

}  // namespace syncer