package pregozip;

import java.io.*;
import java.util.*;

/**
 * <p>Class Directory</p>
 * <p>Copyright: Copyright (c) 2002</p>
 * @author Markus Wilthaner - contact@wilth.net
 * @version 1.0
 * <p>Opens a directory and puts all files in a Vector.
 *    You can retrieve files like from a stack with the method getItem()
 *    and check if there are more items in the directory with moreElements()</p>
 * <p>The class also offers filters. Just add one or more filters with
 * setIncludeFilter and setExcludeFilter. The default value for includeFilter
 * is *.* and ExcludeFilter is empty.</p>
 */

public class Directory {

  private FileFilter includeFilter = null;
  private FileFilter excludeFilter = null;
  private Vector list;
  private File dir;
  private int dirCursor = 0;
  private boolean needUpdate = true;
  private boolean noFilter = true;

 /*****************************************************************************
  * <p>Basic constructor</p>
  * <p>Throws an exception if dirName is not a directory</p>
  *****************************************************************************/
  public Directory(String dirName) throws Exception {
    this.list = new Vector();

    this.dir = new File(dirName);           // Try to use dirName

    if(!this.dir.isDirectory()) {
      throw new Exception("Error opening directory ");
    }

    includeFilter = new FileFilter();
    excludeFilter = new FileFilter();
  }

 /*****************************************************************************
  * boolean moreElements()
  * <p>Returns true if there are more elements that have not been used with
  * popItem().</p>
  *****************************************************************************/
  public boolean moreElements() {
    this.Update();

    if(list.size() > (dirCursor)) {
       return true;
    }
    return false;
  }

 /*****************************************************************************
  * File popItem()
  * <p>Pops the next file. Throws an exception if there are no more files.</p>
  *****************************************************************************/
  public File popItem() throws Exception {
    this.Update();

    File ret;

    if(list.size() > (dirCursor)) {
      ret = (File)(list.get(dirCursor));
      dirCursor++;
      return ret;
    }
    else {
      throw new Exception("Stack empty");
    }
  }

 /*****************************************************************************
  * setIncludeFilter(Vector newFilter)
  * <p>Uses newFilter as a new Vector for including files.</p>
  *****************************************************************************/
  public void setIncludeFilter(FileFilter newFilter) {
    noFilter = newFilter.isEmpty();
    this.includeFilter = newFilter;
    this.needUpdate = true;
  }

 /*****************************************************************************
  * setExcludeFilter(Vector newFilter)
  * <p>Uses newFilter as a new Vector for excluding files.</p>
  *****************************************************************************/
  public void setExcludeFilter(FileFilter newFilter) {
    this.excludeFilter = newFilter;
    this.needUpdate = true;
  }

 /*****************************************************************************
  * String getRelativePath(File fTemp)
  * <p>Returns the relative path of the File fTemp to this directory.
  * Throws an exception if fTemp is not located in this directory.</p>
  *****************************************************************************/
  public String getRelativePath(File fTemp) throws Exception {
    String filename = fTemp.getAbsolutePath();
    String dirname = this.dir.getAbsolutePath();

    if(filename.startsWith(dirname)) {
      // +1, because the path delimiter must be stripped from the string
      return filename.substring(dirname.length()+1);
    }
    else {
      throw new Exception ("File not in directory");
    }
  }

 /*****************************************************************************
  * String getName()
  * <p>Returns the name of the directory.</p>
  *****************************************************************************/
  public String getName() {
    return dir.getName();
  }

 /*****************************************************************************
  * Update
  * <p>Updates the directory if necessary.</p>
  *****************************************************************************/
  private void Update() {
    if(this.needUpdate) {
      this.makeList(dir);
      this.dirCursor = 0;
      this.needUpdate = false;
    }
  }

 /*****************************************************************************
  * makeList(File subdir)
  * <p>Adds the file of subdir to the file list. Calls itself recursively to
  * include subdirectories.</p>
  *****************************************************************************/
  private void makeList(File subdir) {
    File[] tList = subdir.listFiles();

    for(int i=0; i<tList.length; i++) {
      if(tList[i].isDirectory()) {
        makeList(tList[i]);
      }
      else {
        if(noFilter || acceptFile(tList[i])) {   // If no filter is set, accept
          this.list.add(tList[i]);
        }
      }
    }
  }

 /*****************************************************************************
  * boolean acceptFile
  * <p>Returns true if the File satisfies the filters.</p>
  *****************************************************************************/
  private boolean acceptFile(File tFile) {
    boolean accept = false;

    if(includeFilter.matches(tFile.getName())) {
      accept = true;
    }
    if(excludeFilter.matches(tFile.getName())) {
      accept = false;
    }
    return accept;
  }
}
