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/extensions/api/bookmarks/bookmark_api_helpers.h"
6
7#include <math.h>  // For floor()
8#include <vector>
9
10#include "base/strings/string_number_conversions.h"
11#include "base/strings/utf_string_conversions.h"
12#include "chrome/browser/bookmarks/chrome_bookmark_client.h"
13#include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h"
14#include "chrome/common/extensions/api/bookmarks.h"
15#include "components/bookmarks/browser/bookmark_model.h"
16#include "components/bookmarks/browser/bookmark_utils.h"
17
18namespace extensions {
19
20namespace keys = bookmark_api_constants;
21using api::bookmarks::BookmarkTreeNode;
22
23namespace bookmark_api_helpers {
24
25namespace {
26
27void AddNodeHelper(ChromeBookmarkClient* client,
28                   const BookmarkNode* node,
29                   std::vector<linked_ptr<BookmarkTreeNode> >* nodes,
30                   bool recurse,
31                   bool only_folders) {
32  if (node->IsVisible()) {
33    linked_ptr<BookmarkTreeNode> new_node(GetBookmarkTreeNode(client,
34                                                              node,
35                                                              recurse,
36                                                              only_folders));
37    nodes->push_back(new_node);
38  }
39}
40
41}  // namespace
42
43BookmarkTreeNode* GetBookmarkTreeNode(ChromeBookmarkClient* client,
44                                      const BookmarkNode* node,
45                                      bool recurse,
46                                      bool only_folders) {
47  BookmarkTreeNode* bookmark_tree_node = new BookmarkTreeNode;
48
49  bookmark_tree_node->id = base::Int64ToString(node->id());
50
51  const BookmarkNode* parent = node->parent();
52  if (parent) {
53    bookmark_tree_node->parent_id.reset(new std::string(
54        base::Int64ToString(parent->id())));
55    bookmark_tree_node->index.reset(new int(parent->GetIndexOf(node)));
56  }
57
58  if (!node->is_folder()) {
59    bookmark_tree_node->url.reset(new std::string(node->url().spec()));
60  } else {
61    // Javascript Date wants milliseconds since the epoch, ToDoubleT is seconds.
62    base::Time t = node->date_folder_modified();
63    if (!t.is_null()) {
64      bookmark_tree_node->date_group_modified.reset(
65          new double(floor(t.ToDoubleT() * 1000)));
66    }
67  }
68
69  bookmark_tree_node->title = base::UTF16ToUTF8(node->GetTitle());
70  if (!node->date_added().is_null()) {
71    // Javascript Date wants milliseconds since the epoch, ToDoubleT is seconds.
72    bookmark_tree_node->date_added.reset(
73        new double(floor(node->date_added().ToDoubleT() * 1000)));
74  }
75
76  if (client->IsDescendantOfManagedNode(node))
77    bookmark_tree_node->unmodifiable = BookmarkTreeNode::UNMODIFIABLE_MANAGED;
78
79  if (recurse && node->is_folder()) {
80    std::vector<linked_ptr<BookmarkTreeNode> > children;
81    for (int i = 0; i < node->child_count(); ++i) {
82      const BookmarkNode* child = node->GetChild(i);
83      if (child->IsVisible() && (!only_folders || child->is_folder())) {
84        linked_ptr<BookmarkTreeNode> child_node(
85            GetBookmarkTreeNode(client, child, true, only_folders));
86        children.push_back(child_node);
87      }
88    }
89    bookmark_tree_node->children.reset(
90        new std::vector<linked_ptr<BookmarkTreeNode> >(children));
91  }
92  return bookmark_tree_node;
93}
94
95void AddNode(ChromeBookmarkClient* client,
96             const BookmarkNode* node,
97             std::vector<linked_ptr<BookmarkTreeNode> >* nodes,
98             bool recurse) {
99  return AddNodeHelper(client, node, nodes, recurse, false);
100}
101
102void AddNodeFoldersOnly(ChromeBookmarkClient* client,
103                        const BookmarkNode* node,
104                        std::vector<linked_ptr<BookmarkTreeNode> >* nodes,
105                        bool recurse) {
106  return AddNodeHelper(client, node, nodes, recurse, true);
107}
108
109bool RemoveNode(BookmarkModel* model,
110                ChromeBookmarkClient* client,
111                int64 id,
112                bool recursive,
113                std::string* error) {
114  const BookmarkNode* node = bookmarks::GetBookmarkNodeByID(model, id);
115  if (!node) {
116    *error = keys::kNoNodeError;
117    return false;
118  }
119  if (model->is_permanent_node(node)) {
120    *error = keys::kModifySpecialError;
121    return false;
122  }
123  if (client->IsDescendantOfManagedNode(node)) {
124    *error = keys::kModifyManagedError;
125    return false;
126  }
127  if (node->is_folder() && !node->empty() && !recursive) {
128    *error = keys::kFolderNotEmptyError;
129    return false;
130  }
131
132  const BookmarkNode* parent = node->parent();
133  model->Remove(parent, parent->GetIndexOf(node));
134  return true;
135}
136
137void GetMetaInfo(const BookmarkNode& node,
138                 base::DictionaryValue* id_to_meta_info_map) {
139  if (!node.IsVisible())
140    return;
141
142  const BookmarkNode::MetaInfoMap* meta_info = node.GetMetaInfoMap();
143  base::DictionaryValue* value = new base::DictionaryValue();
144  if (meta_info) {
145    BookmarkNode::MetaInfoMap::const_iterator itr;
146    for (itr = meta_info->begin(); itr != meta_info->end(); ++itr) {
147      value->SetStringWithoutPathExpansion(itr->first, itr->second);
148    }
149  }
150  id_to_meta_info_map->Set(base::Int64ToString(node.id()), value);
151
152  if (node.is_folder()) {
153    for (int i = 0; i < node.child_count(); ++i) {
154      GetMetaInfo(*(node.GetChild(i)), id_to_meta_info_map);
155    }
156  }
157}
158
159}  // namespace bookmark_api_helpers
160}  // namespace extensions
161