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 "chrome/browser/chromeos/drive/file_change.h"
6
7#include <sstream>
8
9#include "base/logging.h"
10#include "base/strings/stringprintf.h"
11#include "chrome/browser/chromeos/drive/drive.pb.h"
12
13namespace drive {
14
15FileChange::Change::Change(ChangeType change, FileType file_type)
16    : change_(change), file_type_(file_type) {
17}
18
19std::string FileChange::Change::DebugString() const {
20  const char* change_string = NULL;
21  switch (change()) {
22    case ADD_OR_UPDATE:
23      change_string = "ADD_OR_UPDATE";
24      break;
25    case DELETE:
26      change_string = "DELETE";
27      break;
28  }
29  const char* type_string = "UNKNOWN";
30  switch (file_type()) {
31    case FileChange::FILE_TYPE_FILE:
32      type_string = "FILE";
33      break;
34    case FileChange::FILE_TYPE_DIRECTORY:
35      type_string = "DIRECTORY";
36      break;
37    case FILE_TYPE_UNKNOWN:
38      // Keeps it as "unknown".
39      break;
40  }
41  return base::StringPrintf("%s:%s", change_string, type_string);
42}
43
44FileChange::ChangeList::ChangeList() {
45}
46FileChange::ChangeList::~ChangeList() {
47}
48
49void FileChange::ChangeList::Update(const Change& new_change) {
50  if (list_.empty()) {
51    list_.push_back(new_change);
52    return;
53  }
54
55  Change& last = list_.back();
56  if (last.IsFile() != new_change.IsFile()) {
57    list_.push_back(new_change);
58    return;
59  }
60
61  if (last.change() == new_change.change())
62    return;
63
64  // ADD + DELETE on directory -> revert
65  if (!last.IsFile() && last.IsAddOrUpdate() && new_change.IsDelete()) {
66    list_.pop_back();
67    return;
68  }
69
70  // DELETE + ADD/UPDATE -> ADD/UPDATE
71  // ADD/UPDATE + DELETE -> DELETE
72  last = new_change;
73}
74
75FileChange::ChangeList FileChange::ChangeList::PopAndGetNewList() const {
76  ChangeList changes;
77  changes.list_ = this->list_;
78  changes.list_.pop_front();
79  return changes;
80}
81
82std::string FileChange::ChangeList::DebugString() const {
83  std::ostringstream ss;
84  ss << "{ ";
85  for (size_t i = 0; i < list_.size(); ++i)
86    ss << list_[i].DebugString() << ", ";
87  ss << "}";
88  return ss.str();
89}
90
91FileChange::FileChange() {
92}
93FileChange::~FileChange() {}
94
95void FileChange::Update(const base::FilePath file_path,
96                        const FileChange::Change& new_change) {
97  map_[file_path].Update(new_change);
98}
99
100void FileChange::Update(const base::FilePath file_path,
101                        const FileChange::ChangeList& new_change) {
102  for (ChangeList::List::const_iterator it = new_change.list().begin();
103       it != new_change.list().end();
104       it++) {
105    map_[file_path].Update(*it);
106  }
107}
108
109void FileChange::Update(const base::FilePath file_path,
110                        FileType file_type,
111                        FileChange::ChangeType change) {
112  Update(file_path, FileChange::Change(change, file_type));
113}
114
115void FileChange::Update(const base::FilePath file_path,
116                        const ResourceEntry& entry,
117                        FileChange::ChangeType change) {
118  FileType type =
119      entry.deleted() ? FILE_TYPE_UNKNOWN : entry.file_info().is_directory()
120                                                ? FILE_TYPE_DIRECTORY
121                                                : FILE_TYPE_FILE;
122  Update(file_path, type, change);
123}
124
125void FileChange::Apply(const FileChange& new_changed_files) {
126  for (Map::const_iterator it = new_changed_files.map().begin();
127       it != new_changed_files.map().end();
128       it++) {
129    Update(it->first, it->second);
130  }
131}
132
133size_t FileChange::CountDirectory(const base::FilePath& directory_path) const {
134  size_t count = 0;
135  for (Map::const_iterator it = map_.begin(); it != map_.end(); it++) {
136    if (it->first.DirName() == directory_path)
137      count++;
138  }
139  return count;
140}
141
142std::string FileChange::DebugString() const {
143  std::ostringstream ss;
144  ss << "{ ";
145  for (FileChange::Map::const_iterator it = map_.begin(); it != map_.end();
146       it++) {
147    ss << it->first.value() << ": " << it->second.DebugString() << ", ";
148  }
149  ss << "}";
150  return ss.str();
151}
152
153}  // namespace drive
154