/*
 *  Copyright(c)2002 Forward Computing and Control Pty. Ltd.
 *  ACN 003 669 994, NSW, Australia	    All rights Reserved
 *  
 *   Written by Dr. M.P. Ford
 */
import au.com.forward.threads.*;
import java.io.IOException;
import java.util.Random;
import java.util.Date;
import java.text.SimpleDateFormat;


/**
 *  test thread 
 *
 * @author     matthew ford 
 * @created    5 May 2002 
 */
class TestThread extends Thread {
	/**
	 *  Description of the Field 
	 */

	boolean throwException = false;


	/**
	 *  Constructor for TestThread 
	 *
	 * @param  name  the name of this thread
	 * @param  _throwException  true if IOException to be thrown, else false 
	 */
	TestThread(String name, boolean _throwException) {
		super(name);
		throwException = _throwException;
	}


	/**
	 *  The TestThread's run() method This will throw an IOException of 
	 *  throwException is true 
	 */
	public void run() {
		try {
			System.out.println("In TestThread run() " + Thread.currentThread().getName() + " " + 
					new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
      
			ThreadReturn.ifInterruptedStop(); // stop here if already interrupted
			
			if (throwException) {
				throw new IOException("TestThread throwing IOException in "+Thread.currentThread().getName());
			}
			System.out.println("Start calculations in "+Thread.currentThread().getName());
			// do some work here but check every now and again if thread should stop
			// test if this thread should stop
			Random rand = new Random();
			double nextRand = rand.nextDouble();
			for (int j = 0; j < 1000; j++) {
				for (int i = 0; i < 10000; i++) {
					nextRand = rand.nextDouble();
				}
				// throw InterruptedException if interrupted
				ThreadReturn.ifInterruptedStop();
			}
			System.out.println("Finished calculations in "+Thread.currentThread().getName());

			Thread.currentThread().sleep(1500);

			System.out.println("End of TestThread run() " + Thread.currentThread().getName() + " " + 
					new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			// return result
			ThreadReturn.save(new Double(nextRand));
		} catch (Throwable t) {
			ThreadReturn.save(t);
		}
	}
}

/**
 *  Tests for ThreadReturn Class 
 *
 * @author     matthew ford 
 * @created    October 21, 2001 
 */
public class ThreadTests implements ThreadListener {

	/**
	 * the newline string for this system
	 */
	private static String nl;
	
	static {
		nl = (String) java.security.AccessController.doPrivileged(
				new sun.security.action.GetPropertyAction("line.separator"));
	}
	
	/**
	 *  the date formatter for all output 
	 */
	private static SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SS");


	/**
	 *  The main program for the tests 
	 *
	 * @param  args  The command line arguments 
	 */
	public static void main(String[] args) {
		new ThreadTests().Tests();
	}


	// listener methods
	/**
	 *  Description of the Method 
	 *
	 * @param  e  Description of Parameter 
	 */
	public void threadResult(ThreadEvent e) {
		System.out.println(formatter.format(new Date()) 
			+ " in threadReturned with ThreadEvent:" + nl+ e.toString());
	}


	// listener methods
	/**
	 *  Description of the Method 
	 *
	 * @param  e  Description of Parameter 
	 */
	public void threadInterrupted(ThreadEvent e) {
		System.out.println(formatter.format(new Date()) 
			+ " in threadInterrupted with ThreadEvent:" + nl+  e.toString());
	}

	// listener methods
	/**
	 *  Description of the Method 
	 *
	 * @param  e  Description of Parameter 
	 */
	public void threadError(ThreadEvent e) {
		System.out.println(formatter.format(new Date()) 
			+ " in threadError with ThreadEvent:" + nl+  e.toString());
	}


	/**
	 *  test ThreadReturn 
	 */
	public void Tests() {
		System.out.println(" ------------ ThreadTests");
		System.out.println();

		// try one and wait forever
		TestThread t1 = new TestThread("Thread_1",false);
		System.out.println(" Thread_1 " + (t1.isAlive() ? "is Alive" : "is NOT Alive") + 
				" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		try {
			System.out.println(" join(Thread_1) before starting it." + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			Object rtn = ThreadReturn.join(t1);
			System.out.println(" join() returned result:" + rtn.toString());
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}

		try {
  		System.out.println();
			System.out.println(" starting Thread_1 " + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			t1.start();
			System.out.println(" Thread_1 " + (t1.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			Object rtn = ThreadReturn.join(t1);
			System.out.println(" join() returned result:" + rtn.toString());
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}
		
		System.out.println(" Thread_1 " + (t1.isAlive() ? "is Alive" : "is NOT Alive") + 
				" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		try {
			System.out.println();
  		System.out.println(" starting Thread_1 again" + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			t1.start();
			System.out.println(" Thread_1 " + (t1.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			Object rtn = ThreadReturn.join(t1);
			System.out.println(" join() returned result:" + rtn.toString());
			System.out.println(" join() returned " + (t1.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}

		// now try stop
		ThreadReturn.debug = true;
		try {
			TestThread i1 = new TestThread("Thread_i1",false);
  		System.out.println();
  		System.out.println(" Interrupt Thread_i1 before starting it.");
			ThreadReturn.stop(i1);
			Thread.currentThread().sleep(ThreadReturn.getCheckDelay()*2);
			System.out.println(" starting Thread_2 " + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			i1.start();
			System.out.println(" Thread_i1 " + (i1.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			Object rtn = ThreadReturn.join(i1, 500);
			System.out.println(" join() returned result:" + rtn.toString());
			System.out.println(" join() returned " + (i1.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}
		ThreadReturn.debug = false;
		
		try {
			TestThread t2 = new TestThread("Thread_2",false);
  		System.out.println();
  		System.out.println(" Start Thread_2 and then stop it.");
			System.out.println(" starting Thread_2 " + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			t2.start();
			System.out.println(" Thread_2 " + (t2.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			t2.interrupt();
			Object rtn = ThreadReturn.join(t2, 500);
			System.out.println(" join() returned result:" + rtn.toString());
			System.out.println(" join() returned " + (t2.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}

		try {
			TestThread t3 = new TestThread("Thread_3",false);
  		System.out.println();
  		System.out.println(" Start Thread_3 and let join() timeout.");
			System.out.println(" starting Thread_3 " + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			t3.start();
			System.out.println(" Thread_3 " + (t3.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			Object rtn = ThreadReturn.join(t3, 500);
			System.out.println(" join() returned result:" + rtn.toString());
			System.out.println(" join() returned " + (t3.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}

		try {
			TestThread t4 = new TestThread("Thread_4",true);
  		System.out.println();
  		System.out.println(" Start Thread_4 which will throw an Exception.");
			System.out.println(" starting Thread_4 " + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			t4.start();
			System.out.println(" Thread_4 " + (t4.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			Object rtn = ThreadReturn.join(t4, 500);
			System.out.println(" join() returned result:" + rtn.toString());
			System.out.println(" join() returned " + (t4.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}

		// now try listeners
		ThreadReturn.debug = true;
		// turn on debug
		System.out.println();
		System.out.println(" -----------  Test Listeners --------- ");
		System.out.println();
		
		TestThread t5 = new TestThread("Thread_5",false);

		try {
  		System.out.println(" Add listener to Thread_5 before starting thread ");
			ThreadReturn.addListener(t5, this);
			Thread.currentThread().sleep(200);
			System.out.println(" starting Thread_5 " + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			t5.start();
			System.out.println(" Thread_5 " + (t5.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			Object rtn = ThreadReturn.join(t5);
			System.out.println(" join() returned result:" + rtn.toString());
			System.out.println(" join() returned " + (t5.isAlive() ? "is Alive" : "is NOT Alive") + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}

		try {
			Thread.currentThread().sleep(100);
		} catch (InterruptedException ex) {
		}

		System.out.println();
		System.out.println(" adding listener after Thread_5 died." + 
				" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		ThreadReturn.addListener(t5, this);

		try {
			Thread.currentThread().sleep(100);
		} catch (InterruptedException ex) {
		}

		System.out.println();
		System.out.println(" adding listener after Thread_5 restarted." + 
				" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
		t5.start();
		try {
			ThreadReturn.addListener(t5, this);
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}


		try {
			System.out.println();
  		System.out.println(" Add listener to Thread_6 that will throw an exception ");
			TestThread t6 = new TestThread("Thread_6",true);
			ThreadReturn.addListener(t6, this);
			System.out.println(" starting Thread_6 " + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			t6.start();
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}

		try {
			System.out.println();
  		System.out.println(" Add listener to Thread_7 that will be interrupted ");
			TestThread t7 = new TestThread("Thread_7",false);
			ThreadReturn.addListener(t7, this);
			System.out.println(" starting Thread_7 " + 
					" " + new SimpleDateFormat("yy/MM/dd HH:mm:ss.SS").format(new Date()));
			t7.start();
			Thread.currentThread().sleep(100);
			t7.interrupt();
			Thread.currentThread().sleep(1000);
		} catch (Exception ex) {
			System.out.println(StackTrace.toString(ex));
		}

		System.out.println();
		System.out.println(" - finished - ThreadTests");
	}

}
