package com.eactive.eai.adapter.socket2.app.tester;


import com.eactive.eai.adapter.socket2.common.StopWatch;
import com.eactive.eai.adapter.socket2.config.SocketAdapterContext;
import com.eactive.eai.adapter.socket2.config.SocketAdapterFactory;
import com.eactive.eai.adapter.socket2.protocol.ByteMessage;
import com.eactive.eai.adapter.socket2.protocol.IRequestProcessor;
import com.eactive.eai.adapter.socket2.protocol.ISocketAdapter;
import com.eactive.eai.common.util.UUIDGenerator;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


public class LoadRunner {
	String hostname;
	String message;
	
	final ISocketAdapter httpAdapter;
	final ISocketAdapter adapter1;	
	final ISocketAdapter adapter2;	
	final ISocketAdapter adapter3;	
	final ISocketAdapter adapter4;	
	
	int threadCount = 1;
	int loopCount = 1;
	long thinkTime = 0L;
	CountDownLatch latch;
	
	
	public LoadRunner(String hostname, String filename) throws Exception {
		this.hostname = hostname;		
		this.message = readFile(filename);
		
		SocketAdapterContext context = null;
		
		/**
		 * Http Server
		 */
		context = new SocketAdapterContext();
		context.setAdapterGroupName("AdminAdapterGroup");
		context.setAdapterName("HttpAdapter");
		context.setProtocol("HTTP");
		context.setBoundUsage("IOBOUND");
		context.setSocketType("SERVER");
		context.setHostName("*");
		context.setPortNumber(8282);
		context.setAckSupport("N");
		context.setPermanent("N");
		context.setResponseType("SYNC");
		context.setTimeout(60);
		context.setTraceLevel(context.TRACE_LEVEL_DEFAULT);		
		context.setAclList("172.26.127.*,127.0.0.1");
		httpAdapter = SocketAdapterFactory.createSocketAdapter(context);
		httpAdapter.start();		
		
		/**
		 * port:10004
		 */
		context = new SocketAdapterContext();
		context.setAdapterGroupName("FixedLengthHeaderAdapterGroup");
		context.setAdapterName("Bin2ClientAdapter-10004");
		context.setProtocol("FIXED_LENGTH_HEADER");
		context.setSocketType("CLIENT");
		context.setHostName(hostname);
		context.setPortNumber(10004);
		
		//context.setLocalHostName("172.26.127.106");
		//context.setLocalPortNumber(12929);
		
		context.setResponseType("ASYN");
		context.setMaxConnection(10);
		context.setMaxThread(100);
		context.setTimeout(10);
		context.setTraceLevel(context.TRACE_LEVEL_INFO);	
		
		context.setRequestProcessor(new IRequestProcessor() {
			public byte[] handle(byte[] request) throws Exception {
				//System.out.println("[" + TimeUtil.formatDate(System.currentTimeMillis()) + "] <RECV> " + new String(request));
				System.out.print(".");
				latch.countDown();
				return request;
			}
		});
		
		adapter4 = SocketAdapterFactory.createSocketAdapter(context);
		adapter4.start();
		
		/**
		 * port:10003
		 */
		context = new SocketAdapterContext();
		context.setAdapterGroupName("FixedLengthHeaderAdapterGroup");
		context.setAdapterName("Bin2ClientAdapter-10003");
		context.setProtocol("FIXED_LENGTH_HEADER");
		context.setSocketType("CLIENT");
		context.setHostName(hostname);
		context.setPortNumber(10003);
		context.setResponseType("ASYN");
		context.setMaxConnection(10);
		context.setMaxThread(100);
		context.setTimeout(10);
		context.setTraceLevel(context.TRACE_LEVEL_INFO);		
		adapter3 = SocketAdapterFactory.createSocketAdapter(context);
		adapter3.start();
		
		/**
		 * port:10002
		 */
		context = new SocketAdapterContext();
		context.setAdapterGroupName("FixedLengthHeaderAdapterGroup");
		context.setAdapterName("Bin2ClientAdapter-10002");
		context.setProtocol("FIXED_LENGTH_HEADER");
		context.setSocketType("CLIENT");
		context.setHostName(hostname);
		context.setPortNumber(10002);
		context.setResponseType("ASYN");
		context.setMaxConnection(10);
		context.setMaxThread(100);
		context.setTimeout(10);
		context.setTraceLevel(context.TRACE_LEVEL_INFO);		
		adapter2 = SocketAdapterFactory.createSocketAdapter(context);
		adapter2.start();	

		context.setRequestProcessor(new IRequestProcessor() {
			public byte[] handle(byte[] request) throws Exception {
				//System.out.print("2");
				adapter3.sendMessage(request);
				//System.out.print("3");
				return request;
			}
		});
		
		/**
		 * port:10001
		 */
		context = new SocketAdapterContext();
		context.setAdapterGroupName("FixedLengthHeaderAdapterGroup");
		context.setAdapterName("Bin2ClientAdapter-10001");
		context.setProtocol("FIXED_LENGTH_HEADER");
		context.setSocketType("CLIENT");
		context.setHostName(hostname);
		context.setPortNumber(10001);
		context.setResponseType("ASYN");
		context.setMaxConnection(10);
		context.setMaxThread(100);
		context.setTimeout(10);
		context.setTraceLevel(context.TRACE_LEVEL_INFO);		
		adapter1 = SocketAdapterFactory.createSocketAdapter(context);
		adapter1.start().join();
	}
	
