Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / components / dom_distiller / core / dom_distiller_service.cc
index 6f5983b..0661f6e 100644 (file)
@@ -3,12 +3,37 @@
 // found in the LICENSE file.
 
 #include "components/dom_distiller/core/dom_distiller_service.h"
+
+#include "base/guid.h"
+#include "base/message_loop/message_loop.h"
 #include "components/dom_distiller/core/dom_distiller_store.h"
+#include "components/dom_distiller/core/proto/distilled_article.pb.h"
+#include "components/dom_distiller/core/task_tracker.h"
+#include "url/gurl.h"
 
 namespace dom_distiller {
 
-ViewerHandle::ViewerHandle() {}
-ViewerHandle::~ViewerHandle() {}
+namespace {
+
+ArticleEntry CreateSkeletonEntryForUrl(const GURL& url) {
+  ArticleEntry skeleton;
+  skeleton.set_entry_id(base::GenerateGUID());
+  ArticleEntryPage* page = skeleton.add_pages();
+  page->set_url(url.spec());
+
+  DCHECK(IsEntryValid(skeleton));
+  return skeleton;
+}
+
+void RunArticleAvailableCallback(
+    const DomDistillerService::ArticleAvailableCallback& article_cb,
+    const ArticleEntry& entry,
+    const DistilledArticleProto* article_proto,
+    bool distillation_succeeded) {
+  article_cb.Run(distillation_succeeded);
+}
+
+}  // namespace
 
 DomDistillerService::DomDistillerService(
     scoped_ptr<DomDistillerStoreInterface> store,
@@ -21,23 +46,171 @@ syncer::SyncableService* DomDistillerService::GetSyncableService() const {
   return store_->GetSyncableService();
 }
 
-void DomDistillerService::AddToList(const GURL& url) { NOTIMPLEMENTED(); }
+const std::string DomDistillerService::AddToList(
+    const GURL& url,
+    const ArticleAvailableCallback& article_cb) {
+  ArticleEntry entry;
+  const bool is_already_added = store_->GetEntryByUrl(url, &entry);
+
+  TaskTracker* task_tracker;
+  if (is_already_added) {
+    task_tracker = GetTaskTrackerForEntry(entry);
+    if (task_tracker == NULL) {
+      // Entry is in the store but there is no task tracker. This could
+      // happen when distillation has already completed. For now just return
+      // true.
+      // TODO(shashishekhar): Change this to check if article is available,
+      // An article may not be available for a variety of reasons, e.g.
+      // distillation failure or blobs not available locally.
+      base::MessageLoop::current()->PostTask(FROM_HERE,
+                                             base::Bind(article_cb, true));
+      return entry.entry_id();
+    }
+  } else {
+    task_tracker = GetOrCreateTaskTrackerForUrl(url);
+  }
+
+  if (!article_cb.is_null()) {
+    task_tracker->AddSaveCallback(
+        base::Bind(&RunArticleAvailableCallback, article_cb));
+  }
+
+  if (!is_already_added) {
+    task_tracker->AddSaveCallback(base::Bind(
+        &DomDistillerService::AddDistilledPageToList, base::Unretained(this)));
+    task_tracker->StartDistiller(distiller_factory_.get());
+  }
+
+  return task_tracker->GetEntryId();
+}
 
 std::vector<ArticleEntry> DomDistillerService::GetEntries() const {
   return store_->GetEntries();
 }
 
+scoped_ptr<ArticleEntry> DomDistillerService::RemoveEntry(
+    const std::string& entry_id) {
+  scoped_ptr<ArticleEntry> entry(new ArticleEntry);
+  entry->set_entry_id(entry_id);
+  TaskTracker* task_tracker = GetTaskTrackerForEntry(*entry);
+  if (task_tracker != NULL) {
+    task_tracker->CancelSaveCallbacks();
+  }
+
+  if (!store_->GetEntryById(entry_id, entry.get())) {
+    return scoped_ptr<ArticleEntry>();
+  }
+
+  if (store_->RemoveEntry(*entry)) {
+    return entry.Pass();
+  }
+  return scoped_ptr<ArticleEntry>();
+}
+
 scoped_ptr<ViewerHandle> DomDistillerService::ViewEntry(
-    ViewerContext* context,
+    ViewRequestDelegate* delegate,
     const std::string& entry_id) {
-  NOTIMPLEMENTED();
-  return scoped_ptr<ViewerHandle>();
+  ArticleEntry entry;
+  if (!store_->GetEntryById(entry_id, &entry)) {
+    return scoped_ptr<ViewerHandle>();
+  }
+
+  TaskTracker* task_tracker = GetOrCreateTaskTrackerForEntry(entry);
+  scoped_ptr<ViewerHandle> viewer_handle = task_tracker->AddViewer(delegate);
+  task_tracker->StartDistiller(distiller_factory_.get());
+
+  return viewer_handle.Pass();
+}
+
+scoped_ptr<ViewerHandle> DomDistillerService::ViewUrl(
+    ViewRequestDelegate* delegate,
+    const GURL& url) {
+  if (!url.is_valid()) {
+    return scoped_ptr<ViewerHandle>();
+  }
+
+  TaskTracker* task_tracker = GetOrCreateTaskTrackerForUrl(url);
+  scoped_ptr<ViewerHandle> viewer_handle = task_tracker->AddViewer(delegate);
+  task_tracker->StartDistiller(distiller_factory_.get());
+
+  return viewer_handle.Pass();
+}
+
+TaskTracker* DomDistillerService::GetOrCreateTaskTrackerForUrl(
+    const GURL& url) {
+  ArticleEntry entry;
+  if (store_->GetEntryByUrl(url, &entry)) {
+    return GetOrCreateTaskTrackerForEntry(entry);
+  }
+
+  for (TaskList::iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
+    if ((*it)->HasUrl(url)) {
+      return *it;
+    }
+  }
+
+  ArticleEntry skeleton_entry = CreateSkeletonEntryForUrl(url);
+  TaskTracker* task_tracker = CreateTaskTracker(skeleton_entry);
+  return task_tracker;
+}
+
+TaskTracker* DomDistillerService::GetTaskTrackerForEntry(
+    const ArticleEntry& entry) const {
+  const std::string& entry_id = entry.entry_id();
+  for (TaskList::const_iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
+    if ((*it)->HasEntryId(entry_id)) {
+      return *it;
+    }
+  }
+  return NULL;
+}
+
+TaskTracker* DomDistillerService::GetOrCreateTaskTrackerForEntry(
+    const ArticleEntry& entry) {
+  TaskTracker* task_tracker = GetTaskTrackerForEntry(entry);
+  if (task_tracker == NULL) {
+    task_tracker = CreateTaskTracker(entry);
+  }
+  return task_tracker;
+}
+
+TaskTracker* DomDistillerService::CreateTaskTracker(const ArticleEntry& entry) {
+  TaskTracker::CancelCallback cancel_callback =
+      base::Bind(&DomDistillerService::CancelTask, base::Unretained(this));
+  TaskTracker* tracker = new TaskTracker(entry, cancel_callback);
+  tasks_.push_back(tracker);
+  return tracker;
+}
+
+void DomDistillerService::CancelTask(TaskTracker* task) {
+  TaskList::iterator it = std::find(tasks_.begin(), tasks_.end(), task);
+  if (it != tasks_.end()) {
+    tasks_.weak_erase(it);
+    base::MessageLoop::current()->DeleteSoon(FROM_HERE, task);
+  }
+}
+
+void DomDistillerService::AddDistilledPageToList(
+    const ArticleEntry& entry,
+    const DistilledArticleProto* article_proto,
+    bool distillation_succeeded) {
+  DCHECK(IsEntryValid(entry));
+  if (distillation_succeeded) {
+    DCHECK(article_proto);
+    DCHECK_GT(article_proto->pages_size(), 0);
+    store_->AddEntry(entry);
+    DCHECK_EQ(article_proto->pages_size(), entry.pages_size());
+  }
+}
+
+void DomDistillerService::AddObserver(DomDistillerObserver* observer) {
+  DCHECK(observer);
+  store_->AddObserver(observer);
 }
 
-scoped_ptr<ViewerHandle> DomDistillerService::ViewUrl(ViewerContext* context,
-                                                      const GURL& url) {
-  NOTIMPLEMENTED();
-  return scoped_ptr<ViewerHandle>();
+void DomDistillerService::RemoveObserver(DomDistillerObserver* observer) {
+  DCHECK(observer);
+  store_->RemoveObserver(observer);
 }
 
 }  // namespace dom_distiller