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 "sync/api/sync_data.h"
6
7#include <ostream>
8
9#include "base/json/json_writer.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/strings/string_number_conversions.h"
12#include "base/values.h"
13#include "sync/internal_api/public/attachments/attachment_service_proxy.h"
14#include "sync/internal_api/public/base/model_type.h"
15#include "sync/internal_api/public/base_node.h"
16#include "sync/protocol/proto_value_conversions.h"
17#include "sync/protocol/sync.pb.h"
18
19namespace {
20
21sync_pb::AttachmentIdProto IdToProto(
22    const syncer::AttachmentId& attachment_id) {
23  return attachment_id.GetProto();
24}
25
26syncer::AttachmentId ProtoToId(const sync_pb::AttachmentIdProto& proto) {
27  return syncer::AttachmentId::CreateFromProto(proto);
28}
29
30// Return true iff |attachment_ids| contains duplicates.
31bool ContainsDuplicateAttachments(
32    const syncer::AttachmentIdList& attachment_ids) {
33  syncer::AttachmentIdSet id_set;
34  id_set.insert(attachment_ids.begin(), attachment_ids.end());
35  return id_set.size() != attachment_ids.size();
36}
37
38}  // namespace
39
40namespace syncer {
41
42void SyncData::ImmutableSyncEntityTraits::InitializeWrapper(Wrapper* wrapper) {
43  *wrapper = new sync_pb::SyncEntity();
44}
45
46void SyncData::ImmutableSyncEntityTraits::DestroyWrapper(Wrapper* wrapper) {
47  delete *wrapper;
48}
49
50const sync_pb::SyncEntity& SyncData::ImmutableSyncEntityTraits::Unwrap(
51    const Wrapper& wrapper) {
52  return *wrapper;
53}
54
55sync_pb::SyncEntity* SyncData::ImmutableSyncEntityTraits::UnwrapMutable(
56    Wrapper* wrapper) {
57  return *wrapper;
58}
59
60void SyncData::ImmutableSyncEntityTraits::Swap(sync_pb::SyncEntity* t1,
61                                               sync_pb::SyncEntity* t2) {
62  t1->Swap(t2);
63}
64
65SyncData::SyncData() : id_(kInvalidId), is_valid_(false) {}
66
67SyncData::SyncData(int64 id,
68                   sync_pb::SyncEntity* entity,
69                   const base::Time& remote_modification_time,
70                   const syncer::AttachmentServiceProxy& attachment_service)
71    : id_(id),
72      remote_modification_time_(remote_modification_time),
73      immutable_entity_(entity),
74      attachment_service_(attachment_service),
75      is_valid_(true) {}
76
77SyncData::~SyncData() {}
78
79// Static.
80SyncData SyncData::CreateLocalDelete(const std::string& sync_tag,
81                                     ModelType datatype) {
82  sync_pb::EntitySpecifics specifics;
83  AddDefaultFieldValue(datatype, &specifics);
84  return CreateLocalData(sync_tag, std::string(), specifics);
85}
86
87// Static.
88SyncData SyncData::CreateLocalData(const std::string& sync_tag,
89                                   const std::string& non_unique_title,
90                                   const sync_pb::EntitySpecifics& specifics) {
91  syncer::AttachmentIdList attachment_ids;
92  return CreateLocalDataWithAttachments(
93      sync_tag, non_unique_title, specifics, attachment_ids);
94}
95
96// Static.
97SyncData SyncData::CreateLocalDataWithAttachments(
98    const std::string& sync_tag,
99    const std::string& non_unique_title,
100    const sync_pb::EntitySpecifics& specifics,
101    const AttachmentIdList& attachment_ids) {
102  DCHECK(!ContainsDuplicateAttachments(attachment_ids));
103  sync_pb::SyncEntity entity;
104  entity.set_client_defined_unique_tag(sync_tag);
105  entity.set_non_unique_name(non_unique_title);
106  entity.mutable_specifics()->CopyFrom(specifics);
107  std::transform(attachment_ids.begin(),
108                 attachment_ids.end(),
109                 RepeatedFieldBackInserter(entity.mutable_attachment_id()),
110                 IdToProto);
111  return SyncData(kInvalidId,
112                  &entity,
113                  base::Time(),
114                  AttachmentServiceProxy());
115}
116
117// Static.
118SyncData SyncData::CreateRemoteData(
119    int64 id,
120    const sync_pb::EntitySpecifics& specifics,
121    const base::Time& modification_time,
122    const AttachmentIdList& attachment_ids,
123    const AttachmentServiceProxy& attachment_service) {
124  DCHECK_NE(id, kInvalidId);
125  sync_pb::SyncEntity entity;
126  entity.mutable_specifics()->CopyFrom(specifics);
127  std::transform(attachment_ids.begin(),
128                 attachment_ids.end(),
129                 RepeatedFieldBackInserter(entity.mutable_attachment_id()),
130                 IdToProto);
131  return SyncData(id, &entity, modification_time, attachment_service);
132}
133
134bool SyncData::IsValid() const { return is_valid_; }
135
136const sync_pb::EntitySpecifics& SyncData::GetSpecifics() const {
137  return immutable_entity_.Get().specifics();
138}
139
140ModelType SyncData::GetDataType() const {
141  return GetModelTypeFromSpecifics(GetSpecifics());
142}
143
144const std::string& SyncData::GetTitle() const {
145  // TODO(zea): set this for data coming from the syncer too.
146  DCHECK(immutable_entity_.Get().has_non_unique_name());
147  return immutable_entity_.Get().non_unique_name();
148}
149
150bool SyncData::IsLocal() const { return id_ == kInvalidId; }
151
152std::string SyncData::ToString() const {
153  if (!IsValid())
154    return "<Invalid SyncData>";
155
156  std::string type = ModelTypeToString(GetDataType());
157  std::string specifics;
158  scoped_ptr<base::DictionaryValue> value(
159      EntitySpecificsToValue(GetSpecifics()));
160  base::JSONWriter::WriteWithOptions(
161      value.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &specifics);
162
163  if (IsLocal()) {
164    SyncDataLocal sync_data_local(*this);
165    return "{ isLocal: true, type: " + type + ", tag: " +
166           sync_data_local.GetTag() + ", title: " + GetTitle() +
167           ", specifics: " + specifics + "}";
168  }
169
170  SyncDataRemote sync_data_remote(*this);
171  std::string id = base::Int64ToString(sync_data_remote.GetId());
172  return "{ isLocal: false, type: " + type + ", specifics: " + specifics +
173         ", id: " + id + "}";
174}
175
176void PrintTo(const SyncData& sync_data, std::ostream* os) {
177  *os << sync_data.ToString();
178}
179
180AttachmentIdList SyncData::GetAttachmentIds() const {
181  AttachmentIdList result;
182  const sync_pb::SyncEntity& entity = immutable_entity_.Get();
183  std::transform(entity.attachment_id().begin(),
184                 entity.attachment_id().end(),
185                 std::back_inserter(result),
186                 ProtoToId);
187  return result;
188}
189
190SyncDataLocal::SyncDataLocal(const SyncData& sync_data) : SyncData(sync_data) {
191  DCHECK(sync_data.IsLocal());
192}
193
194SyncDataLocal::~SyncDataLocal() {}
195
196const std::string& SyncDataLocal::GetTag() const {
197  return immutable_entity_.Get().client_defined_unique_tag();
198}
199
200SyncDataRemote::SyncDataRemote(const SyncData& sync_data)
201    : SyncData(sync_data) {
202  DCHECK(!sync_data.IsLocal());
203}
204
205SyncDataRemote::~SyncDataRemote() {}
206
207const base::Time& SyncDataRemote::GetModifiedTime() const {
208  return remote_modification_time_;
209}
210
211int64 SyncDataRemote::GetId() const {
212  return id_;
213}
214
215void SyncDataRemote::GetOrDownloadAttachments(
216    const AttachmentIdList& attachment_ids,
217    const AttachmentService::GetOrDownloadCallback& callback) {
218  attachment_service_.GetOrDownloadAttachments(attachment_ids, callback);
219}
220
221void SyncDataRemote::DropAttachments(
222    const AttachmentIdList& attachment_ids,
223    const AttachmentService::DropCallback& callback) {
224  attachment_service_.DropAttachments(attachment_ids, callback);
225}
226
227}  // namespace syncer
228