/* This a modified version of a program from Helliot's Network Programming 
   book, 3rd edition. Modified by Giorgio Ingargiola.
 */

import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.util.concurrent.*;

// GZipThread represents a consumer
class GZipThread extends Thread {

  private ArrayBlockingQueue<File> pb;

  public GZipThread(ArrayBlockingQueue<File> pb) {
    this.pb = pb;
  }

  public void run() {
    System.out.println("Thread " + this.getName() + " has started");
    while (true) {
      File input = null;
      try {
	input = pb.take();
      } catch (InterruptedException e) {
	System.out.println(e);
      }
      if (input == GZipAllFiles.getTerminator()) break;
      String fileName = input.getName();
      System.out.println("Thread " + this.getName() + " got " + fileName);

      // don't compress an already compressed file
      if (!fileName.endsWith(".gz")) {
        try {
          InputStream in = new FileInputStream(input);
          in = new BufferedInputStream(in);

          File output = new File(input.getParent(), input.getName() + ".gz");
          if (!output.exists()) { // Don't overwrite an existing file
            OutputStream out = new FileOutputStream(output);
            out = new GZIPOutputStream(out);
	    int n = in.available();
	    // The following loop is to make certain that we read
	    // completely the underlying file
	    while (n > 0) {
        	byte[] buf = new byte[n];
        	in.read(buf);
        	out.write(buf, 0, n);
		n = in.available();
	    }
            out.close();
            in.close();
          }
          System.out.println("Thread " + this.getName() + " gzipped "
		+ fileName);
        }
        catch (IOException e) {
         System.err.println(e);
	 e.printStackTrace(System.err);
        }
      } // end if
    } // end while
    System.out.println("Thread " + this.getName() + " has terminated");
  } // end run

} // end GZipThread

// GZipAllFiles represents the producer
public class GZipAllFiles {
  
  public final static int THREAD_COUNT = 4;
  private static File terminator; // This is a sentinel value 
	// indicating a file that cannot exist in our program
  
  static {
    try {
      terminator = new File("");
    } catch (Exception e) {
	e.printStackTrace(System.err);
    }
  }

  public static File getTerminator() {
    return terminator;
  }


  public static void main(String[] args) {
    if (args.length < 1) {
	System.out.println("usage: java GZipAllFiles file1 .. filen");
	return;
    }

    ArrayBlockingQueue<File> pb = new ArrayBlockingQueue<File>(100);
    
    for (int i = 0; i < THREAD_COUNT; i++) {
      (new GZipThread(pb)).start();
    }

    for (int i = 0; i < args.length; i++) {
      File f = new File(args[i]);
      try {
      if (f.exists()) {
        if (f.isDirectory()) {
          File[] files = f.listFiles();
          for (int j = 0; j < files.length; j++) {
            if (!files[j].isDirectory()) { // don't recurse directories
                pb.put(files[j]);
		System.out.println("Main puts " + files[j].getName());
            }
          }
        } else {
            pb.put(f);
	    System.out.println("Main puts " + f.getName());
        }
      } // end if
      } catch (InterruptedException e) {
	System.out.println(e);
      }
    } // end for
    for (int i = 0; i < THREAD_COUNT; i++)
      try {
	pb.put(terminator); // Termination token 
      } catch (InterruptedException e) {
	System.out.println(e);
     }
    System.out.println("Main has terminated");
  }
}
