package tests;

import static org.junit.Assert.*;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;

import jsr166y.ForkJoinPool;
import jsr166y.ForkJoinTask;

import maxInParallel.MaxWithFJ;
import maxInParallel.SelectMaxProblem;

import org.junit.Test;


public class MaxWithFJTests {
	
	private final SelectMaxProblem problem;
    private int threshold;
    private int nThreads;
    private final int[] number = new int[10000000];
	
	public MaxWithFJTests(){
		
		
		Random randomGenerator = new Random();
		
		for (int idx = 0; idx < 10000000; idx++)
			number[idx] = randomGenerator.nextInt(50000000);

		this.problem = new SelectMaxProblem(number, 0, number.length-1);
        this.threshold = 1000000;
        this.nThreads = 4;

	}
	
	//@Test
	public void parallelTest(){

		// Create file
		FileWriter fstream = null;
		try {
			fstream = new FileWriter("SelectMaxOut.csv");
			
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		BufferedWriter fileOut = new BufferedWriter(fstream);

		int[] chunk = {1000000, 500000, 50000,5000,500,50};

		try {
			fileOut.write("#Thread; Threashold; time (ms) \n ");			
		} catch (Exception e) {// Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}

		for (int i = 1; i <= 20; i++) {
			int numThreads = i;
			for (int j = 0; j < chunk.length; j++) {
				
				threshold = chunk[j];
				nThreads = i;
				

				MaxWithFJ mfj = new MaxWithFJ(problem, threshold);
				ForkJoinPool fjPool = new ForkJoinPool(nThreads);

				long startTime = System.currentTimeMillis();

				fjPool.invoke(mfj);

				long endTime = System.currentTimeMillis();
				long elapsed = endTime - startTime;

				int result = mfj.getResult();

				System.err.println("The result of the PARALLEL execution is: " + result + " and the elapsed time is: " + elapsed +"ms (threshold: "+threshold+" threads: "+nThreads+")");

				try {
					fileOut.write(nThreads+";" + threshold + ";" + elapsed +" \n");			
				} catch (Exception e) {// Catch exception if any
					System.err.println("Error: " + e.getMessage());
				}
				
				//calculating the maximum value on the entire sequence  
				int max = Integer.MIN_VALUE;
				for (int y = 0; y<number.length-1; y++){
					int n = number[y];
					if(n > max)
						max = n;
				}

				assertEquals(result, max);
			}
		}
		try {
			fileOut.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}
	
	@Test
	public void sequentialTest(){	       
		
		long startTime = System.currentTimeMillis();
		
		int result = problem.solveSequentially();
		
		long endTime = System.currentTimeMillis();
        long elapsed = endTime - startTime;
        
        System.err.println("The result of the SEQUENTIAL execution is: " + result + " and the elapsed time is: " + elapsed +"ms");
        
        //calculating the maximum value on the entire sequence  
        int max = Integer.MIN_VALUE;
		for (int i = 0; i<number.length-1; i++){
			int n = number[i];
			if(n > max)
				max = n;
		}
		
        assertEquals(result, max);        
	}
	
	@Test
	public void parallelTestClean(){
	        
        MaxWithFJ mfj = new MaxWithFJ(problem, threshold);
        ForkJoinPool fjPool = new ForkJoinPool(nThreads);

        long startTime = System.currentTimeMillis();
        
        fjPool.invoke(mfj);

		long endTime = System.currentTimeMillis();
        long elapsed = endTime - startTime;
        
        int result = mfj.getResult();

        System.err.println("The result of the PARALLEL execution is: " + result + " and the elapsed time is: " + elapsed +"ms (threshold: "+threshold+" threads: "+nThreads+")");
        
        //calculating the maximum value on the entire sequence  
        int max = Integer.MIN_VALUE;
		for (int i = 0; i<number.length-1; i++){
			int n = number[i];
			if(n > max)
				max = n;
		}
		
        assertEquals(result, max);        
	}
	
}
