/*
 * Directory module
 *
 * This module provides an abstraction around the disk representation
 * of directories.
 */

#ifndef FSDIR_H
#define FSDIR_H

#include "persifs.h"
#include "fsfile.h"
#include <itree.h>



/*
 * Directory entry
 */
class fsdirEntry
{
public:
  /**
   * Get the name of this entry.
   */
  str getName() { return my_name; }
  /**
   * Get the inumber of this entry.
   */
  inumber getInumber();
protected:
  fsdirEntry(str name, inumber num): my_name(name), my_num(num) {}
  fsdirEntry();

private:
  friend class fsdir;
  str my_name;
  inumber my_num;
  itree_entry<fsdirEntry> tlink;
};

//typedef itree<str, fsdirEntry, &fsdirEntry::name, &fsdirEntry::tlink> entries_tree;


class fsdir
{
   typedef itree<str, fsdirEntry, &fsdirEntry::my_name, 
                 &fsdirEntry::tlink> entries_tree;
public:
  /**
   * Create a new directory containing only . and .. entries.  This is
   * a factory function.
   */
  static void create(ref<fsdir> parent, fattr3 fa,
                     callback<void, ref<fsdir> >::ref cb, cbe error);

  /**
   * Load an existing directory from a file.  This is a factory
   * function.
   */
  static void load(ref<fsfile> file,
                   callback<void, ref<fsdir> >::ref cb, cbe error);

  /**
   * Lookup an entry in this directory.
   */
  void lookup(str name, callback<void, fsdirEntry* >::ref cb, cbe error);


  /**
   * Add an entry to this directory.  It is an error if an entry with
   * this name already exists.
   */
  void add(str name, inumber num,
           callback<void>::ref cb, cbe error);


  /**
   * Add an entry to this directory.  This is a convenience overload
   * for the above add method.
   */
   void add(str name, ref<fsfile> file,
           callback<void>::ref cb, cbe error);



  /**
   * Remove an entry from this directory.  
   */
  void remove(str name, callback<void>::ref cb, cbe error);


protected:
  fsdir(ref<fsfile> file,  inumber parent);
  ~fsdir(); 
private:
  ref<fsfile> my_file;
  inumber my_parent; 
  ptr<entries_tree> entries;

  fsdirEntry dot, dotdot;
  const static str sdot, sdotdot;
  
  friend class fsdirEntry;

  void remove_cb1(callback<void>::ref cb, cbe error, fsdirEntry *e);
  static void create_cb1(callback<void, ref<fsdir> >::ref cb, cbe error, ref<fsfile> file);

};

#endif // FSDIR_H

