/**
 * ExPrime
 * 
 * This program counts the number of prime numbers
 * between two integer numbers
 * (jdk 1.1)
 *
 */

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

public class ExPrime {
  public static void main(String[] args) {
    new ExPrime().work(new PrintWriter(System.out,true));
  }

  /**
   * main
   */
  void work(PrintWriter out) {
    int workers = 5;
    int items = 100;
    int minval = 1;
    int maxval = 1000000;

    BoundedBuffer buf = new BoundedBuffer(items+workers+1);
    ExProConRes res = new ExProConRes();

    // create work
    int size = (maxval-minval)/items;
    for (int n = minval; n < maxval; n += size) {
      int s = (n+size > maxval)? maxval-n: size;
      buf.put(new ExPrimeElem(n, s));
    }
    // drop end markers
    for (int i=0; i<workers; i++)
      buf.put(new ExPrimeElem(-1,-1));

    // creating workers
    Thread th[] = new Thread[workers];
    for (int i=0; i<workers; i++) {
      th[i] = new Thread(new ExPrimeWork(buf, i, res, out));
      th[i].start();
    }

    // terminating
    for (int i=0; i<workers; i++) 
      try { th[i].join(); } catch (InterruptedException e) {}

    out.println("total #primes between "+minval+" and "+maxval+
		" = "+res.get());
    out.println("terminated");
  }
}

/*
 * Prime number worker
 */
class ExPrimeWork implements Runnable {
  BoundedBuffer buf;
  int id;
  ExProConRes res;
  PrintWriter out;

  /**
   * Constructs a worker unit
   */
  public ExPrimeWork(BoundedBuffer b, int i, ExProConRes r, PrintWriter o) {
    buf = b;
    id = i;
    res = r;
    out = o;
  }

  /**
   * Performs the worker's work
   */
  public void run() {

    int t = 0;
    for (;;) {
      ExPrimeElem elem = (ExPrimeElem)buf.get();

      int m = elem.getValue();
      int k = elem.getSize();
      if (k < 0) break; // end

      t++;
      SmallPrimes sp = new SmallPrimes(m,k);
      int[] primes = sp.generate();
      out.println("id = "+id+", primes = "+primes.length+
		  " from "+m+" to "+(m+k));
      res.add(primes.length);
    }

    out.println("id = "+id+", done = "+t);
  }

  // simulates some computation
  // in reality, it idles for a random duration up to t seconds
  static void doSomeWork(double t) {
    try {
      Thread.currentThread().sleep((long)(t*1000.0*Math.random()));
    }
    catch (InterruptedException e) {
    }
  }
}

