1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 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/sync/engine/syncapi.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/profile_sync_service.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kTypedUrlTag[] = "google_chrome_typed_urls";
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTypedUrlModelAssociator::TypedUrlModelAssociator(
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProfileSyncService* sync_service,
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::HistoryBackend* history_backend)
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : sync_service_(sync_service),
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history_backend_(history_backend),
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      typed_url_node_id_(sync_api::kInvalidId),
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      expected_loop_(MessageLoop::current()) {
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(sync_service_);
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(history_backend_);
28731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31513209b27ff55e2841eac0e4120199c23acce758Ben MurdochTypedUrlModelAssociator::~TypedUrlModelAssociator() {}
32513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TypedUrlModelAssociator::AssociateModels() {
34731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "Associating TypedUrl Models";
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<history::URLRow> typed_urls;
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!history_backend_->GetAllTypedURLs(&typed_urls)) {
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Could not get the typed_url entries.";
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get all the visits.
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::map<history::URLID, history::VisitVector> visit_vectors;
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<history::URLRow>::iterator ix = typed_urls.begin();
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ix != typed_urls.end(); ++ix) {
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!history_backend_->GetVisitsForURL(ix->id(),
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           &(visit_vectors[ix->id()]))) {
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Could not get the url's visits.";
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(!visit_vectors[ix->id()].empty());
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlTitleVector titles;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlVector new_urls;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlVisitVector new_visits;
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlUpdateVector updated_urls;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    sync_api::WriteTransaction trans(sync_service_->GetUserShare());
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
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // propagated 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  }
21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::ReadNode typed_url_node(&trans);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!typed_url_node.InitByIdLookup(typed_url_sync_id)) {
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Server did not create the top-level typed_url node. We "
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << "might be running against an out-of-date server.";
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The sync model has user created nodes if the typed_url folder has any
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // children.
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *has_nodes = sync_api::kInvalidId != typed_url_node.GetFirstChildId();
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid TypedUrlModelAssociator::AbortAssociation() {
23421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // TODO(zork): Implement this.
23521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
23621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
23721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenconst std::string* TypedUrlModelAssociator::GetChromeNodeFromSyncId(
23821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    int64 sync_id) {
23921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return NULL;
24021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
24121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
24221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool TypedUrlModelAssociator::InitSyncNodeFromChromeId(
24321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const std::string& node_id,
24421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    sync_api::BaseNode* sync_node) {
24521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return false;
24621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
24721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 TypedUrlModelAssociator::GetSyncIdFromChromeId(
24921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const std::string& typed_url) {
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TypedUrlToSyncIdMap::const_iterator iter = id_map_.find(typed_url);
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlModelAssociator::Associate(
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string* typed_url, int64 sync_id) {
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(sync_api::kInvalidId, sync_id);
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(id_map_.find(*typed_url) == id_map_.end());
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_[*typed_url] = sync_id;
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_[sync_id] = *typed_url;
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlModelAssociator::Disassociate(int64 sync_id) {
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SyncIdToTypedUrlMap::iterator iter = id_map_inverse_.find(sync_id);
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (iter == id_map_inverse_.end())
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(id_map_.erase(iter->second));
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_.erase(iter);
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TypedUrlModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     int64* sync_id) {
27572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::ReadNode sync_node(&trans);
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!sync_node.InitByTagLookup(tag.c_str()))
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *sync_id = sync_node.GetId();
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TypedUrlModelAssociator::WriteToHistoryBackend(
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TypedUrlTitleVector* titles,
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TypedUrlVector* new_urls,
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TypedUrlUpdateVector* updated_urls,
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const TypedUrlVisitVector* new_visits,
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::VisitVector* deleted_visits) {
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (titles) {
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (TypedUrlTitleVector::const_iterator title = titles->begin();
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         title != titles->end(); ++title) {
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      history_backend_->SetPageTitle(title->first, title->second);
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_urls) {
2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    history_backend_->AddPagesWithDetails(*new_urls, history::SOURCE_SYNCED);
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (updated_urls) {
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (TypedUrlUpdateVector::const_iterator url = updated_urls->begin();
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         url != updated_urls->end(); ++url) {
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!history_backend_->UpdateURL(url->first, url->second)) {
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(ERROR) << "Could not update page: " << url->second.url().spec();
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_visits) {
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (TypedUrlVisitVector::const_iterator visits = new_visits->begin();
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         visits != new_visits->end(); ++visits) {
3103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick           if (!history_backend_->AddVisits(visits->first, visits->second,
3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                            history::SOURCE_SYNCED)) {
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(ERROR) << "Could not add visits.";
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (deleted_visits) {
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!history_backend_->RemoveVisits(*deleted_visits)) {
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Could not remove visits.";
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TypedUrlModelAssociator::MergeUrls(
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::TypedUrlSpecifics& typed_url,
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::URLRow& url,
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::VisitVector* visits,
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::URLRow* new_url,
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<base::Time>* new_visits) {
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(new_url);
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!typed_url.url().compare(url.url().spec()));
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!typed_url.url().compare(new_url->url().spec()));
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(visits->size());
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_url->set_visit_count(visits->size());
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Convert these values only once.
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string16 typed_title(UTF8ToUTF16(typed_url.title()));
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::Time typed_visit =
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      base::Time::FromInternalValue(
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          typed_url.visit(typed_url.visit_size() - 1));
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This is a bitfield represting what we'll need to update with the output
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // value.
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int different = DIFF_NONE;
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check if the non-incremented values changed.
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if ((typed_title.compare(url.title()) != 0) ||
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (typed_url.hidden() != url.hidden())) {
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Use the values from the most recent visit.
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (typed_visit >= url.last_visit()) {
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_url->set_title(typed_title);
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_url->set_hidden(typed_url.hidden());
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      different |= DIFF_ROW_CHANGED;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // If we're changing the local title, note this.
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (new_url->title().compare(url.title()) != 0) {
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        different |= DIFF_TITLE_CHANGED;
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_url->set_title(url.title());
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_url->set_hidden(url.hidden());
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      different |= DIFF_NODE_CHANGED;
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No difference.
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_title(url.title());
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_hidden(url.hidden());
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For typed count, we just select the maximum value.
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (typed_url.typed_count() > url.typed_count()) {
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_typed_count(typed_url.typed_count());
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    different |= DIFF_ROW_CHANGED;
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (typed_url.typed_count() < url.typed_count()) {
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_typed_count(url.typed_count());
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    different |= DIFF_NODE_CHANGED;
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No difference.
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_url->set_typed_count(typed_url.typed_count());
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t left_visit_count = typed_url.visit_size();
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t right_visit_count = visits->size();
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t left = 0;
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t right = 0;
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (left < left_visit_count && right < right_visit_count) {
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::Time left_time = base::Time::FromInternalValue(typed_url.visit(left));
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (left_time < (*visits)[right].visit_time) {
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      different |= DIFF_VISITS_ADDED;
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_visits->push_back(left_time);
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This visit is added to visits below.
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++left;
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (left_time > (*visits)[right].visit_time) {
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      different |= DIFF_NODE_CHANGED;
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++right;
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++left;
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++right;
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for ( ; left < left_visit_count; ++left) {
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    different |= DIFF_VISITS_ADDED;
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::Time left_time = base::Time::FromInternalValue(typed_url.visit(left));
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_visits->push_back(left_time);
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This visit is added to visits below.
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (different & DIFF_VISITS_ADDED) {
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::VisitVector::iterator visit_ix = visits->begin();
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (std::vector<base::Time>::iterator new_visit = new_visits->begin();
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         new_visit != new_visits->end(); ++new_visit) {
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      while (visit_ix != visits->end() && *new_visit > visit_ix->visit_time) {
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ++visit_ix;
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      visit_ix = visits->insert(visit_ix,
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                history::VisitRow(url.id(), *new_visit,
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                  0, 0, 0));
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++visit_ix;
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_url->set_last_visit(visits->back().visit_time);
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(static_cast<size_t>(new_url->visit_count()) ==
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         (visits->size() - new_visits->size()));
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return different;
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlModelAssociator::WriteToSyncNode(
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::URLRow& url,
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::VisitVector& visits,
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::WriteNode* node) {
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!url.last_visit().is_null());
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!visits.empty());
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(url.last_visit() == visits.back().visit_time);
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::TypedUrlSpecifics typed_url;
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typed_url.set_url(url.url().spec());
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typed_url.set_title(UTF16ToUTF8(url.title()));
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typed_url.set_typed_count(url.typed_count());
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  typed_url.set_hidden(url.hidden());
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (history::VisitVector::const_iterator visit = visits.begin();
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       visit != visits.end(); ++visit) {
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    typed_url.add_visit(visit->visit_time.ToInternalValue());
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  node->SetTypedUrlSpecifics(typed_url);
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TypedUrlModelAssociator::DiffVisits(
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const history::VisitVector& old_visits,
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const sync_pb::TypedUrlSpecifics& new_url,
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<base::Time>* new_visits,
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    history::VisitVector* removed_visits) {
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t left_visit_count = old_visits.size();
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t right_visit_count = new_url.visit_size();
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t left = 0;
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t right = 0;
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (left < left_visit_count && right < right_visit_count) {
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::Time right_time = base::Time::FromInternalValue(new_url.visit(right));
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (old_visits[left].visit_time < right_time) {
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      removed_visits->push_back(old_visits[left]);
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++left;
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (old_visits[left].visit_time > right_time) {
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      new_visits->push_back(right_time);
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++right;
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++left;
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++right;
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for ( ; left < left_visit_count; ++left) {
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    removed_visits->push_back(old_visits[left]);
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for ( ; right < right_visit_count; ++right) {
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new_visits->push_back(base::Time::FromInternalValue(new_url.visit(right)));
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool TypedUrlModelAssociator::CryptoReadyIfNecessary() {
491ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We only access the cryptographer while holding a transaction.
492ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
493ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  syncable::ModelTypeSet encrypted_types;
494ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_service_->GetEncryptedDataTypes(&encrypted_types);
495ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return encrypted_types.count(syncable::TYPED_URLS) == 0 ||
496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         sync_service_->IsCryptographerReady(&trans);
497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
500