	public void start() throws Exception {	
		/**
		 * latch
		 */
		latch = new CountDownLatch(threadCount * loopCount);
		
		/**
		 * executor
		 */
        ExecutorService executor = Executors.newCachedThreadPool();

        final CountDownLatch startLatch = new CountDownLatch(1);
        final CountDownLatch stopLatch  = new CountDownLatch(threadCount);

		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
        
		for (int i = 0; i < threadCount; i++) {
			executor.execute(new Runnable() {
				public void run() {
					try {
			            startLatch.await();
						for (int j=0; j<loopCount; j++) {
							// �׷��ڵ�(3) + ����Ű(10) + timestamp(17) + �Ϸù�ȣ(3) + �ý��� ����Ϸù�ȣ("001")
							String uuid = UUIDGenerator.getGUID("KB0");
							System.out.print("o");
							adapter1.sendMessage(message.replace("#{UUID}", uuid).replace("#{UUID-3}", uuid.substring(0, uuid.length()-3)));
							Thread.sleep(thinkTime);
						}
			            stopLatch.countDown();
					} catch (Exception e) {
						// System.out.println(e.toString());
					} catch (Error e) {
						// System.out.println(e.toString());
					}					
				}
			});
		}
		
        startLatch.countDown();
        
        try {   
            stopLatch.await();
        } catch (InterruptedException ex) {
            //ex.printStackTrace();
        	// System.out.println("wait error");
        }

        executor.shutdown();
		while (true) {
	       try {
	           boolean result = executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
	           if (result)
	        	   break;
	           // System.out.println("[LoadRunner] shutdown() progressing ... await 1 seconds more");
	       } catch (InterruptedException e) {
	           //e.printStackTrace();
	    	   // System.out.println("awaitTermination error");
	       }
		}
		
		latch.await();
		stopWatch.stop();
		
		// System.out.println();
		// System.out.println();
		// System.out.println("===============================================================");
		// System.out.println("    think time    : " + thinkTime + " ms");
		// System.out.println("    thread count  : " + threadCount);
		// System.out.println("    loop count    : " + loopCount);
		// System.out.println("    total request : " + (threadCount * loopCount));
		// System.out.println("    elapsed       : " + stopWatch.toString());
		// System.out.println("    tps           : " + new Integer(threadCount * loopCount * 1000).longValue() / stopWatch.getTime());
		// System.out.println("===============================================================");
		// System.out.println();
	}

	
    public void processCommand() {
        while(true) {
            try {
            	System.out.print("cmd> ");
            	String line = (new BufferedReader(new java.io.InputStreamReader(System.in))).readLine();
            	
            	if (line == null) {
            		break;            	
            	} else if ("".equals(line.trim())) {
            	} else if ("help".equals(line.trim())) {
            		// System.out.println("===============================================================");
            		// System.out.println("LoadRunner v1.0 (http port = 8282)");
            		// System.out.println("===============================================================");
            		// System.out.println("    help    : help");
            		// System.out.println("    start   : start [thread count] [loop count] [think time]");
            		// System.out.println("    exit    : exit");
            		// System.out.println("");
            	} else if (line.trim().startsWith("start")) {
            		String[] tokens = line.trim().split("[ ]+");
            		if (tokens.length > 1)
            			threadCount = Integer.parseInt(tokens[1]);
            		if (tokens.length > 2)
            			loopCount = Integer.parseInt(tokens[2]);
            		if (tokens.length > 3)
            			thinkTime = Long.parseLong(tokens[3]);
            		start();
            	} else if ("exit".equals(line.trim())) {
            		System.exit(1);
            	} else {
            		// System.out.println("Unknow command. type help.");
            	}
            } catch(Exception e) {
                // System.out.println("Error " + e.toString());
            }
        }
	}	
	
    
	private String readFile(String filename) throws FileNotFoundException, IOException {
		String line = "";
		ByteMessage data = new ByteMessage();
		BufferedReader br = new BufferedReader(new FileReader(filename));
		
		try {
			while ((line = br.readLine()) != null) {	
				while(line.indexOf("0x") != -1) {
					data.append(line.substring(0, line.indexOf("0x")));
					String hex = line.substring(line.indexOf("0x"), line.indexOf("0x")+4);	
					data.append((byte) Integer.parseInt(hex.substring(2), 16));
					line = line.substring(line.indexOf("0x")+4);				
				}
				data.append(line);
			}
			return data.getString();
		}
		catch(Exception e) {
			throw e;
		}
		finally {
			try {
				if(br != null) br.close();
			}
			catch(Exception ee) {
				// System.out.println("close error");
			}
		}
		
	
	}    
	
