package org.jvirtanen.parity.system;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

class OrderEntry implements Runnable {

    private static final int TIMEOUT_MILLIS = 1000;

    private OrderEntryServer server;

    private List<Session> sessions;

    private List<Session> toClose;

    private Selector selector;

    private OrderEntry(OrderEntryServer server) throws IOException {
        this.server = server;

        this.sessions = new ArrayList<>();
        this.toClose  = new ArrayList<>();

        this.selector = Selector.open();

        this.server.getChannel().register(this.selector, SelectionKey.OP_ACCEPT, null);
    }

    public static OrderEntry create(int port) throws IOException {
        return new OrderEntry(OrderEntryServer.create(port));
    }

    @Override
    public void run() {
        int numKeys;

        while (true) {
            try {
                numKeys = selector.select(TIMEOUT_MILLIS);
            } catch (IOException e) {
                break;
            }

            if (numKeys > 0) {
                Iterator<SelectionKey> keys = selector.selectedKeys().iterator();

                while (keys.hasNext()) {
                    SelectionKey key = keys.next();

                    if (key.isAcceptable())
                        accept();

                    if (key.isReadable())
                        receive((Session)key.attachment());

                    keys.remove();
                }
            }

            keepAlive();

            cleanUp();
        }
    }

    private void accept() {
        try {
            Session session = server.accept();
            if (session != null) {
                sessions.add(session);

                session.getTransport().getChannel().register(selector, SelectionKey.OP_READ, session);
            }
        } catch (IOException e) {
        }
    }

    private void receive(Session session) {
        try {
            if (session.getTransport().receive() < 0)
                toClose.add(session);
        } catch (IOException e) {
            toClose.add(session);
        }
    }

    private void keepAlive() {
        for (int i = 0; i < sessions.size(); i++) {
            Session session = sessions.get(i);

            try {
                session.getTransport().keepAlive();

                if (session.hasHeartbeatTimeout())
                    toClose.add(session);
            } catch (IOException e) {
                toClose.add(session);
            }
        }
    }

    private void cleanUp() {
        for (int i = 0; i < toClose.size(); i++) {
            Session session = toClose.get(i);

            sessions.remove(session);

            try {
                session.getTransport().close();
            } catch (IOException e) {
            }
        }

        if (!toClose.isEmpty())
            toClose.clear();
    }

}

@@ -373,18 +373,20 @@
 on%3E 
-sessions;%0A
+toKeepAlive;
 %0A   
@@ -412,19 +412,21 @@
 on%3E toCl
-ose
+eanUp
 ;%0A%0A    p
@@ -565,24 +565,27 @@
    this.
-sessions
+toKeepAlive
  = new A
@@ -615,19 +615,22 @@
 his.toCl
-ose
+eanUp 
   = new 
@@ -1818,24 +1818,27 @@
         
-sessions
+toKeepAlive
 .add(ses
@@ -2137,35 +2137,37 @@
             toCl
-ose
+eanUp
 .add(session);%0A 
@@ -2207,35 +2207,37 @@
             toCl
-ose
+eanUp
 .add(session);%0A 
@@ -2311,24 +2311,27 @@
  0; i %3C 
-sessions
+toKeepAlive
 .size();
@@ -2368,24 +2368,27 @@
 ssion = 
-sessions
+toKeepAlive
 .get(i);
@@ -2527,35 +2527,37 @@
             toCl
-ose
+eanUp
 .add(session);%0A 
@@ -2613,19 +2613,21 @@
     toCl
-ose
+eanUp
 .add(ses
@@ -2725,19 +2725,21 @@
 i %3C toCl
-ose
+eanUp
 .size();
@@ -2780,19 +2780,21 @@
 n = toCl
-ose
+eanUp
 .get(i);
@@ -2811,16 +2811,19 @@
     
-sessions
+toKeepAlive
 .rem
@@ -2983,19 +2983,21 @@
 f (!toCl
-ose
+eanUp
 .isEmpty
@@ -3016,19 +3016,21 @@
     toCl
-ose
+eanUp
 .clear()

Improve naming in order entry server