/home/gshute/netbeans/Toolkit/src/vfs/VFSDirectory.java
package vfs;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

/**
 * A VFSDirectory is a container for VFSItem objects
 * in a virtual file system.
 * In addition to VFSItem methods, it has methods
 * for accessing files and subdirectories.
 * <p>
 * This is a Composite class in a Composite
 * design pattern whose other classes are
 * VFSItem (Component) and VFSFile (Leaf).
 * </p>
 * 
 * @author gshute
 */
public class VFSDirectory
implements VFSItem {

  private String name;
  private URL url;
  private Map<String, VFSFile> files;
  private Map<String, VFSDirectory> subdirectories;

  /**
   * d.addSubdirectory(nm) adds the subdirectory named nm
   * to d.
   */
  protected void addSubdirectory(VFSDirectory dir) {
    subdirectories.put(dir.getName(), dir);
  }

  /**
   * addFile(nm) adds the file named nm to this
   * VFSDirectory.
   */
  protected VFSFile addFile(String nm) {
    int slashPosition = nm.indexOf("/");
    if (slashPosition < 0) {
      VFSFile file = new VFSFile(nm, this);
      files.put(nm, file);
      return file;
    }
    if (slashPosition == nm.length() - 1) {
      throw new IllegalArgumentException(
              "Illegal file name: " + nm);
    }
    String childName = nm.substring(0, slashPosition);
    VFSDirectory child = subdirectories.get(childName + "/");
    return child.addFile(nm.substring(slashPosition + 1));
  }

  /**
   * new VFSDirectory(url) returns a virtual file system
   * root directory representing the directory whose URL
   * is url.
   * 
   * @param url the URL of the root directory
   */
  public VFSDirectory(URL url) {
    name = "/";
    this.url = url;
    files = new TreeMap<String, VFSFile>();
    subdirectories = new TreeMap<String, VFSDirectory>();
  }

  /**
   * new VFSDirectory(nm, par) returns a virtual directory
   * named nm whose parent is par.
   * 
   * @param nm the name of the directory
   * @param par its virtual file system parent
   */
  public VFSDirectory(String nm, VFSDirectory par) {
    name = nm;
    if (par != null) {
      try {
        url = new URL(par.getURL(), nm);
      } catch (MalformedURLException ex) {
        throw new VFSError("Bad name: " + nm, ex);
      }
    }
    files = new TreeMap<String, VFSFile>();
    subdirectories = new TreeMap<String, VFSDirectory>();
  }

  /**
   * d.getName() returns the name of d.
   */
  public String getName() {
    return name;
  }

  /**
   * v.getURL() returns the URL for d.
   * 
   * @return the URL for the directory
   */
  public URL getURL() {
    return url;
  }

  public boolean isRoot() {
    return getName().equals("/");
  }

  /**
   * d.getFile(nm) returns the file named nm in d
   * or null if there is no such file.
   * 
   * @return the named file
   */
  public VFSFile getFile(String nm) {
    return files.get(nm);
  }

  /**
   * d.getFiles() returns an iterator for the files
   * in d.
   * 
   * @return an iterator for the files
   */
  public Iterator<VFSFile> getFiles() {
    return files.values().iterator();
  }

  /**
   * d.getFileNames() returns an iterator for the
   * names of file in d.
   * 
   * @return an iterator for the file names
   */
  public Iterator<String> getFileNames() {
    return files.keySet().iterator();
  }

  /**
   * d.getFile(nm) returns the subdirectory named nm
   * in d or null if there is no such subdirectory.
   * 
   * @return the named directory
   */
  public VFSDirectory getSubdirectory(String nm) {
    return subdirectories.get(nm);
  }

  /**
   * d.getSubdirectories() returns an iterator for
   * the subdirectories of d.
   * 
   * @return an iterator for the subdirectories
   */
  public Iterator<VFSDirectory> getSubdirectories() {
    return subdirectories.values().iterator();
  }

  /**
   * d.getSubdirectoryNames() returns an iterator for
   * the names of subdirectories of d.
   * 
   * @return an iterator for the subdirectory names
   */
  public Iterator<String> getSubdirectoryNames() {
    return subdirectories.keySet().iterator();
  }

  public void escort(VFSVisitor v) {
    v.enter(this);
    for (VFSDirectory d : subdirectories.values()) {
      d.escort(v);
    }
    for (VFSFile f : files.values()) {
      v.visit(f);
    }
    v.leave(this);
  }

}  // public class VFSDirectory