/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

include protocol PFileSystemAccessHandle;
include protocol PFileSystemAccessHandleControl;
include protocol PFileSystemWritableFileStream;

include IPCBlob;
include RandomAccessStreamParams;

using mozilla::dom::fs::ContentType from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::EntryId from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::Name from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::Origin from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::PageNumber from "mozilla/dom/FileSystemTypes.h";
using mozilla::dom::fs::TimeStamp from "mozilla/dom/FileSystemTypes.h";
using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";

namespace mozilla {
namespace dom {
namespace fs {

/**
 * Identifies a file or a directory and contains its user provided name.
 */
struct FileSystemEntryMetadata
{
  EntryId entryId;
  Name entryName;
  bool directory;
};

/**
 * Identifies a file or a directory with its parent identifier and
 * user provided name.
 */
struct FileSystemChildMetadata
{
  EntryId parentId;
  Name childName;
};

/**
 * Identifies a file with its parent directory and name, and
 * indicates whether the file may be created if it is missing.
 */
struct FileSystemGetHandleRequest
{
  FileSystemChildMetadata handle;
  bool create;
};

/**
 * Contains a file or directory or an error.
 */
union FileSystemGetHandleResponse
{
  nsresult;
  EntryId;
};

/**
 * Contains an identifier for a parent directory and a page number
 * which is used to fetch the next set of entries when the directory
 * contains so many items that communicating all of them in one message
 * is an impractical.
 */
struct FileSystemGetEntriesRequest
{
  EntryId parentId;
  PageNumber page;
};

/**
 * Contains a set of directories and files
 * under the same parent directory.
 */
struct FileSystemDirectoryListing
{
  FileSystemEntryMetadata[] directories;
  FileSystemEntryMetadata[] files;
};

/**
 * Contains a set of entries or an error.
 */
union FileSystemGetEntriesResponse
{
  nsresult;
  FileSystemDirectoryListing;
};

/**
 * Contains entry handle information.
 */
struct FileSystemGetFileRequest
{
  EntryId entryId;
};

/**
 * Contains the properties of a file and a file descriptor.
 * The properties may differ from the properties of the
 * underlying object of the file descriptor.
 */
struct FileSystemFileProperties
{
  TimeStamp last_modified_ms;
  IPCBlob file;
  ContentType type;
  Name[] path;
};

/**
 * Contains file properties or an error.
 */
union FileSystemGetFileResponse
{
  nsresult;
  FileSystemFileProperties;
};

/**
 * Contains entry handle information.
 */
struct FileSystemGetAccessHandleRequest
{
  EntryId entryId;
};

struct FileSystemAccessHandleProperties
{
  RandomAccessStreamParams streamParams;
  ManagedEndpoint<PFileSystemAccessHandleChild> accessHandleChildEndpoint;
  Endpoint<PFileSystemAccessHandleControlChild> accessHandleControlChildEndpoint;
};

union FileSystemGetAccessHandleResponse
{
  nsresult;
  FileSystemAccessHandleProperties;
};

/**
 * Contains entry handle information.
 */
struct FileSystemGetWritableRequest
{
  EntryId entryId;
  bool keepData;
};

struct FileSystemWritableFileStreamProperties
{
  RandomAccessStreamParams streamParams;
  PFileSystemWritableFileStream writableFileStream;
};

union FileSystemGetWritableFileStreamResponse
{
  nsresult;
  FileSystemWritableFileStreamProperties;
};

/**
 * Represents a pair of file system entries which
 * are not necessarily connected by a path.
 */
struct FileSystemEntryPair
{
  EntryId parentId;
  EntryId childId;
};

/**
 * Contains a pair of file system entries.
 */
struct FileSystemResolveRequest
{
  FileSystemEntryPair endpoints;
};

/**
 * Contains a file system path.
 */
struct FileSystemPath
{
  Name[] path;
};

/**
 * Contains a potentially empty path or an error.
 */
union FileSystemResolveResponse
{
  nsresult;
  FileSystemPath?;
};

/**
 * Identifies a file with its parent directory and name, and
 * indicates whether all the children of a directory may be removed.
 */
struct FileSystemRemoveEntryRequest
{
  FileSystemChildMetadata handle;
  bool recursive;
};

/**
 * Contains an error or nothing.
 */
union FileSystemRemoveEntryResponse
{
  nsresult;
  void_t;
};

/**
 * Identifies a file/directory to be moved and the new name, and the
 * destination directory
 */
struct FileSystemMoveEntryRequest
{
  FileSystemEntryMetadata handle;
  FileSystemChildMetadata destHandle;
};

/**
 * Identifies a file/directory to be renamed and the new name
 */
struct FileSystemRenameEntryRequest
{
  FileSystemEntryMetadata handle;
  Name name;
};

/**
 * Contains an error or the new entryId
 */
union FileSystemMoveEntryResponse
{
  nsresult;
  void_t;
};

}  // namespace fs

async protocol PFileSystemManager
{
  manages PFileSystemAccessHandle;
  manages PFileSystemWritableFileStream;

 parent:
  /**
   * TODO: documentation
   */
  [VirtualSendImpl]
  async GetRootHandle()
      returns(FileSystemGetHandleResponse response);

  /**
   * Initiates an asynchronous request for the handle of
   * a subdirectory with a given name under the current directory.
   *
   * Invalid names are rejected with an appropriate error.
   *
   * If the subdirectory exists, a handle to it is always returned.
   *
   * If no child of any kind with the given name exists and
   * the create-flag of the input is set, the subdirectory will be created,
   * otherwise an appropriate error is returned.
   *
   * @param[in] handle request containing a create flag
   *
   * @returns error or entry handle
   */
  [VirtualSendImpl]
  async GetDirectoryHandle(FileSystemGetHandleRequest request)
      returns(FileSystemGetHandleResponse handle);

  /**
   * Initiates an asynchronous request for the handle to
   * a file with a given name under the current directory.
   *
   * Invalid names are rejected with an appropriate error.
   *
   * If the file exists, a handle to it is always returned.
   *
   * If no child of any kind with the given name exists and
   * the create-flag of the input is set, the file will be created,
   * otherwise an appropriate error is returned.
   *
   * @param[in] handle request containing a create flag
   *
   * @returns error or entry handle
   */
  [VirtualSendImpl]
  async GetFileHandle(FileSystemGetHandleRequest request)
      returns(FileSystemGetHandleResponse handle);

  /**
   * Initiates an asynchronous request for a read-only object representing the
   * file corresponding to the current file handle.
   *
   * The returned object provides read-only access.
   *
   * If the underlying file object is modified through a mutable interface,
   * the returned value is considered stale. Concurrent changes are not
   * guaranteed to be visible or invisible. Using a stale object
   * returns appropriate errors when the results are unpredictable.
   *
   * @param[in] request for a file object
   *
   * @returns error or file object
   */
  [VirtualSendImpl]
  async GetFile(FileSystemGetFileRequest request)
      returns(FileSystemGetFileResponse response);

  /**
   * TODO: documentation
   */
  [VirtualSendImpl]
  async GetAccessHandle(FileSystemGetAccessHandleRequest request)
      returns(FileSystemGetAccessHandleResponse response);

  /**
   * TODO: documentation
   */
  [VirtualSendImpl]
  async GetWritable(FileSystemGetWritableRequest request)
      returns(FileSystemGetWritableFileStreamResponse fileData);

  /**
   * Initiates an asynchronous request for the file system path
   * associated with a file system entry.
   *
   * @param[in] request identifying a file object
   *
   * @returns error or file system path
   */
  [VirtualSendImpl]
  async Resolve(FileSystemResolveRequest request)
      returns(FileSystemResolveResponse response);

  /**
   * Initiates an asynchronous request for an iterator to the child entries
   * under the calling directory handle.
   *
   * If the directory item names or the directory structure is modified while
   * the iterator is in use, the iterator remains safe to use but no guarantees
   * are made regarding the visibility of the concurrent changes.
   * It is possible that a file which is added after the iteration has begun
   * will not be returned, or that among the values there are invalid file
   * handles whose underlying objects have been removed after the iteration
   * started.
   *
   * @param[in] request for a iterator
   *
   * @returns error or iterator
   */
  [VirtualSendImpl]
  async GetEntries(FileSystemGetEntriesRequest request)
      returns(FileSystemGetEntriesResponse entries);

  /**
   * Initiates an asynchronous request to delete a directory or file with a
   * given name under the calling directory handle.
   *
   * If recursive flag of the request is not set, a request to remove a
   * non-empty directory returns an appropriate error, otherwise all the child
   * files and directories are made to vanish.
   *
   * The recursive flag has no impact on files.
   *
   * @param[in] request containing a recursive flag
   *
   * @returns error information
   */
  [VirtualSendImpl]
  async RemoveEntry(FileSystemRemoveEntryRequest request)
      returns(FileSystemRemoveEntryResponse response);

  /**
   * Initiates an asynchronous request to move a directory or file with a
   * given name to a given destination and new name.
   *
   * @returns error information
   */
  async MoveEntry(FileSystemMoveEntryRequest request)
      returns(FileSystemMoveEntryResponse response);

  /**
   * Initiates an asynchronous request to rename a directory or file
   *
   * @returns error information
   */
  async RenameEntry(FileSystemRenameEntryRequest request)
      returns(FileSystemMoveEntryResponse response);

 child:
  async PFileSystemWritableFileStream();

  async CloseAll()
      returns(nsresult rv);
};

} // namespace dom
} // namespace mozilla