package pt.utl.ist.fenix.client.test.load;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import pt.utl.ist.fenix.client.http.PropertiesManager;


public class MultiThreadedLoadTest {

    private static int numberOfThreads = PropertiesManager.NUMBER_PARALEL_THREADS;

    public static void main(String[] args) {
	processArgs(args);
	run();
	System.out.flush();
	System.err.flush();
	System.exit(0);
    }

    private static void processArgs(final String[] args) {
	for (final String arg : args) {
	    try {
		int a = Integer.valueOf(arg);
		numberOfThreads = a;
	    } catch (final NumberFormatException e) {
	    }
	}
	System.out.println("Will launch: " + numberOfThreads + " concurrent threads.");
    }

    private static void run() {
	try {
	    final ThreadWatcher threadWatcher = new ThreadWatcher();
	    for (int i = 0; i < numberOfThreads; i++) {
//		System.out.println("Lanching thread " + i);
		launchThread(threadWatcher);
	    }
	    System.out.println("All " + numberOfThreads + " thread have been launched.");
	    threadWatcher.start();
	    threadWatcher.join();
	} catch (final Exception ex) {
	    ex.printStackTrace();
	}
    }

    private static void launchThread(final ThreadWatcher threadWatcher) {
	final User user = new Student(null);
	//final User user = new AnnonymousUser(null);
	user.start();
	threadWatcher.add(user);
	snooze(PropertiesManager.THREAD_LAUNCH_SLEEP_INTERVAL);
    }

    private static class ThreadWatcher extends Thread {

	private List<User> threads = new ArrayList<User>();

	private int numberRequests = 0;

	private int numberResponses = 0;

	private int totalResponseTime = 0;

	@Override
	public void run() {
	    super.run();
	    while (!threads.isEmpty()) {
		for (final Iterator<User> threadIterator = threads.iterator(); threadIterator.hasNext(); ) {
		    final User thread = threadIterator.next();
		    if (!thread.isAlive()) {
			numberRequests += thread.getTotalRequests();
			numberResponses += thread.getTotalResponses();
			totalResponseTime += thread.getTotalSucessfulResponseTime();
			threadIterator.remove();
		    }
		}
//		System.out.println("" + threads.size() + " still remaining.");
		snooze(PropertiesManager.THREAD_WATCHER_SLEEP_INTERVAL);
	    }

	    report();
	}

	private void report() {
	    System.out.println("Launched a total of: " + numberOfThreads);
	    System.out.println("   number of requests: " + numberRequests);
	    System.out.println("   number of responses: " + numberResponses);
	    System.out.println("   total response time: " + totalResponseTime + "ms");
	    System.out.println("   average response time: " + (totalResponseTime / numberResponses) + "ms");
	    System.out.println("   average total user time: " + (totalResponseTime / numberOfThreads) + "ms");
	    System.out.println("Sucess rate: " + ((100 * numberResponses) / numberRequests) + "%");
	}

	public void add(final User thread) {
	    threads.add(thread);
	}
    }

    private static void snooze(int time) {
	if (time > 0) {
	    try {
		Thread.currentThread().sleep(time);
	    } catch (InterruptedException e) {
		throw new Error(e);
	    }
	}
    }

}
