/*
 * Filesystem object
 *
 * This provides a simple object meant for carrying around the
 * coherent state of the file system.  A file system is defined by a
 * couple of objects (a superblob, a blob index, and an inode log).
 * This bundles them together for ease of use.
 */

#ifndef FS_H
#define FS_H

#include "persifs.h"
#include "diskblobindex.h"
#include "disksuperblob.h"
#include "logginginodelog.h"
#include "lockmanager.h"
#include "writegrouper.h"

// Deal with the infuriating SFS wrap argument limit.
struct fsCreateArgs
{
  str filebase;
  bool arborescent;
  int writeGrouping;
  unsigned long imapCacheSize;
};


class fsdir;

class FS
{
public:
  /**
   * Load an entire file system.  filebase is used as the base name
   * from which the file names for the various structures are derived.
   * If the files don't already exist, this creates a new, empty file
   * system.  Otherwise, this loads the file system from those files.
   * This is a factory function.
   */
  static void create(fsCreateArgs args,
                     callback<void, ref<FS> >::ref cb, cbe error);

  // The superblob of this file system
  ref<superblob> blob;
  // The inode log of this file system
  ref<inodeLog> log;
  // The file system's lock manager
  ref<lockManager> lockMgr;
  // And its write grouper
  ref<writeGrouper> grouper;

  /**
   * Retrieve the inumber of the root directory.
   */
  inumber getRootInumber();

protected:
  FS(ref<superblob> blob, ref<inodeLog> log, int writeGrouping);

private:
  inumber rootInumber;

  static void create_afterBlobIndex(fsCreateArgs args,
                                    callback<void, ref<FS> >::ref cb, cbe error,
                                    ref<diskBlobIndex> bi);
  static void create_afterSuperblob(fsCreateArgs args,
                                    callback<void, ref<FS> >::ref cb, cbe error,
                                    ref<diskSuperblob> blob);
  static void create_afterInodeLog(fsCreateArgs args, ref<diskSuperblob> blob,
                                   callback<void, ref<FS> >::ref cb, cbe error,
                                   ref<inodeLog> log);
  static void create_afterGetRoot(ref<FS> fs,
                                  callback<void, ref<FS> >::ref cb, cbe error,
                                  inumber rootNum);
  static void create_afterCreateRoot(ref<FS> fs,
                                     callback<void, ref<FS> >::ref cb, cbe error,
                                     ref<fsdir> rootDir);
  static void create_afterSetRoot(ref<FS> fs,
                                  callback<void, ref<FS> >::ref cb, cbe error);

  void setRootInumber(inumber num);
};

#endif // FS_H
