/* 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.*;

class ProtectedBuffer
{
    private ArrayList<File> pool;

    public ProtectedBuffer() {
	pool = new ArrayList<File>();
    }

    public synchronized void put(File s) {
	pool.add(s);
	this.notify();
    }

    public synchronized File get() {
      while (pool.isEmpty()) {
	    System.out.println("Thread waits on empty buffer");
	    try {
		this.wait();
	    } catch (InterruptedException e) {
		System.err.println(e);
	    }
      }
      return pool.remove(0);
    }
}

// GZipThread represents a consumer
class GZipThread extends Thread {

  private ProtectedBuffer pb;

  public GZipThread(ProtectedBuffer pb) {
    this.pb = pb;
  }

  public void run() {
    System.out.println("Thread " + this.getName() + " has started");
    while (true) {
      File input = pb.get();
      if (input == null) 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 b;
            while ((b = in.read()) != -1) out.write(b);
            out.close();
            in.close();
          }
      System.out.println("Thread " + this.getName() + " gzipped "
		+ fileName);
        }
        catch (IOException e) {
         System.err.println(e);
        }
      } // 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;

  public static void main(String[] args) {
    ProtectedBuffer pb = new ProtectedBuffer();
    
    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]);
      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
    } // end for
    for (int i = 0; i < THREAD_COUNT; i++)
	pb.put(null); // Termination token 
    System.out.println("Main has terminated");
  }
}
