package org.voovan.network.nio;

import org.voovan.network.EventTrigger;
import org.voovan.network.MessageLoader;
import org.voovan.network.SocketContext;
import org.voovan.tools.ByteBufferChannel;
import org.voovan.tools.TByteBuffer;
import org.voovan.tools.TObject;
import org.voovan.tools.log.Logger;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * 事件监听器
 * 
 * @author helyho
 *
 * Voovan Framework.
 * WebSite: https://github.com/helyho/Voovan
 * Licence: Apache v2 License
 */
public class NioSelector {
	
	private Selector selector;
	private SocketContext socketContext;
	private ByteBufferChannel netByteBufferChannel;
	private ByteBufferChannel appByteBufferChannel;
	private NioSession session;
	
	/**
	 * 事件监听器构造
	 * @param selector   对象Selector
	 * @param socketContext socketContext 对象
	 */
	public NioSelector(Selector selector, SocketContext socketContext) {
		this.selector = selector;
		this.socketContext = socketContext;
		if (socketContext instanceof NioSocket){
			this.session = ((NioSocket)socketContext).getSession();
			this.appByteBufferChannel = session.getByteBufferChannel();
			netByteBufferChannel = new ByteBufferChannel(session.socketContext().getBufferSize());
		}

	}

	/**
	 * 所有的事件均在这里触发
	 */
	public void eventChose() {
		//读取用的缓冲区
		ByteBuffer readTempBuffer = ByteBuffer.allocateDirect(socketContext.getBufferSize());
		
		if (socketContext instanceof NioSocket) {
			// 连接完成onConnect事件触发
			EventTrigger.fireConnectThread(session);
		}
		
		// 事件循环
		try {
			while (socketContext != null && socketContext.isConnected()) {
				if (selector.select(1000) > 0) {
					Set<SelectionKey> selectionKeys = selector.selectedKeys();
					Iterator<SelectionKey> selectionKeyIterator = selectionKeys
							.iterator();
					while (selectionKeyIterator.hasNext()) {
						SelectionKey selectionKey = selectionKeyIterator.next();
						if (selectionKey.isValid()) {
							// 获取 socket 通道
							SocketChannel socketChannel = getSocketChannel(selectionKey);
							if (socketChannel.isOpen() && selectionKey.isValid()) {
								// 事件分发,包含时间 onRead onAccept
								
								switch (selectionKey.readyOps()) {
									// Server接受连接
									case SelectionKey.OP_ACCEPT: {
										NioServerSocket serverSocket = (NioServerSocket)socketContext;
										NioSocket socket = new NioSocket(serverSocket,socketChannel);
										session = socket.getSession();
										EventTrigger.fireAcceptThread(session);
										break;
									}
									// 有数据读取
									case SelectionKey.OP_READ: {
                                            int readSize = socketChannel.read(readTempBuffer);
											//判断连接是否关闭
											if(MessageLoader.isRemoteClosed(readTempBuffer, readSize) && session.isConnected()){

												session.getMessageLoader().setStopType(MessageLoader.StopType.STREAM_END);
												//如果 Socket 流达到结尾,则关闭连接
												while(session.isConnected()) {
													if (session.getByteBufferChannel().size() == 0) {
														session.close();
													}
												}
												break;
											}else if(readSize>0){
												readTempBuffer.flip();
												// 接收数据
												if(session.getSSLParser()!=null && session.getSSLParser().isHandShakeDone()){
													netByteBufferChannel.writeEnd(readTempBuffer);
													session.getSSLParser().unWarpByteBufferChannel(session, netByteBufferChannel, appByteBufferChannel);
												}else{
													appByteBufferChannel.writeEnd(readTempBuffer);
												}
												readTempBuffer.clear();
											}

											readTempBuffer.clear();

											// 触发 onRead 事件,如果正在处理 onRead 事件则本次事件触发忽略
											EventTrigger.fireReceiveThread(session);
										break;
									}
									default: {
										Logger.debug("Nothing to do ,SelectionKey is:"
												+ selectionKey.readyOps());
									}
								}
								selectionKeyIterator.remove();
							}
						}
					}
				}
			}
		} catch (IOException e) {
			if((e instanceof AsynchronousCloseException) ||
					(e instanceof ClosedChannelException)){
				return;
			}

			if(e instanceof Exception){
				//触发 onException 事件
				EventTrigger.fireExceptionThread(session, e);
			}
		} finally{
			// 触发连接断开事件
			if(session!=null) {
				EventTrigger.fireDisconnect(session);
				TByteBuffer.release(readTempBuffer);
			}
		}
	}

	/**
	 * 获取 socket 通道
	 * 
	 * @param selectionKey  当前 Selectionkey
	 * @return SocketChannel 对象
	 * @throws IOException  IO 异常
	 */
	public SocketChannel getSocketChannel(SelectionKey selectionKey)
			throws IOException {
		SocketChannel socketChannel = null;
		// 取得通道
		Object unknowChannel = selectionKey.channel();
		//  根据通道的类来判断类型是 ServerSocketChannel 还是 SocketChannel
		if (unknowChannel instanceof ServerSocketChannel) {
			ServerSocketChannel serverSocketChannel = TObject.cast( unknowChannel );
			socketChannel = serverSocketChannel.accept();
		} else if (unknowChannel instanceof SocketChannel) {
			socketChannel = TObject.cast( unknowChannel );
		}
		return socketChannel;
	}

	public void release(){
		netByteBufferChannel.release();
	}
}

@@ -4149,16 +4149,156 @@
 ;%0A%09%09%09%7D%0A%0A
+%09%09%09//%E5%85%BC%E5%AE%B9 windows %E7%9A%84 %22java.io.IOException: %E6%8C%87%E5%AE%9A%E7%9A%84%E7%BD%91%E7%BB%9C%E5%90%8D%E4%B8%8D%E5%86%8D%E5%8F%AF%E7%94%A8%22 %E9%94%99%E8%AF%AF%0A%09%09%09if(e.getStackTrace()%5B0%5D.getClassName().contains(%22sun.nio.ch%22))%7B%0A%09%09%09%09return;%0A%09%09%09%7D%0A%0A
 %09%09%09if(e 

修复了 Windows 下的操作异常