typed_url_model_associator.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/typed_url_model_associator.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_backend.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/profile.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncapi.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/profile_sync_service.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kTypedUrlTag[] = "google_chrome_typed_urls";
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTypedUrlModelAssociator::TypedUrlModelAssociator(
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProfileSyncService* sync_service,
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::HistoryBackend* history_backend)
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : sync_service_(sync_service),
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history_backend_(history_backend),
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      typed_url_node_id_(sync_api::kInvalidId),
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      expected_loop_(MessageLoop::current()) {
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(sync_service_);
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(history_backend_);
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::UI));
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TypedUrlModelAssociator::AssociateModels() {
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LOG(INFO) << "Associating TypedUrl Models";
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<history::URLRow> typed_urls;
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!history_backend_->GetAllTypedURLs(&typed_urls)) {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Could not get the typed_url entries.";
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get all the visits.
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<history::URLID, history::VisitVector> visit_vectors;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<history::URLRow>::iterator ix = typed_urls.begin();
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ix != typed_urls.end(); ++ix) {
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!history_backend_->GetVisitsForURL(ix->id(),
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           &(visit_vectors[ix->id()]))) {
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Could not get the url's visits.";
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(!visit_vectors[ix->id()].empty());
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlTitleVector titles;
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlVector new_urls;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlVisitVector new_visits;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlUpdateVector updated_urls;
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::WriteTransaction trans(
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        sync_service_->backend()->GetUserShareHandle());
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::ReadNode typed_url_root(&trans);
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!typed_url_root.InitByTagLookup(kTypedUrlTag)) {
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Server did not create the top-level typed_url node. We "
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 << "might be running against an out-of-date server.";
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::set<std::string> current_urls;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::vector<history::URLRow>::iterator ix = typed_urls.begin();
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         ix != typed_urls.end(); ++ix) {
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string tag = ix->url().spec();
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history::VisitVector& visits = visit_vectors[ix->id()];
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK(visits.size() == static_cast<size_t>(ix->visit_count()));
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (visits.size() != static_cast<size_t>(ix->visit_count())) {
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(ERROR) << "Visit count does not match.";
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      sync_api::ReadNode node(&trans);
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (node.InitByClientTagLookup(syncable::TYPED_URLS, tag)) {
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const sync_pb::TypedUrlSpecifics& typed_url(
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            node.GetTypedUrlSpecifics());
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_EQ(tag, typed_url.url());
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        history::URLRow new_url(ix->url());
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::vector<base::Time> added_visits;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        int difference = MergeUrls(typed_url, *ix, &visits, &new_url,
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   &added_visits);
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (difference & DIFF_NODE_CHANGED) {
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          sync_api::WriteNode write_node(&trans);
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          if (!write_node.InitByClientTagLookup(syncable::TYPED_URLS, tag)) {
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            LOG(ERROR) << "Failed to edit typed_url sync node.";
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            return false;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          }
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          WriteToSyncNode(new_url, visits, &write_node);
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (difference & DIFF_TITLE_CHANGED) {
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          titles.push_back(std::pair<GURL, string16>(new_url.url(),
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     new_url.title()));
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (difference & DIFF_ROW_CHANGED) {
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          updated_urls.push_back(
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              std::pair<history::URLID, history::URLRow>(ix->id(), new_url));
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (difference & DIFF_VISITS_ADDED) {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          new_visits.push_back(
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              std::pair<GURL, std::vector<base::Time> >(ix->url(),
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                        added_visits));
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Associate(&tag, node.GetId());
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        sync_api::WriteNode node(&trans);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!node.InitUniqueByCreation(syncable::TYPED_URLS,
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       typed_url_root, tag)) {
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          LOG(ERROR) << "Failed to create typed_url sync node.";
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        node.SetTitle(UTF8ToWide(tag));
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        WriteToSyncNode(*ix, visits, &node);
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Associate(&tag, node.GetId());
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      current_urls.insert(tag);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int64 sync_child_id = typed_url_root.GetFirstChildId();
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    while (sync_child_id != sync_api::kInvalidId) {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      sync_api::ReadNode sync_child_node(&trans);
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!sync_child_node.InitByIdLookup(sync_child_id)) {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(ERROR) << "Failed to fetch child node.";
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const sync_pb::TypedUrlSpecifics& typed_url(
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        sync_child_node.GetTypedUrlSpecifics());
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (current_urls.find(typed_url.url()) == current_urls.end()) {
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_visits.push_back(
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            std::pair<GURL, std::vector<base::Time> >(
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                GURL(typed_url.url()),
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                std::vector<base::Time>()));
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::vector<base::Time>& visits = new_visits.back().second;
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        history::URLRow new_url(GURL(typed_url.url()));
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_url.set_title(UTF8ToUTF16(typed_url.title()));
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // When we add a new url, the last visit is always added, thus we set
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // the initial visit count to one.  This value will be automatically
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // incremented as visits are added.
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_url.set_visit_count(1);
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_url.set_typed_count(typed_url.typed_count());
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_url.set_hidden(typed_url.hidden());
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // The latest visit gets added automatically, so skip it.
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        for (int c = 0; c < typed_url.visit_size() - 1; ++c) {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          DCHECK(typed_url.visit(c) < typed_url.visit(c + 1));
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          visits.push_back(base::Time::FromInternalValue(typed_url.visit(c)));
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_url.set_last_visit(base::Time::FromInternalValue(
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            typed_url.visit(typed_url.visit_size() - 1)));
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        Associate(&typed_url.url(), sync_child_node.GetId());
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        new_urls.push_back(new_url);
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      sync_child_id = sync_child_node.GetSuccessorId();
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Since we're on the history thread, we don't have to worry about updating
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the history database after closing the write transaction, since
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // this is the only thread that writes to the database.  We also don't have
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to worry about the sync model getting out of sync, because changes are
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // propogated to the ChangeProcessor on this thread.
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return WriteToHistoryBackend(&titles, &new_urls, &updated_urls,
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               &new_visits, NULL);
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TypedUrlModelAssociator::DeleteAllNodes(
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::WriteTransaction* trans) {
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (TypedUrlToSyncIdMap::iterator node_id = id_map_.begin();
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       node_id != id_map_.end(); ++node_id) {
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::WriteNode sync_node(trans);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!sync_node.InitByIdLookup(node_id->second)) {
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Typed url node lookup failed.";
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_node.Remove();
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_.clear();
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_.clear();
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TypedUrlModelAssociator::DisassociateModels() {
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_.clear();
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_.clear();
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TypedUrlModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(has_nodes);
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *has_nodes = false;
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 typed_url_sync_id;
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetSyncIdForTaggedNode(kTypedUrlTag, &typed_url_sync_id)) {
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Server did not create the top-level typed_url node. We "
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << "might be running against an out-of-date server.";
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::ReadTransaction trans(
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      sync_service_->backend()->GetUserShareHandle());
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::ReadNode typed_url_node(&trans);
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!typed_url_node.InitByIdLookup(typed_url_sync_id)) {
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Server did not create the top-level typed_url node. We "
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << "might be running against an out-of-date server.";
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The sync model has user created nodes if the typed_url folder has any
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // children.
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *has_nodes = sync_api::kInvalidId != typed_url_node.GetFirstChildId();
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 TypedUrlModelAssociator::GetSyncIdFromChromeId(
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string typed_url) {
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlToSyncIdMap::const_iterator iter = id_map_.find(typed_url);
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlModelAssociator::Associate(
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string* typed_url, int64 sync_id) {
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(sync_api::kInvalidId, sync_id);
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(id_map_.find(*typed_url) == id_map_.end());
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_[*typed_url] = sync_id;
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_[sync_id] = *typed_url;
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlModelAssociator::Disassociate(int64 sync_id) {
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SyncIdToTypedUrlMap::iterator iter = id_map_inverse_.find(sync_id);
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (iter == id_map_inverse_.end())
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(id_map_.erase(iter->second));
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_.erase(iter);
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TypedUrlModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     int64* sync_id) {
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::ReadTransaction trans(
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      sync_service_->backend()->GetUserShareHandle());
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::ReadNode sync_node(&trans);
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!sync_node.InitByTagLookup(tag.c_str()))
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *sync_id = sync_node.GetId();
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TypedUrlModelAssociator::WriteToHistoryBackend(
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TypedUrlTitleVector* titles,
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TypedUrlVector* new_urls,
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TypedUrlUpdateVector* updated_urls,
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TypedUrlVisitVector* new_visits,
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::VisitVector* deleted_visits) {
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (titles) {
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (TypedUrlTitleVector::const_iterator title = titles->begin();
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         title != titles->end(); ++title) {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history_backend_->SetPageTitle(title->first, title->second);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_urls) {
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history_backend_->AddPagesWithDetails(*new_urls);
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (updated_urls) {
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (TypedUrlUpdateVector::const_iterator url = updated_urls->begin();
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         url != updated_urls->end(); ++url) {
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!history_backend_->UpdateURL(url->first, url->second)) {
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(ERROR) << "Could not update page: " << url->second.url().spec();
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_visits) {
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (TypedUrlVisitVector::const_iterator visits = new_visits->begin();
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         visits != new_visits->end(); ++visits) {
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!history_backend_->AddVisits(visits->first, visits->second)) {
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(ERROR) << "Could not add visits.";
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (deleted_visits) {
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!history_backend_->RemoveVisits(*deleted_visits)) {
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Could not remove visits.";
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TypedUrlModelAssociator::MergeUrls(
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::TypedUrlSpecifics& typed_url,
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::URLRow& url,
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::VisitVector* visits,
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::URLRow* new_url,
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<base::Time>* new_visits) {
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(new_url);
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!typed_url.url().compare(url.url().spec()));
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!typed_url.url().compare(new_url->url().spec()));
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(visits->size());
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_url->set_visit_count(visits->size());
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Convert these values only once.
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string16 typed_title(UTF8ToUTF16(typed_url.title()));
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::Time typed_visit =
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      base::Time::FromInternalValue(
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          typed_url.visit(typed_url.visit_size() - 1));
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is a bitfield represting what we'll need to update with the output
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // value.
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int different = DIFF_NONE;
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check if the non-incremented values changed.
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((typed_title.compare(url.title()) != 0) ||
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (typed_url.hidden() != url.hidden())) {
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Use the values from the most recent visit.
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (typed_visit >= url.last_visit()) {
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_url->set_title(typed_title);
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_url->set_hidden(typed_url.hidden());
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      different |= DIFF_ROW_CHANGED;
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If we're changing the local title, note this.
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (new_url->title().compare(url.title()) != 0) {
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        different |= DIFF_TITLE_CHANGED;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_url->set_title(url.title());
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_url->set_hidden(url.hidden());
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      different |= DIFF_NODE_CHANGED;
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No difference.
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_title(url.title());
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_hidden(url.hidden());
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For typed count, we just select the maximum value.
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (typed_url.typed_count() > url.typed_count()) {
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_typed_count(typed_url.typed_count());
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    different |= DIFF_ROW_CHANGED;
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (typed_url.typed_count() < url.typed_count()) {
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_typed_count(url.typed_count());
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    different |= DIFF_NODE_CHANGED;
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No difference.
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_typed_count(typed_url.typed_count());
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t left_visit_count = typed_url.visit_size();
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t right_visit_count = visits->size();
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t left = 0;
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t right = 0;
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (left < left_visit_count && right < right_visit_count) {
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::Time left_time = base::Time::FromInternalValue(typed_url.visit(left));
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (left_time < (*visits)[right].visit_time) {
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      different |= DIFF_VISITS_ADDED;
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_visits->push_back(left_time);
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This visit is added to visits below.
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++left;
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (left_time > (*visits)[right].visit_time) {
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      different |= DIFF_NODE_CHANGED;
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++right;
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++left;
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++right;
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for ( ; left < left_visit_count; ++left) {
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    different |= DIFF_VISITS_ADDED;
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::Time left_time = base::Time::FromInternalValue(typed_url.visit(left));
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_visits->push_back(left_time);
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This visit is added to visits below.
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (different & DIFF_VISITS_ADDED) {
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::VisitVector::iterator visit_ix = visits->begin();
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::vector<base::Time>::iterator new_visit = new_visits->begin();
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         new_visit != new_visits->end(); ++new_visit) {
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      while (visit_ix != visits->end() && *new_visit > visit_ix->visit_time) {
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ++visit_ix;
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      visit_ix = visits->insert(visit_ix,
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                history::VisitRow(url.id(), *new_visit,
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  0, 0, 0));
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++visit_ix;
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_url->set_last_visit(visits->back().visit_time);
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(static_cast<size_t>(new_url->visit_count()) ==
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (visits->size() - new_visits->size()));
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return different;
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlModelAssociator::WriteToSyncNode(
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::URLRow& url,
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::VisitVector& visits,
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::WriteNode* node) {
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!url.last_visit().is_null());
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!visits.empty());
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(url.last_visit() == visits.back().visit_time);
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::TypedUrlSpecifics typed_url;
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typed_url.set_url(url.url().spec());
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typed_url.set_title(UTF16ToUTF8(url.title()));
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typed_url.set_typed_count(url.typed_count());
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typed_url.set_hidden(url.hidden());
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (history::VisitVector::const_iterator visit = visits.begin();
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       visit != visits.end(); ++visit) {
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    typed_url.add_visit(visit->visit_time.ToInternalValue());
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  node->SetTypedUrlSpecifics(typed_url);
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlModelAssociator::DiffVisits(
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::VisitVector& old_visits,
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::TypedUrlSpecifics& new_url,
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<base::Time>* new_visits,
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::VisitVector* removed_visits) {
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t left_visit_count = old_visits.size();
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t right_visit_count = new_url.visit_size();
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t left = 0;
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t right = 0;
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (left < left_visit_count && right < right_visit_count) {
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::Time right_time = base::Time::FromInternalValue(new_url.visit(right));
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (old_visits[left].visit_time < right_time) {
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      removed_visits->push_back(old_visits[left]);
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++left;
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (old_visits[left].visit_time > right_time) {
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_visits->push_back(right_time);
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++right;
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++left;
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++right;
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for ( ; left < left_visit_count; ++left) {
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    removed_visits->push_back(old_visits[left]);
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for ( ; right < right_visit_count; ++right) {
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_visits->push_back(base::Time::FromInternalValue(new_url.visit(right)));
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
477