1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/drive/file_task_executor.h"
6
7#include <string>
8#include <vector>
9
10#include "chrome/browser/chromeos/drive/drive.pb.h"
11#include "chrome/browser/chromeos/drive/drive_integration_service.h"
12#include "chrome/browser/chromeos/drive/file_system_interface.h"
13#include "chrome/browser/drive/drive_service_interface.h"
14#include "chrome/browser/profiles/profile_manager.h"
15#include "chrome/browser/ui/browser.h"
16#include "chrome/browser/ui/browser_finder.h"
17#include "chrome/browser/ui/browser_tabstrip.h"
18#include "chrome/browser/ui/browser_window.h"
19#include "content/public/browser/browser_thread.h"
20#include "webkit/browser/fileapi/file_system_url.h"
21
22using fileapi::FileSystemURL;
23
24namespace drive {
25
26FileTaskExecutor::FileTaskExecutor(Profile* profile,
27                                   const std::string& app_id)
28  : profile_(profile),
29    app_id_(app_id),
30    current_index_(0),
31    weak_ptr_factory_(this) {
32}
33
34FileTaskExecutor::~FileTaskExecutor() {
35}
36
37void FileTaskExecutor::Execute(
38    const std::vector<FileSystemURL>& file_urls,
39    const file_manager::file_tasks::FileTaskFinishedCallback& done) {
40  std::vector<base::FilePath> paths;
41  for (size_t i = 0; i < file_urls.size(); ++i) {
42    base::FilePath path = util::ExtractDrivePathFromFileSystemUrl(file_urls[i]);
43    if (path.empty()) {
44      Done(false);
45      return;
46    }
47    paths.push_back(path);
48  }
49
50  DriveIntegrationService* integration_service =
51      DriveIntegrationServiceFactory::GetForProfile(profile_);
52  DCHECK_EQ(current_index_, 0);
53  if (!integration_service || !integration_service->file_system()) {
54    Done(false);
55    return;
56  }
57  FileSystemInterface* file_system = integration_service->file_system();
58
59  done_ = done;
60  // Reset the index, so we know when we're done.
61  current_index_ = paths.size();
62
63  for (size_t i = 0; i < paths.size(); ++i) {
64    file_system->GetResourceEntryByPath(
65        paths[i],
66        base::Bind(&FileTaskExecutor::OnFileEntryFetched,
67                   weak_ptr_factory_.GetWeakPtr()));
68  }
69}
70
71void FileTaskExecutor::OnFileEntryFetched(FileError error,
72                                          scoped_ptr<ResourceEntry> entry) {
73  DriveIntegrationService* integration_service =
74      DriveIntegrationServiceFactory::GetForProfile(profile_);
75
76  // Here, we are only interested in files.
77  if (entry.get() && !entry->has_file_specific_info())
78    error = FILE_ERROR_NOT_FOUND;
79
80  if (!integration_service || error != FILE_ERROR_OK) {
81    Done(false);
82    return;
83  }
84
85  DriveServiceInterface* drive_service =
86      integration_service->drive_service();
87
88  // Send off a request for the drive service to authorize the apps for the
89  // current document entry for this document so we can get the
90  // open-with-<app_id> urls from the document entry.
91  drive_service->AuthorizeApp(entry->resource_id(),
92                              app_id_,
93                              base::Bind(&FileTaskExecutor::OnAppAuthorized,
94                                         weak_ptr_factory_.GetWeakPtr(),
95                                         entry->resource_id()));
96}
97
98void FileTaskExecutor::OnAppAuthorized(const std::string& resource_id,
99                                       google_apis::GDataErrorCode error,
100                                       const GURL& open_link) {
101  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
102
103  DriveIntegrationService* integration_service =
104      DriveIntegrationServiceFactory::GetForProfile(profile_);
105
106  if (!integration_service || error != google_apis::HTTP_SUCCESS) {
107    Done(false);
108    return;
109  }
110
111  if (open_link.is_empty()) {
112    Done(false);
113    return;
114  }
115
116  Browser* browser = chrome::FindOrCreateTabbedBrowser(
117      profile_ ? profile_ : ProfileManager::GetDefaultProfileOrOffTheRecord(),
118      chrome::HOST_DESKTOP_TYPE_ASH);
119
120  chrome::AddSelectedTabWithURL(browser, open_link,
121                                content::PAGE_TRANSITION_LINK);
122  // If the current browser is not tabbed then the new tab will be created
123  // in a different browser. Make sure it is visible.
124  browser->window()->Show();
125
126  // We're done with this file.  If this is the last one, then we're done.
127  current_index_--;
128  DCHECK_GE(current_index_, 0);
129  if (current_index_ == 0)
130    Done(true);
131}
132
133void FileTaskExecutor::Done(bool success) {
134  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
135  if (!done_.is_null())
136    done_.Run(success);
137  delete this;
138}
139
140}  // namespace drive
141