	static public void main(String[] args) throws Exception {
//		/**
//		 * server - port:10004
//		 */
//		SocketAdapterContext context = new SocketAdapterContext();
//		context.setAdapterGroupName("FixedLengthHeaderAdapterServerGroup");
//		context.setAdapterName("Bin2ServerAdapter-10004");
//		context.setProtocol("FIXED_LENGTH_HEADER");
//		context.setSocketType("SERVER");
//		context.setHostName("*");
//		context.setPortNumber(10004);
//		context.setResponseType("ASYN");
//		context.setMaxConnection(10);
//		context.setMaxThread(100);
//		context.setTimeout(10);
//		context.setTraceLevel(context.TRACE_LEVEL_INFO);	
//		final ISocketAdapter adapter4 = SocketAdapterFactory.createSocketAdapter(context);
//		adapter4.start();
//
//		
//		/**
//		 * server - port:10001
//		 */
//		context = new SocketAdapterContext();
//		context.setAdapterGroupName("FixedLengthHeaderAdapterServerGroup");
//		context.setAdapterName("Bin2ServerAdapter-10001");
//		context.setProtocol("FIXED_LENGTH_HEADER");
//		context.setSocketType("SERVER");
//		context.setHostName("*");
//		context.setPortNumber(10001);
//		context.setResponseType("ASYN");
//		context.setMaxConnection(10);
//		context.setMaxThread(100);
//		context.setTimeout(10);
//		context.setTraceLevel(context.TRACE_LEVEL_INFO);	
//		
//		context.setRequestProcessor(new IRequestProcessor() {
//			public byte[] handle(final byte[] request) throws Exception {
////		        ExecutorService executor = new ThreadPoolExecutor(16, 16, 60, TimeUnit.SECONDS, new LinkedBlockingQueue());
////		        executor.execute(new Runnable() {
////		        	public void run() {
////		        		try {
//		        			adapter4.sendMessage(request);
////		        		} catch(Exception e) {
////		        			e.printStackTrace();
////		        		}
////		        	}
////		        });
//				return request;
//			}
//		});
//		
//		final ISocketAdapter adapter1 = SocketAdapterFactory.createSocketAdapter(context);
//		adapter1.start();
		
		//----------------------------------------------------------------------
		if (System.getProperty("inst.Name") == null)
			System.setProperty("inst.Name", System.getProperty("test"));
		
		String hostname = "localhost";
		String filename = "";
		
		if (args.length == 2) {
			hostname = args[0];
			// System.out.println("remote host : " + hostname);
			filename = args[1];
		} else {
			// System.out.println("Usage : loadrunner [ip] [file]");
			return;
		}
		
		LoadRunner loadRunner = new LoadRunner(hostname, filename);
		loadRunner.processCommand();
	}
}
