package edu.ouc.reactor;

import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EventLoop extends Thread{
	
	private static final Logger LOG = LoggerFactory.getLogger(EventLoop.class);
	
	private Selector selector;
	
    EventLoop(){
        try {
        	selector = Selector.open();
		} catch (IOException e) {
			throw new RuntimeException("failed to open a new selector", e);
		}
    }
    
    public SelectionKey register(final SelectableChannel sc, final int interestOps, Object attachment){
    	if(sc == null){
    		throw new NullPointerException("SelectableChannel");
    	}
    	if(interestOps == 0){
    		throw new IllegalArgumentException("interestOps must be non-zero.");
    	}
    	SelectionKey key;
    	try {
			key = sc.register(getSelector(), interestOps, attachment);
		} catch (ClosedChannelException e) {
			throw new RuntimeException("failed to register a channel", e);
		}
    	return key;
    }
    
	public void close(){
		try {
			getSelector().close();
			if(LOG.isDebugEnabled()){
				LOG.debug("Close selector");
			}
		} catch (IOException e) {
			LOG.warn("Ignoring exception during close selector, e=" + e);
		}
	}
    
	private int wakenUp;
	
	@Override
	public void run() {
		for(;;){
			try {
				getSelector().select(wakenUp);
				Set<SelectionKey> keys;
				synchronized(this){
					keys = getSelector().selectedKeys();
				}
				processSelectedKeys(keys);
				
			} catch (Throwable e) {
				LOG.warn("Unexpected exception in the selector loop.", e);
				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e1) {	}
			}
		}
	}
	private void processSelectedKeys(Set<SelectionKey> keys){
		if(keys.isEmpty()){
			return;
		}
		Iterator<SelectionKey> it = keys.iterator();
		while(it.hasNext()){
			SelectionKey key = it.next();
			dispatch(key);
			it.remove();
		}
	}
	
	public void dispatch(SelectionKey key){
		Runnable r = (Runnable)key.attachment();
		if(r != null)
			r.run();
	}

	public Selector getSelector() {
		return selector;
	}
}

@@ -42,32 +42,61 @@
 o.IOException;%0D%0A
+import java.nio.ByteBuffer;%0D%0A
 import java.nio.
@@ -520,16 +520,218 @@
 or;%0D%0A%09%0D%0A
+%09private Handler DEFAULT_HANDLER = new Handler()%7B%0D%0A%09%09@Override%0D%0A%09%09public void processRequest(Processor processor, ByteBuffer msg) %7B%0D%0A%09%09%09//NOOP%0D%0A%09%09%7D%0D%0A%09%7D;%0D%0A%09private Handler handler = DEFAULT_HANDLER;%0D%0A%09%0D%0A
     Even
@@ -2525,16 +2525,174 @@
 %0D%0A%09%7D%0D%0A%0D%0A
+%09public void processRequest(Processor processor, ByteBuffer msg)%7B%0D%0A%09%09if(handler != DEFAULT_HANDLER)%7B%0D%0A%09%09%09handler.processRequest(processor, msg);%0D%0A%09%09%7D%0D%0A%09%7D%0D%0A%09%0D%0A
 %09public 

add Handler for extention