package nxm.sys.lib;

import java.io.File;
import java.io.FilenameFilter;

/** Encapsulation of a directory traversal algorithm. Each instance of this
    class is associated with a FilenameFilter object. In the execute method
    the instance will apply the filter to every file in that directory,
    traversing into subdirectories when necessary. For each file that the
    filter accepts (FilenameFilter.accept returns true), the visit method,
    with the full path to the file will be called.
*/
public abstract class FileVisitor {

  /** The filter being applied. */
  private FilenameFilter filter;

  /** Ignore these directories. */
  private String ignore = "CVS";

  /**  Construct a new instance that uses the given filename filter.
   *  @param ff filename filter */
  public FileVisitor(FilenameFilter ff) {
    filter = ff;
  }

  /** Executes the directory traversal algorithm on the given path.
   *  @param name path */
  public void execute(String name) {
    File fd = new File(name);
    execute (fd);
  }

  /** Tells the instance to ignore files or directories with this name.
   *  @param newIgnore name of files or directories to ignore
   */
  public void addIgnore (String newIgnore) {
    if ( ignore.indexOf(newIgnore) == -1 ) ignore = ignore + "|" + newIgnore;
  }

  /** Return true if the given filename does not point to an invalid NeXtMidas
      option tree. If the name of the file is "NXM" (ignoring case) and the
      granparent directory (two levels up) is also "NXM" then this will return
      false.
      @param file file name
      @return true if the given filename does not point to an invalid NeXtMidas option tree
    */
  public boolean isValidArea (File file) {
    if ( file.isFile() ) return true;

    FileName fname = new FileName ( file.getAbsolutePath() );
    String[] elems = fname.getPathElements();
    if ( elems.length > 2 ) {
      String name = elems[elems.length - 1].toUpperCase();
      String gparentName = elems[elems.length - 3].toUpperCase();
      if ( name.equals("NXM") && gparentName.equals("NXM") ) return false;
    }
    return true;
  }

  /** Executes the directory traversal algorithm on the given path. If the
      file descriptor is a file then the visit method will be invoked if the
      filter accepts the file.If the file descriptor is a directory then the
      method will walk through the tree rooted at that directory in a depth
      first traversal.
      @param fd file descriptor
  */
  public void execute (File fd) {
    if (fd==null || !fd.exists()) return;
    if (ignore.indexOf(fd.getName()) >= 0) return;

    if ( fd.isDirectory() ) {
      if ( isValidArea(fd) ) {
        String[] contents = fd.list(filter);
        for (int i=0; i<contents.length; i++) {
          execute( new File(fd, contents[i]) );
        }
      }
      else {
        //System.out.println ("Skipping " + fd );
      }
    }
    else if ( filter.accept (fd.getParentFile(), fd.getName()) ) {
      visit(fd.getAbsolutePath());
    }
  }

  /** Invoked by the execute method for files that pass the filter.
   *  @param name name of file
   */
  public abstract void visit(String name);
}
