import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SimpleChatClient {

	
	private static final String HOST = "127.0.0.1";
	private static final int PORT = 9999;
	
	private static FileHandler fileHandler;
	private static Logger logger = Logger.getLogger("net.IOCP.client");
	
	private Selector selector = null;
	private SocketChannel sc = null;
	
	private Charset charset = null;
	private CharsetDecoder decoder = null;
	
	public SimpleChatClient() {
		charset = Charset.forName("EUC-KR");
		decoder = charset.newDecoder();
	}
	
	public void initServer() {
		
		try {
			
			//open Selector
			selector = Selector.open();
			
			//¼ÒÄÏÃ¤³ÎÀ» »ý¼ºÇÑ´Ù.
			
			sc = SocketChannel.open(new InetSocketAddress(HOST, PORT));
			
			//ºñ ºí·ÏÅ· ¸ðµå·Î ¼³Á¤ÇÑ´Ù.
			sc.configureBlocking(false);
			
			//¼­¹ö¼ÒÄÏ Ã¤³ÎÀ» ¼¿·ºÅÍ¿¡ µî·ÏÇÑ´Ù.
			sc.register(selector, SelectionKey.OP_READ);
		}
		catch (IOException ex) {
			log(Level.WARNING, "SimpleChatClient.initServer()", ex);
		}
	}
	
	public void startServer() {
		startWriter();
		startReader();
	}
	
	private void startWriter() {

		info("Writer is started...");
		Thread t = new MyThread(sc);
		t.start();
	}

	private void startReader() {

		info("Reader is started..");
		try {
			
			while (true){
				info("¿äÃ»À» ±â´Ù¸®´ÂÁß...");
				
				//¼¿·ºÅÍÀÇ select() ¸Þ¼Òµå·Î ÁØºñµÈ ÀÌº¥Æ®°¡ ÀÖ´ÂÁö È®ÀÎÇÑ´Ù.
				
				selector.select();
				
				//¼¿·ºÅÍÀÇ SelectoedSet¿¡ ÀúÀåµÈ ÁØºñµÈ ÀÌº¥Æ®µé(SelectionKey)À» ÇÏ³ª¾¿ Ã³¸®ÇÑ´Ù.
				Iterator it = selector.selectedKeys().iterator();
				
				while (it.hasNext()) {
					
					SelectionKey key = (SelectionKey)it.next();
					
					if (key.isReadable()) {
						// ÀÌ¹Ì ¿¬°áµÈ Å¬¶óÀÌ¾ðÆ®°¡ ¸Þ½ÃÁö¸¦ º¸³½°æ¿ì...
						read(key);
					}
					
					//ÀÌ¹Ì Ã³¸®ÇÑ ÀÌº¥Æ®¹Ç·Î ¹Ýµå½Ã »èÁ¦ÇØÁØ´Ù.
					it.remove();
				}
			}
		}
		catch (Exception ex) {
			log(Level.WARNING ,"SimpleChatClient.startServer()", ex);
		}
	}
	
	
	private void read(SelectionKey key) {
		
		//SelectionKey·ÎºÎÅÍ ¼ÒÄÏÃ¤³ÎÀ» ¾ò¾î¿Â´Ù.
		
		SocketChannel sc = (SocketChannel)key.channel();
		//ByteBuffer¸¦ »ý¼ºÇÑ´Ù.
		ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
		int read = 0;
		
		try {
			
			//¿äÃ»ÇÑ Å¬¶óÀÌ¾ðÆ®ÀÇ ¼ÒÄÏÃ¤³Î·ÎºÎÅÍ µ¥ÀÌÅÍ¸¦ ÀÐ¾îµéÀÎ´Ù.
			read = sc.read(buffer);
			info(read + " byte¸¦ ÀÐ¾ú½À´Ï´Ù.");
		} catch (IOException ex) {
			try {
				sc.close();
			}catch (IOException ex1) {
				
			}
		}
		
		buffer.flip();
		
		String data = new String();
		
		try {
			data = decoder.decode(buffer).toString();
		} catch (CharacterCodingException ex) {
			log(Level.WARNING, "SimpleChatClient.read()", ex);
		}
		
		System.out.println("Message - " + data);
		
		//¹öÆÛ ¸Þ¸ð¸®¸¦ ÇØÁ¦ÇÑ´Ù.
		clearBuffer(buffer);
	}

	private void clearBuffer(ByteBuffer buffer) {

		if (buffer != null) {
			buffer.clear();
			buffer = null;
		}
		
	}
	
	/**
	 * Log
	 */

	public void initLog() {
		try {
			fileHandler = new FileHandler("SimpleChatClient.log");
		} catch (IOException ex) {
			logger.addHandler(fileHandler);
			logger.setLevel(Level.ALL);
		}
	}
	
	public void log(Level level, String msg, Throwable error) {
		logger.log(level, msg, error);
	}
	
	
	public void info(String msg) {
		logger.info(msg);
	}
	
	class MyThread extends Thread {
		
		private SocketChannel sc = null;
		public MyThread(SocketChannel sc) {
			this.sc = sc;
		}
		
		public void run() {
			
			ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
			
			try {
				
				while (!Thread.currentThread().isInterrupted()) {
					
					buffer.clear();
					BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
					String message = in.readLine();
					
					if (message.equals("quit") || message.equals("shutdown")) { 
						System.exit(0);
					}
					
					buffer.put(message.getBytes());
					buffer.flip();
					
					sc.write(buffer);
				}
			}
			catch (Exception ex) {
				log(Level.WARNING, "MyThread.run()", ex);
			}
			finally {
				clearBuffer(buffer);
			}
		}
	}
	
	/**
	 * main
	 */
	
	public static void main(String[] args) {
		SimpleChatClient scc = new SimpleChatClient();
		scc.initLog();
		scc.initServer();
		scc.startServer();
	}
}
