// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Use the <code>chrome.fileSystem</code> API to create, read, navigate,
// and write to the user's local file system. With this API, Chrome Apps can
// read and write to a user-selected location. For example, a text editor app
// can use the API to read and write local documents. All failures are notified
// via chrome.runtime.lastError.
namespace fileSystem {
  dictionary AcceptOption {
    // This is the optional text description for this option. If not present,
    // a description will be automatically generated; typically containing an
    // expanded list of valid extensions (e.g. "text/html" may expand to
    // "*.html, *.htm").
    DOMString? description;

    // Mime-types to accept, e.g. "image/jpeg" or "audio/*". One of mimeTypes or
    // extensions must contain at least one valid element.
    DOMString[]? mimeTypes;

    // Extensions to accept, e.g. "jpg", "gif", "crx".
    DOMString[]? extensions;
  };

  enum ChooseEntryType {

    // Prompts the user to open an existing file and returns a FileEntry on
    // success. From Chrome 31 onwards, the FileEntry will be writable if the
    // application has the 'write' permission under 'fileSystem'; otherwise, the
    // FileEntry will be read-only.
    openFile,

    // Prompts the user to open an existing file and returns a writable
    // FileEntry on success. Calls using this type will fail with a runtime
    // error if the application doesn't have the 'write' permission under
    // 'fileSystem'.
    openWritableFile,

    // Prompts the user to open an existing file or a new file and returns a
    // writable FileEntry on success. Calls using this type will fail with a
    // runtime error if the application doesn't have the 'write' permission
    // under 'fileSystem'.
    saveFile,

    // Prompts the user to open a directory and returns a DirectoryEntry on
    // success. Calls using this type will fail with a runtime error if the
    // application doesn't have the 'directory' permission under 'fileSystem'.
    // If the application has the 'write' permission under 'fileSystem', the
    // returned DirectoryEntry will be writable; otherwise it will be read-only.
    // New in Chrome 31.
    openDirectory
  };

  // Type of a change happened to a child entry within a tracked directory.
  enum ChildChangeType {
    created,
    removed,
    changed
  };

  dictionary ChooseEntryOptions {
    // Type of the prompt to show. The default is 'openFile'.
    ChooseEntryType? type;

    // The suggested file name that will be presented to the user as the
    // default name to read or write. This is optional.
    DOMString? suggestedName;

    // The optional list of accept options for this file opener. Each option
    // will be presented as a unique group to the end-user.
    AcceptOption[]? accepts;

    // Whether to accept all file types, in addition to the options specified
    // in the accepts argument. The default is true. If the accepts field is
    // unset or contains no valid entries, this will always be reset to true.
    boolean? acceptsAllTypes;

    // Whether to accept multiple files. This is only supported for openFile and
    // openWritableFile. The callback to chooseEntry will be called with a list
    // of entries if this is set to true. Otherwise it will be called with a
    // single Entry.
    boolean? acceptsMultiple;
  };

  dictionary RequestFileSystemOptions {
    // The ID of the requested volume.
    DOMString volumeId;

    // Whether the requested file system should be writeable, or read-only.
    // By default read-only.
    boolean? writable;
  };

  // Represents a mounted volume, which can be accessed via <code>chrome.
  // fileSystem.requestFileSystem</code>.
  dictionary Volume {
    DOMString volumeId;
    boolean writable;
  };

  // Change to an entry within a tracked directory.
  [nodoc] dictionary ChildChange {
    [instanceOf=Entry] object entry;
    ChildChangeType type;
  };

  // Event notifying about an inserted or a removed volume from the system.
  dictionary VolumeListChangedEvent {
    Volume[] volumes;
  };

  // Event notifying about a change in a file or a directory, including its
  // contents.
  [nodoc] dictionary EntryChangedEvent {
    // Tracked entry.
    [instanceOf=Entry] object target;

    // List of changed entries within the tracked directory in order they
    // happened. May not be available for some types of file systems.
    ChildChange[]? childChanges;
  };

  // Event notifying about a tracked file or a directory being removed.
  [nodoc] dictionary EntryRemovedEvent {
    [instanceOf=Entry] object target;
  };

  callback GetDisplayPathCallback = void (DOMString displayPath);
  callback EntryCallback = void ([instanceOf=Entry] object entry);
  callback EntriesCallback = void (
      [instanceOf=Entry] optional object entry,
      [instanceOf=FileEntry] optional object[] fileEntries);
  callback IsWritableCallback = void (boolean isWritable);
  callback IsRestorableCallback = void (boolean isRestorable);
  [nodoc] callback GetObservedEntriesCallback = void (
      [instanceOf=Entry] object[] entries);
  callback RequestFileSystemCallback = void(
      [instanceOf=FileSystem] optional object fileSystem);
  callback GetVolumeListCallback = void(optional Volume[] volumes);

