package pregozip;

/*******************************************************************************
 * PregoZip
 *******************************************************************************
 * Author: Markus Wilthaner
 * Class: 4ADV
 * E-Mail: contact@wilth.net
 *******************************************************************************
 * Requirements:
 * A console-based application, written in Java
 * The user can enter a source directory, a target archive and an optional
 * source archive. The program creates the target archive and copies the files
 * from the directory into the archive. If the user specified a source archive,
 * the files are only added if they are not in the source archiv yet or if the
 * file in the source archive is older.
 * The user should also be able to specifiy an unlimited amount of Include and
 * Exclude filters (e.g. *.doc).
 *******************************************************************************
 * Command-line paramenters:
 * PregoZip <Directory> <Target archive> [Source archive] [-i <IncludeFilter1> <IncludeFilter2> ...] [-e <ExcludeFilter1> <ExcludeFilter2>]
 */

import java.io.*;
import java.util.Enumeration;
import java.util.Vector;
import java.util.zip.*;

/*******************************************************************************
 * <p>Class PregoZip</p>
 * <p>Copyright: Copyright (c) 2002</p>
 * @author Markus Wilthaner
 * @version 1.0
 * <p>The main class - offers a command-line interface to the classes and
 * controls them.</p>
 *******************************************************************************
 */

public class PregoZip {

  private Directory sourceDir;
  private ZipWriter zOut;
  private ZipReader zIn;

 /*****************************************************************************
  * <p>Basic Constructor - Receives the command line arguments</p>
  *****************************************************************************/
  public PregoZip(String[] args) {
    try {
      parseArguments(args);
    } catch(Exception e) {
      cmdLineError(e.getMessage(), true);
      endWithError(-2);
    }

    startZip();
  }

 /*****************************************************************************
  * <p>parseArguments</p>
  * <p>Parses the arguments and saves them in the class-variables
  *****************************************************************************/
  private void parseArguments(String args[]) throws Exception {
    if(args.length < 2) {
      if(args[0].startsWith("-help")) {
         displayHelp();
         System.exit(0);
      }
      throw new Exception("Too less parameters");
    }

    // Create a ZipWriter
    zOut = new ZipWriter(args[1]);

    // Parse the Directory
    sourceDir = new Directory(args[0]);

    if(args.length > 2) {
      FileFilter filter = null;
      FileFilter filterIn = new FileFilter();
      FileFilter filterEx = new FileFilter();

      // Parse the filter
      for(int i=2; i<args.length; i++) {

        if(args[i].charAt(0) == '-') {
          // New Filter definition
          if(args[i].charAt(1) == 'i') {
            filter = filterIn;  // Write to Include-Filter
          }
          else {
            if(args[i].charAt(1) == 'e') {
              filter = filterEx;  // Write to Exclude-Filter
            }
            else {
              throw new Exception("Filter syntax doesn't match");
            }
          }
        }
        else {
          if(filter != null) {
            filter.add(args[i]);
          } else {

          // Special case: if this is the first argument & no filter is
          // defined, try to parse it as sourceArchive
            if(i==2) {
              // Parse the source Archive
              zIn = new ZipReader(args[2]);
            }
            else {
              throw new Exception("Filter syntax doesn't match");
            }
          }
        }
      }
      sourceDir.setIncludeFilter(filterIn);
      sourceDir.setExcludeFilter(filterEx);
    }
  }

 /*****************************************************************************
  * <p>startZip</p>
  * <p>Zip loop - calls the methods for filtering, saving  and checking the
  *  files</p>
  *****************************************************************************/
  private void startZip() {
    File tFile;
    String relativePath;

    try {
      System.out.print("Archiving " + sourceDir.getName() + " into " + zOut.getName());
      if(zIn != null) {
        System.out.print(" comparing to " + zIn.getName());
      }
      System.out.println(":");

      while(sourceDir.moreElements()) {
        tFile = sourceDir.popItem();
        relativePath = sourceDir.getRelativePath(tFile);

        if(zIn == null || !(zIn.fileExists(relativePath, tFile.lastModified()))) {
          zOut.addFile(tFile, relativePath);
          System.out.println(relativePath);
        }
        else {
          System.out.println("Skipping: " + relativePath);
        }
      }
      zOut.closeArchive();
    }
    catch(Exception e) {
       cmdLineError(e.getMessage(), false);
       endWithError(-3);
    }

    System.out.println(zOut.getFileCount() + " File(s) zipped successfully");
    System.exit(0);
  }

