/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package test.org.glassfish.grizzly.samples.plain;


import static org.junit.Assert.*;

import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.xml.ws.BindingProvider;

import org.glassfish.grizzly.samples.echo.EchoClient;
import org.glassfish.grizzly.samples.echo.EchoServer;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 *
 * @author tmeltse
 */
public class PlainEchoNGTest
{
	private static final short MIN_RANGE_INDEX = 1;
	private static final short MAX_RANGE_INDEX = 100;
	

	EchoServer server;
	
	public PlainEchoNGTest()
	{
	}
	// TODO add test methods here.
	// The methods must be annotated with annotation @Test. For example:
	//
	// @Test
	// public void hello() {}

	@BeforeClass
	public static void setUpClass() throws Exception
	{
		
	}

	@AfterClass
	public static void tearDownClass() throws Exception
	{
	}

	@Before
	public void setUpMethod() throws Exception
	{
		server = new EchoServer();
		server.start();
	}

	@After
	public void tearDownMethod() throws Exception
	{
		server.stopServer();
	}
	
	/**
	 * Test parallel  session.
	 */
	@Test
	public void testSessionInParallel()
	{
		final AtomicInteger passedTransactions = new AtomicInteger();
		final AtomicInteger failedTransactions = new AtomicInteger();
		
		final AtomicInteger completedExecutors = new AtomicInteger();
		
		final AtomicInteger totalInvocationTimeInMs = new AtomicInteger();

//		final Random randomRangeIndexGenerator = new Random();

		final int DELAY_BETWEEN_EXECUTORS_IN_MS = 250; // 125
		final int CONCURRENCY_LEVEL = 1000; // 500
		final int DELAY_BETWEEN_REPETITIONS_IN_MS = 125; // 250
		final int REPETITION_COUNT = 50; // 20
		ExecutorService executors = Executors.newFixedThreadPool(CONCURRENCY_LEVEL);
		
		long startTime = System.currentTimeMillis();
		long testExecutionTimeInMs = 0;
		
		for (int idx=0;idx < CONCURRENCY_LEVEL;idx++)
		{
			System.out.println("Going to submit task number " + (idx+1));
			
			try
			{
				// Make a delay
				Thread.sleep(DELAY_BETWEEN_EXECUTORS_IN_MS);
			}
			catch (InterruptedException ex)
			{
				fail("Failed performing plain session");
			}
			
			executors.execute(new Runnable() {
				@Override
				public void run()
				{
					for (int idy=0;idy < REPETITION_COUNT;idy++)
					{
						try
						{
							// Make a delay
							Thread.sleep(DELAY_BETWEEN_REPETITIONS_IN_MS);
						}
						catch (InterruptedException ex)
						{
							fail("Failed performing plain session");
						}
	
						try
						{
							long startTime = System.currentTimeMillis();

							//WORK
							EchoClient client = new EchoClient();
							client.start();
//							while (client.connection==null){}
							client.writeString("1");
							client.writeString("2");
							client.writeString("3");
							client.writeString("4");
							client.writeString("5");
							client.writeString("6");
							client.writeString("7");
							client.writeString("8");
							client.writeString("9");
							client.writeString("10");
							client.stopClient();
							
							long endTime = System.currentTimeMillis();
							long elapsedTime = endTime - startTime;

							// Mark the invocation time
							System.out.println("Current invocation took [" + elapsedTime + "] ms");
							totalInvocationTimeInMs.addAndGet((int)elapsedTime);

							// Count as success
							passedTransactions.incrementAndGet();
						}
						catch (Throwable ex)
						{
							// Count as failure
							failedTransactions.incrementAndGet();

							fail("Failed running Plain tester");
						}
					}
					
					// Mark the thread has ended
					completedExecutors.incrementAndGet();
				}	
			});

//			System.out.println("Submitted task number " + (idx+1));
		}
		
		long endTime = System.currentTimeMillis();
		long elapsedTime = endTime - startTime;
		System.out.println("Elapsed time for launching all executors is: [" + elapsedTime + "] ms");
		
		try
		{
			// Terminate the executors pool
			executors.shutdown();
//			Thread.sleep(1000*60*10);
			executors.awaitTermination(5,TimeUnit.MINUTES);
//			executors.shutdown();
			
			// Verify the test ended with success
			assertEquals(failedTransactions.get(),0);
			assertEquals(completedExecutors.get(),CONCURRENCY_LEVEL);
			
			endTime = System.currentTimeMillis();
			testExecutionTimeInMs = endTime - startTime;
			System.out.println("Elapsed time for total test duration is: [" + testExecutionTimeInMs + "] ms");
		}
		catch (InterruptedException ex)
		{
			fail("Failed transcoding from SBC to AMR");
		}
		finally
		{
				
			System.out.println("===== Number of passed transactions is: [" + passedTransactions.get() + "] =====");
			System.out.println("===== Number of failed transactions is: [" + failedTransactions.get() + "] =====");

			System.out.println("+++++ Number of completed executors is: [" + completedExecutors.get() + "] out of [" + CONCURRENCY_LEVEL + "] +++++");

			System.out.println("----- Average invocation time is: [" + (passedTransactions.get() == 0 ? 0 : totalInvocationTimeInMs.get()/passedTransactions.get()) + "] ms -----");
			System.out.println("----- Average TPS is: [" + (testExecutionTimeInMs <= 1 ? testExecutionTimeInMs : Math.round((CONCURRENCY_LEVEL*REPETITION_COUNT)/(testExecutionTimeInMs/1000))) + "] -----");
		}
	}
}
