package com.cwjcsu.learning.network.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * 
 * @author atlas
 * @date 2012-9-27
 */
public class ChargenServer {

	public static int DEFAULT_PORT = 1025;

	public static void main(String[] args) {

		int port;

		try {

			port = Integer.parseInt(args[0]);

		}

		catch (Exception ex) {

			port = DEFAULT_PORT;

		}

		System.out.println("Listening for connections on port " + port);

		byte[] rotation = new byte[95 * 2];

		for (byte i = ' '; i <= '~'; i++) {

			rotation[i - ' '] = i;

			rotation[i + 95 - ' '] = i;

		}

		ServerSocketChannel serverChannel;

		Selector selector;

		try {

			serverChannel = ServerSocketChannel.open();

			ServerSocket ss = serverChannel.socket();

			InetSocketAddress address = new InetSocketAddress(port);

			ss.bind(address);

			serverChannel.configureBlocking(false);

			selector = Selector.open();

			serverChannel.register(selector, SelectionKey.OP_ACCEPT);

		}

		catch (IOException ex) {

			ex.printStackTrace();

			return;

		}

		while (true) {

			try {

				selector.select();

			}

			catch (IOException ex) {

				ex.printStackTrace();

				break;

			}

			Set readyKeys = selector.selectedKeys();

			Iterator iterator = readyKeys.iterator();

			while (iterator.hasNext()) {

				SelectionKey key = (SelectionKey) iterator.next();

				iterator.remove();

				try {

					if (key.isAcceptable()) {

						ServerSocketChannel server = (ServerSocketChannel) key
								.channel();

						SocketChannel client = server.accept();

						System.out
								.println("Accepted connection from " + client);

						client.configureBlocking(false);

						SelectionKey key2 = client.register(selector,
								SelectionKey.OP_WRITE);

						ByteBuffer buffer = ByteBuffer.allocate(74);

						buffer.put(rotation, 0, 72);

						buffer.put((byte) '\r');

						buffer.put((byte) '\n');

						buffer.flip();

						key2.attach(buffer);

					}

					else if (key.isWritable()) {

						SocketChannel client = (SocketChannel) key.channel();

						ByteBuffer buffer = (ByteBuffer) key.attachment();

						if (!buffer.hasRemaining()) {

							// Refill the buffer with the next line

							buffer.rewind();

							// Get the old first character

							int first = buffer.get();

							// Get ready to change the data in the buffer

							buffer.rewind();

							// Find the new first characters position in
							// rotation

							int position = first - ' ' + 1;

							// copy the data from rotation into the buffer

							buffer.put(rotation, position, 72);

							// Store a line break at the end of the buffer

							buffer.put((byte) '\r');

							buffer.put((byte) '\n');

							// Prepare the buffer for writing

							buffer.flip();

						}

						client.write(buffer);

					}

				}

				catch (IOException ex) {

					key.cancel();

					try {

						key.channel().close();

					}

					catch (IOException cex) {
					}

				}

			}

		}

	}
}
