#ifndef CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_V1_DRIVE_FILE_SYNC_SERVICE_H_
#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_V1_DRIVE_FILE_SYNC_SERVICE_H_
#include <deque>
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/threading/non_thread_safe.h"
#include "chrome/browser/drive/drive_notification_manager_factory.h"
#include "chrome/browser/drive/drive_notification_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/sync_file_system/conflict_resolution_resolver.h"
#include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h"
#include "chrome/browser/sync_file_system/drive_backend_v1/api_util_interface.h"
#include "chrome/browser/sync_file_system/drive_backend_v1/drive_metadata_store.h"
#include "chrome/browser/sync_file_system/drive_backend_v1/local_sync_operation_resolver.h"
#include "chrome/browser/sync_file_system/drive_backend_v1/origin_operation_queue.h"
#include "chrome/browser/sync_file_system/drive_backend_v1/remote_change_handler.h"
#include "chrome/browser/sync_file_system/file_change.h"
#include "chrome/browser/sync_file_system/local_change_processor.h"
#include "chrome/browser/sync_file_system/remote_file_sync_service.h"
#include "chrome/browser/sync_file_system/sync_action.h"
#include "chrome/browser/sync_file_system/sync_callbacks.h"
#include "chrome/browser/sync_file_system/sync_direction.h"
#include "chrome/browser/sync_file_system/sync_file_system.pb.h"
#include "chrome/browser/sync_file_system/sync_status_code.h"
class ExtensionService;
namespace google_apis {
class ResourceList;
}
namespace tracked_objects {
class Location;
}
namespace sync_file_system {
namespace drive_backend {
class LocalSyncDelegate;
class RemoteSyncDelegate;
class SyncTaskManager;
}
class DriveFileSyncService : public RemoteFileSyncService,
                             public LocalChangeProcessor,
                             public drive_backend::APIUtilObserver,
                             public drive_backend::SyncTaskManager::Client,
                             public base::NonThreadSafe,
                             public base::SupportsWeakPtr<DriveFileSyncService>,
                             public drive::DriveNotificationObserver {
 public:
  typedef base::Callback<void(const SyncStatusCallback& callback)> Task;
  static ConflictResolutionPolicy kDefaultPolicy;
  virtual ~DriveFileSyncService();
  
  static scoped_ptr<DriveFileSyncService> Create(Profile* profile);
  static void AppendDependsOnFactories(
      std::set<BrowserContextKeyedServiceFactory*>* factories);
  
  
  static scoped_ptr<DriveFileSyncService> CreateForTesting(
      Profile* profile,
      const base::FilePath& base_dir,
      scoped_ptr<drive_backend::APIUtilInterface> api_util,
      scoped_ptr<DriveMetadataStore> metadata_store);
  
  virtual void AddServiceObserver(Observer* observer) OVERRIDE;
  virtual void AddFileStatusObserver(FileStatusObserver* observer) OVERRIDE;
  virtual void RegisterOrigin(const GURL& origin,
                              const SyncStatusCallback& callback) OVERRIDE;
  virtual void EnableOrigin(const GURL& origin,
                            const SyncStatusCallback& callback) OVERRIDE;
  virtual void DisableOrigin(const GURL& origin,
                             const SyncStatusCallback& callback) OVERRIDE;
  virtual void UninstallOrigin(const GURL& origin,
                               UninstallFlag flag,
                               const SyncStatusCallback& callback) OVERRIDE;
  virtual void ProcessRemoteChange(const SyncFileCallback& callback) OVERRIDE;
  virtual void SetRemoteChangeProcessor(
      RemoteChangeProcessor* processor) OVERRIDE;
  virtual LocalChangeProcessor* GetLocalChangeProcessor() OVERRIDE;
  virtual bool IsConflicting(const fileapi::FileSystemURL& url) OVERRIDE;
  virtual RemoteServiceState GetCurrentState() const OVERRIDE;
  virtual void GetOriginStatusMap(OriginStatusMap* status_map) OVERRIDE;
  virtual scoped_ptr<base::ListValue> DumpFiles(const GURL& origin) OVERRIDE;
  virtual scoped_ptr<base::ListValue> DumpDatabase() OVERRIDE;
  virtual void SetSyncEnabled(bool enabled) OVERRIDE;
  virtual SyncStatusCode SetDefaultConflictResolutionPolicy(
      ConflictResolutionPolicy policy) OVERRIDE;
  virtual SyncStatusCode SetConflictResolutionPolicy(
      const GURL& origin,
      ConflictResolutionPolicy policy) OVERRIDE;
  virtual ConflictResolutionPolicy GetDefaultConflictResolutionPolicy() const
      OVERRIDE;
  virtual ConflictResolutionPolicy GetConflictResolutionPolicy(
      const GURL& origin) const OVERRIDE;
  virtual void GetRemoteVersions(const fileapi::FileSystemURL& url,
                                 const RemoteVersionsCallback& callback)
      OVERRIDE;
  virtual void DownloadRemoteVersion(
      const fileapi::FileSystemURL& url,
      const std::string& version_id,
      const DownloadVersionCallback& callback) OVERRIDE;
  virtual void PromoteDemotedChanges() OVERRIDE;
  
  virtual void ApplyLocalChange(
      const FileChange& change,
      const base::FilePath& local_file_path,
      const SyncFileMetadata& local_file_metadata,
      const fileapi::FileSystemURL& url,
      const SyncStatusCallback& callback) OVERRIDE;
  
  virtual void OnAuthenticated() OVERRIDE;
  virtual void OnNetworkConnected() OVERRIDE;
  
  virtual void OnNotificationReceived() OVERRIDE;
  virtual void OnPushNotificationEnabled(bool enabled) OVERRIDE;
  
  virtual void MaybeScheduleNextTask() OVERRIDE;
  virtual void NotifyLastOperationStatus(
      SyncStatusCode sync_status,
      bool used_network) OVERRIDE;
  static std::string PathToTitle(const base::FilePath& path);
  static base::FilePath TitleToPath(const std::string& title);
  static DriveMetadata::ResourceType SyncFileTypeToDriveMetadataResourceType(
      SyncFileType file_type);
  static SyncFileType DriveMetadataResourceTypeToSyncFileType(
      DriveMetadata::ResourceType resource_type);
 private:
  friend class SyncTaskManager;
  friend class drive_backend::LocalSyncDelegate;
  friend class drive_backend::RemoteSyncDelegate;
  friend class DriveFileSyncServiceFakeTest;
  friend class DriveFileSyncServiceSyncTest;
  friend class DriveFileSyncServiceTest;
  struct ApplyLocalChangeParam;
  struct ProcessRemoteChangeParam;
  typedef base::Callback<
      void(SyncStatusCode status,
           const std::string& resource_id)> ResourceIdCallback;
  explicit DriveFileSyncService(Profile* profile);
  void Initialize(scoped_ptr<drive_backend::SyncTaskManager> task_manager,
                  const SyncStatusCallback& callback);
  void InitializeForTesting(
      scoped_ptr<drive_backend::SyncTaskManager> task_manager,
      const base::FilePath& base_dir,
      scoped_ptr<drive_backend::APIUtilInterface> sync_client,
      scoped_ptr<DriveMetadataStore> metadata_store,
      const SyncStatusCallback& callback);
  void DidInitializeMetadataStore(const SyncStatusCallback& callback,
                                  SyncStatusCode status,
                                  bool created);
  void UpdateServiceStateFromLastOperationStatus(
      SyncStatusCode sync_status,
      google_apis::GDataErrorCode gdata_error);
  
  
  void UpdateServiceState(RemoteServiceState state,
                          const std::string& description);
  void DoRegisterOrigin(
      const GURL& origin,
      const SyncStatusCallback& callback);
  void DoEnableOrigin(
      const GURL& origin,
      const SyncStatusCallback& callback);
  void DoDisableOrigin(
      const GURL& origin,
      const SyncStatusCallback& callback);
  void DoUninstallOrigin(
      const GURL& origin,
      UninstallFlag flag,
      const SyncStatusCallback& callback);
  void DoProcessRemoteChange(
      const SyncFileCallback& sync_callback,
      const SyncStatusCallback& completion_callback);
  void DoApplyLocalChange(
      const FileChange& change,
      const base::FilePath& local_file_path,
      const SyncFileMetadata& local_file_metadata,
      const fileapi::FileSystemURL& url,
      const SyncStatusCallback& callback);
  void DoGetRemoteVersions(
      const fileapi::FileSystemURL& url,
      const RemoteVersionsCallback& callback,
      const SyncStatusCallback& completion_callback);
  void DidGetEntryForRemoteVersions(
      const RemoteVersionsCallback& callback,
      google_apis::GDataErrorCode error,
      scoped_ptr<google_apis::ResourceEntry> entry);
  void DoDownloadRemoteVersion(
      const fileapi::FileSystemURL& url,
      const std::string& version_id,
      const DownloadVersionCallback& callback,
      const SyncStatusCallback& completion_callback);
  void DidDownloadVersion(
      const DownloadVersionCallback& download_callback,
      google_apis::GDataErrorCode error,
      const std::string& file_md5,
      int64 file_size,
      const base::Time& last_updated,
      webkit_blob::ScopedFile downloaded);
  void UpdateRegisteredOrigins();
  void StartBatchSync(const SyncStatusCallback& callback);
  void DidGetDriveDirectoryForOrigin(const GURL& origin,
                                     const SyncStatusCallback& callback,
                                     SyncStatusCode status,
                                     const std::string& resource_id);
  void DidUninstallOrigin(const GURL& origin,
                          const SyncStatusCallback& callback,
                          google_apis::GDataErrorCode error);
  void DidGetLargestChangeStampForBatchSync(
      const SyncStatusCallback& callback,
      const GURL& origin,
      const std::string& resource_id,
      google_apis::GDataErrorCode error,
      int64 largest_changestamp);
  void DidGetDirectoryContentForBatchSync(
      const SyncStatusCallback& callback,
      const GURL& origin,
      const std::string& resource_id,
      int64 largest_changestamp,
      google_apis::GDataErrorCode error,
      scoped_ptr<google_apis::ResourceList> feed);
  void DidProcessRemoteChange(const SyncFileCallback& sync_callback,
                              const SyncStatusCallback& completion_callback,
                              SyncStatusCode status);
  void DidApplyLocalChange(const SyncStatusCallback& callback,
                           SyncStatusCode status);
  
  bool AppendRemoteChange(
      const GURL& origin,
      const google_apis::ResourceEntry& entry,
      int64 changestamp);
  bool AppendFetchChange(
      const GURL& origin,
      const base::FilePath& path,
      const std::string& resource_id,
      SyncFileType file_type);
  bool AppendRemoteChangeInternal(
      const GURL& origin,
      const base::FilePath& path,
      bool is_deleted,
      const std::string& resource_id,
      int64 changestamp,
      const std::string& remote_file_md5,
      const base::Time& updated_time,
      SyncFileType file_type);
  void RemoveRemoteChange(const fileapi::FileSystemURL& url);
  
  void MarkConflict(
      const fileapi::FileSystemURL& url,
      DriveMetadata* drive_metadata,
      const SyncStatusCallback& callback);
  void NotifyConflict(
      const fileapi::FileSystemURL& url,
      const SyncStatusCallback& callback,
      SyncStatusCode status);
  
  
  SyncStatusCode GDataErrorCodeToSyncStatusCodeWrapper(
      google_apis::GDataErrorCode error);
  base::FilePath temporary_file_dir_;
  
  
  
  
  
  
  void MaybeStartFetchChanges();
  void FetchChangesForIncrementalSync(const SyncStatusCallback& callback);
  void DidFetchChangesForIncrementalSync(
      const SyncStatusCallback& callback,
      bool has_new_changes,
      google_apis::GDataErrorCode error,
      scoped_ptr<google_apis::ResourceList> changes);
  bool GetOriginForEntry(const google_apis::ResourceEntry& entry, GURL* origin);
  void NotifyObserversFileStatusChanged(const fileapi::FileSystemURL& url,
                                        SyncFileStatus sync_status,
                                        SyncAction action_taken,
                                        SyncDirection direction);
  void EnsureSyncRootDirectory(const ResourceIdCallback& callback);
  void DidEnsureSyncRoot(const ResourceIdCallback& callback,
                         google_apis::GDataErrorCode error,
                         const std::string& sync_root_resource_id);
  void EnsureOriginRootDirectory(const GURL& origin,
                                 const ResourceIdCallback& callback);
  void DidEnsureSyncRootForOriginRoot(const GURL& origin,
                                      const ResourceIdCallback& callback,
                                      SyncStatusCode status,
                                      const std::string& sync_root_resource_id);
  void DidEnsureOriginRoot(const GURL& origin,
                           const ResourceIdCallback& callback,
                           google_apis::GDataErrorCode error,
                           const std::string& resource_id);
  
  
  
  
  std::string sync_root_resource_id();
  scoped_ptr<DriveMetadataStore> metadata_store_;
  scoped_ptr<drive_backend::APIUtilInterface> api_util_;
  Profile* profile_;
  scoped_ptr<drive_backend::SyncTaskManager> task_manager_;
  scoped_ptr<drive_backend::LocalSyncDelegate> running_local_sync_task_;
  scoped_ptr<drive_backend::RemoteSyncDelegate> running_remote_sync_task_;
  
  
  
  
  RemoteServiceState state_;
  
  
  
  bool sync_enabled_;
  int64 largest_fetched_changestamp_;
  std::map<GURL, std::string> pending_batch_sync_origins_;
  
  
  
  
  
  
  
  
  
  
  
  bool may_have_unfetched_changes_;
  ObserverList<Observer> service_observers_;
  ObserverList<FileStatusObserver> file_status_observers_;
  RemoteChangeHandler remote_change_handler_;
  RemoteChangeProcessor* remote_change_processor_;
  google_apis::GDataErrorCode last_gdata_error_;
  ConflictResolutionResolver conflict_resolution_resolver_;
  OriginOperationQueue pending_origin_operations_;
  DISALLOW_COPY_AND_ASSIGN(DriveFileSyncService);
};
}  
#endif