 /*****************************************************************************
  * <p>endWithError</p>
  * <p>Closes and deletes the archive - exits the program</p>
  *****************************************************************************/
  private void endWithError(int errorCode) {
    if(zOut != null) {
      File faultyArchive = zOut.getAbsoluteFile();
      try {
        zOut.closeArchive();
      }
      catch (Exception e2) { ; }
      try { faultyArchive.delete(); }
      catch (Exception e3) { ; }
    }
    System.exit(errorCode);
  }

  /*****************************************************************************
   * <p>cmdLineError</p>
   * <p>Displays a command line error and basic syntax information</p>
   *****************************************************************************/
  private void cmdLineError(String description, boolean displaySyntax) {
    if(displaySyntax) {
      System.out.println("PregoZip V1");
      System.out.println("Adds/updates a zip file with the files of a directory");
      System.out.println("");
    }
    if(description != null) {
      System.out.print("Error: ");
      System.out.println(description);
    }
    if(displaySyntax) {
      System.out.println("");
      System.out.println("Syntax: java PregoZip <Name of Directory> <Target archive> [Source archive] [-i <IncludeFilter1> <IncludeFilter2> ...] [-e <ExcludeFilter1> <ExcludeFilter2>]");
      System.out.println("Enter java PregoZip -help for more information");
    }
  }

  /*****************************************************************************
   * <p>displayHelp</p>
   * <p>Displays a help page</p>
   *****************************************************************************/
  private void displayHelp() {
    System.out.println("***************");
    System.out.println("* PregoZip V1 *");
    System.out.println("***************");
    System.out.println("Adds/updates a zip file with the files of a directory");
    System.out.println("");

    System.out.println("Syntax: java PregoZip <Name of Directory> <Target archive> [Source archive] [-i <IncludeFilter1> <IncludeFilter2> ...] [-e <ExcludeFilter1> <ExcludeFilter2>]");
    System.out.println("");
    System.out.println("<Name of Directory>        This directory will be archived, including all subdirectories");
    System.out.println("                           The archived files in the directory will be the relative paths to this directory");
    System.out.println("<Target archive>           The archive that the program will create and store the files into");
    System.out.println("[Source archive]           Optional parameter - files that already exist in this archive will not be");
    System.out.println("                           stored in the target archive, unless they are newer");
    System.out.println("[-i <IncludeFilter1> ...]  If you specify one or more include filters, then only files meeting the filter");
    System.out.println("                           will be archived.");
    System.out.println("[-e <ExcludeFilter1> ...]  If you specify one or more exclude filters, files meeting the filter will be");
    System.out.println("                           excempt from archiving.");
    System.out.println("");
    System.out.println("More information to filters: The exclude filters are dominant - e.g. if you specify a file in the exclude");
    System.out.println(" filter, it won't be archived no matter what the include filter says. The order of the arguments doesn't");
    System.out.println(" matter. ");
    System.out.println("");
    System.out.println("Examples:");
    System.out.println("  java PregoZip D:\\MyFiles backup021201.zip backup021101.zip -e *.bak *.old");
    System.out.println("       Archives all files in D:\\MyFiles into backup021201.zip that don't exist in backup021101.zip, ");
    System.out.println("       excluding all *.bak and *.old files.");
    System.out.println("");
    System.out.println("  java PregoZip C:\\java\\ javafiles.zip -i *.j* -e *.jar");
    System.out.println("       Archives all *.j* Files (like *.java *.jdoc...) from C:\\java\\, but but leaves out all *.jar files");
  }

  public static void main(String[] args) {
    PregoZip pregoZip1 = new PregoZip(args);
  }
}
