package pw.koj.jetstreem.core;

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

public class StrmIOLoop extends Thread {
    private Selector selector;
    private StrmQueue taskQueue;

    private StrmIOLoop () {
        super();
        try {
            this.selector = Selector.open();
        } catch (IOException ex) {
            System.err.println("I/O error: " + ex.getMessage());
        }
        this.taskQueue = StrmQueue.getInstance();
    }

    public static StrmIOLoop initIOLoop() {
        StrmIOLoop loop = new StrmIOLoop();
        return loop;
    }

    public void closeIOLoop() {
        this.interrupt();
    }

    public Selector selector() {
        return this.selector;
    }

    public StrmQueue taskQueue() {
        return this.taskQueue;
    }

    public void ioPush(ChannelBuffer cbuf, Streem strm, StrmFunc cb, int key) 
        throws ClosedChannelException, IOException {
        StrmIOTask task = new StrmIOTask(strm, cb);
        SelectableChannel ch = (SelectableChannel)cbuf.ch();
        ch.configureBlocking(false);
        ch.register(this.selector, key, task);
    }

    public void ioStart(Streem strm, ChannelBuffer cbuf, StrmFunc cb, int key) {
        try {
            ioPush(cbuf, strm, cb, key);
        } catch (ClosedChannelException ex) {
            System.err.println("Channel error: " + ex.getMessage());
        } catch (IOException ex) {
            System.err.println("I/O error: " + ex.getMessage());
        }
    }

    public void ioStop(Streem strm, ChannelBuffer cbuf) {
        SelectableChannel ch = (SelectableChannel)cbuf.ch();
        SelectionKey key = ch.keyFor(this.selector);
        key.cancel();
    }

    public void run() {
        try {
            while (this.selector.select() > 0) {
                Set<SelectionKey> keys = this.selector.selectedKeys();
                for (Iterator<SelectionKey> it = keys.iterator(); it.hasNext(); ) {
                    SelectionKey key = it.next();
                    it.remove();
                    StrmIOTask task = (StrmIOTask)key.attachment();
                    key.cancel();  // one shot
                    taskQueue.push(task.strm(), task.func(), null);
                }
            }
        } catch (ClosedChannelException ex) {
            System.err.println("I/O channel is closed!");
        } catch (IOException ex) {
            System.err.println("I/O error: " + ex.getMessage());
        } finally {
            try {
                for (SelectionKey key: this.selector.keys()) {
                    key.channel().close();
                }
            } catch (IOException ex) {
                System.err.println("I/O error: " + ex.getMessage());
            }
        }
    }
}




@@ -282,16 +282,56 @@
 hread %7B%0A
+    private static StrmIOLoop instance;%0A
     priv
@@ -349,24 +349,24 @@
 r selector;%0A
-
     private 
@@ -691,18 +691,19 @@
 oop 
-initIOLoop
+getInstance
 () %7B
@@ -715,23 +715,51 @@
     
-StrmIOLoop loop
+if (instance == null) %7B%0A           instance
  = n
@@ -787,19 +787,33 @@
     
-return loop
+%7D%0A        return instance
 ;%0A  
@@ -983,24 +983,24 @@
 skQueue() %7B%0A
-
         retu
@@ -1017,32 +1017,127 @@
 skQueue;%0A    %7D%0A%0A
+    public boolean hasNoRegistrant() %7B%0A        return this.selector().keys().isEmpty();%0A    %7D%0A%0A
     public void 

add hasNoRegistrant() to StrmIOLoop