package io.mycat.jcache.net;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedTransferQueue;

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

import io.mycat.jcache.context.JcacheContext;
import io.mycat.jcache.net.conn.Connection;


/**
 * 
 * @author liyanjun
 */
public final class NIOReactor extends Thread{
	private static final Logger logger = LoggerFactory.getLogger(NIOReactor.class);
	
	private final Selector selector;

	private final LinkedTransferQueue<Connection> registerQueue;

	public NIOReactor(String name) throws IOException {
		super.setName(name);
		this.selector = Selector.open();
		this.registerQueue = new LinkedTransferQueue<>();  // 这里不使用 ConcurrentLinkedQueue 的原因在于,可能acceptor 和reactor同时操作队列
	}
	
	/**
	 * 将新的连接请求 放到 reactor 的请求队列中,同时唤醒 reactor selector
	 * @param socketChannel
	 */
	final void registerNewClient(Connection conn) {
		registerQueue.offer(conn);
		selector.wakeup();
	}
	
	@Override
	public void run() {
		final Selector selector = this.selector;
		Set<SelectionKey> keys = null;
		int readys=0;
		for (;;) {
			try {
//				400/(readys+1)
				readys=selector.select(400);  //借鉴mycat-core
				if(readys==0) // 没有需要处理的事件时,处理新连接请求  注册 read 事件
				{
					handlerEvents(selector);  
					continue;
				}
				keys = selector.selectedKeys();
				for(SelectionKey key:keys)
				{
					Connection con = (Connection)key.attachment();
					logger.info("select-key-readyOps = {}, attachment = {}", key.readyOps(), con);
//					JcacheContext.getExecutor().execute(con);
					con.run();
				}
			} catch (Throwable e) {
				logger.warn(getName(), e);
			} finally {
				if (keys != null) {
					keys.clear();
				}
			}
			handlerEvents(selector); //处理完成事件后,处理新里连接请求 注册 read 事件
		}
	}

//	private void processEvents() {
// TODO 
//		if(events.isEmpty())
//		{
//			return;
//		}
//		Object[] objs=events.toArray();
//		if(objs.length>0)
//		{
//		for(Object obj:objs)
//		{
//			((Runnable)obj).run();
//		}
//		events.removeAll(Arrays.asList(objs));
//		}		
//	}

	private void handlerEvents(Selector selector)
	{
		try
		{
		register(selector);  //注册 selector  读写事件
		}catch(Exception e)
		{
			logger.warn("caught user event err:",e);
		}
	}
	
	/**
	 * 注册 io 读写事件
	 * @param selector
	 */
	private void register(Selector selector) {
		if (registerQueue.isEmpty()) {
			return;
		}
		Connection c = null;
		while ((c = registerQueue.poll()) != null) {
			try {
				c.register(selector);
			} catch (Throwable e) {
				logger.warn("register error ", e);
				c.close("register err");
			}
		}
	}
}