// The PipeTest example from the book,
// but silghtly rewritten to factor out
// some common code:
//
//  introduced an abstract class OutputtingThread which
//  is sub-classed by both FibMaker and PrimesMaker
//  got an init-method instead of a constructor


import java.io.*;

public class PipeTest {

    static int max = 100000;

    static public void main(String[] args) {
	if (args.length > 0) {
	    try { max = Integer.parseInt(args[0]); 
	    } catch (Exception e) {}
	}
	PipeTest world = new PipeTest(System.out);
    }

    private PipeTest(PrintStream out) {
	DataInputStream fibs = (new FibMaker()).init();
	DataInputStream primes = (new PrimesMaker()).init();
	try {
	    int x = fibs.readInt();
	    int y = primes.readInt();
	    while (x < max) {
		if (x == y) {
		    out.println(x + " is both fib and prime");
		    x = fibs.readInt();
		    y = primes.readInt();
		}
		else if (x<y)
		    x = fibs.readInt();
		else
		    y = primes.readInt();
	    }
	} catch (IOException e) { System.exit(0); }
    }

    abstract class OutputtingThread extends Thread {

	protected DataOutputStream out;

	public void setOutputStream(DataOutputStream o) {out = o;}

	public DataInputStream init() {
	    try {
		PipedInputStream in = new PipedInputStream();
		PipedOutputStream out = new PipedOutputStream(in);
		setOutputStream(new DataOutputStream(out));
		start();
		return new DataInputStream(in);
	    } catch (IOException e) { return null; }
	}

    }

    class FibMaker extends OutputtingThread {
	public void run() {
	    int n = 0;
	    int m = 1;
	    try {
		out.writeInt(m);
		while (m < max) {
		    int newValue = n + m;
		    n = m;
		    m = newValue;
		    out.writeInt(newValue);
		    System.out.println("next Fibonacci number: " + newValue);
		}
		out.close();
	    } catch (IOException e) { return; }
	}
    }

    class PrimesMaker extends OutputtingThread {
	public void run() {
	    int newValue = 1;
	    try {
		while (newValue < max) {
		    newValue++;
		    boolean isPrime = true;
		    for( int i = 2; i*i < newValue; i++) 
			if (newValue % i == 0) {
			    isPrime = false; break;
			}
		    if (isPrime) {
			out.writeInt(newValue);
			System.out.println("next Prime number: " + newValue);
		    }
		}
		out.close();
	    } catch (IOException e) {return; }
	}
    }
}

	
