import java.util.Iterator;
import java.io.File;

/** Contains static methods to represent part of the file system as a tree. */

class FileWalker {
  
  /** Return the files under f as a Tree, rooted at f.
    * Precondition: f != null, the files under f form a tree
    * (no shortcuts/links/etc) and are accessible without security
    * nor other IO problems.
    * @param f  the root of the subtree in the filesystem to represent.
    * @throws  IllegalArgumentException if f is null. */
  public static Tree<File> fileTree(File f) {
    if (f == null) throw new IllegalArgumentException();
    
    Tree<File> result = new Tree<File>();
    result.setRootData(f);
    if (f.isDirectory()) {
      File[] childFiles = f.listFiles();
      for (int i = 0; i < childFiles.length; ++i) {
        result.addChildTree(fileTree(childFiles[i]));
      }
    }
    return result;
  }
  
  /** Return a version of t with non-directory file sizes recorded and
    * accumulated in directory sizes.
    * Precondition: t != null, t represents a subtree of the filesystem
    * (e.g. as returned by FileWalker) and the files in t are accessible
    * without security or other IO problems.
    * @param t  a tree representing a subtree of the filesystem.
    * @throws  IllegalArgumentException if t is null. */
  public static Tree<MeasuredData<File>> measure(Tree<File> t) {
    if (t == null) throw new IllegalArgumentException();
    
    long size = 0;
    File f = t.getRootData();
    Tree<MeasuredData<File>> result = new Tree<MeasuredData<File>>();
    if (f.isDirectory()) {
      Iterator<Tree<File>> children = t.childTreeIterator();
      while (children.hasNext()) {
        Tree<MeasuredData<File>> childResult = measure(children.next());
        size += childResult.getRootData().getSize();
        result.addChildTree(childResult);
      }
    } else {
      size = f.length();
    }
    result.setRootData(new MeasuredData<File>(f, size));
    return result;
  }
  
}