  interface Functions {
    // Get the display path of an Entry object. The display path is based on
    // the full path of the file or directory on the local file system, but may
    // be made more readable for display purposes.
    static void getDisplayPath([instanceOf=Entry] object entry,
                               GetDisplayPathCallback callback);

    // Get a writable Entry from another Entry. This call will fail with a
    // runtime error if the application does not have the 'write' permission
    // under 'fileSystem'. If entry is a DirectoryEntry, this call will fail if
    // the application does not have the 'directory' permission under
    // 'fileSystem'.
    static void getWritableEntry([instanceOf=Entry] object entry,
                                 EntryCallback callback);

    // Gets whether this Entry is writable or not.
    static void isWritableEntry([instanceOf=Entry] object entry,
                                IsWritableCallback callback);

    // Ask the user to choose a file or directory.
    static void chooseEntry(optional ChooseEntryOptions options,
                            EntriesCallback callback);

    // Returns the file entry with the given id if it can be restored. This call
    // will fail with a runtime error otherwise.
    static void restoreEntry(DOMString id, EntryCallback callback);

    // Returns whether the app has permission to restore the entry with the
    // given id.
    static void isRestorable(DOMString id, IsRestorableCallback callback);

    // Returns an id that can be passed to restoreEntry to regain access to a
    // given file entry. Only the 500 most recently used entries are retained,
    // where calls to retainEntry and restoreEntry count as use. If the app has
    // the 'retainEntries' permission under 'fileSystem', entries are retained
    // indefinitely. Otherwise, entries are retained only while the app is
    // running and across restarts.
    static DOMString retainEntry([instanceOf=Entry] object entry);

    // Requests access to a file system for a volume represented by <code>
    // options.volumeId</code>. If <code>options.writable</code> is set to true,
    // then the file system will be writable. Otherwise, it will be read-only.
    // The <code>writable</code> option requires the <code>
    // "fileSystem": {"write"}</code> permission in the manifest. Available to
    // kiosk apps running in kiosk session only. For manual-launch kiosk mode, a
    // confirmation dialog will be shown on top of the active app window.
    // In case of an error, <code>fileSystem</code> will be undefined, and
    // <code>chrome.runtime.lastError</code> will be set.
    static void requestFileSystem(RequestFileSystemOptions options,
                                  RequestFileSystemCallback callback);

    // Returns a list of volumes available for <code>requestFileSystem()</code>.
    // The <code>"fileSystem": {"requestFileSystem"}</code> manifest permission
    // is required. Available to kiosk apps running in the kiosk session only.
    // In case of an error, <code>volumes</code> will be undefined, and <code>
    // chrome.runtime.lastError</code> will be set.
    static void getVolumeList(GetVolumeListCallback callback);

    // Observes a directory entry. Emits an event if the tracked directory is
    // changed (including the list of files on it), or removed. If <code>
    // recursive</code> is set to true, then also all accessible subdirectories
    // will be tracked. Observers are automatically removed once the extension
    // is closed or suspended, unless <code>entry</code> is retained using
    // <code>chrome.fileSystem.retainEntry</code>.
    //
    // In such case of retained entries, the observer stays active across
    // restarts until <code>unobserveEntry</code> is explicitly called. Note,
    // that once the <code>entry</code> is not retained anymore, the observer
    // will be removed automatically. Observed entries are also automatically
    // restored when either <code>getObservers</code> is called, or an observing
    // event for it is invoked.
    [nodoc] static void observeDirectory(
        [instanceOf=DirectoryEntry] object entry,
        optional boolean recursive);

    // Unobserves a previously observed either a file or a directory.
    [nodoc] static void unobserveEntry([instanceOf=Entry] object entry);

    // Lists all observed entries.
    [nodoc] static void getObservedEntries(GetObservedEntriesCallback callback);
  };

  interface Events {
    // Called when a list of available volumes is changed.
    static void onVolumeListChanged(VolumeListChangedEvent event);

    // Called when an observed entry is changed.
    [nodoc] static void onEntryChanged(EntryChangedEvent event);

    // Called when an observed entry is removed.
    [nodoc] static void onEntryRemoved(EntryRemovedEvent event);
  };
};
