package net.i2p.internal;

import net.i2p.data.i2cp.I2CPMessage;
import net.i2p.data.i2cp.I2CPMessageReader;
import net.i2p.util.I2PThread;

/**
 * Get messages off an In-JVM queue, zero-copy.
 *
 * @author zzz
 * @since 0.8.3
 */
public class QueuedI2CPMessageReader extends I2CPMessageReader {
    private final I2CPMessageQueue in;

    /**
     * Creates a new instance of this QueuedMessageReader and spawns a pumper thread.
     */
    public QueuedI2CPMessageReader(I2CPMessageQueue in, I2CPMessageEventListener lsnr) {
        super(lsnr);
        this.in = in;
        _reader = new QueuedI2CPMessageReaderRunner();
        _readerThread = new I2PThread(_reader, "I2CP Internal Reader " + __readerId.incrementAndGet(), true);
    }

    protected class QueuedI2CPMessageReaderRunner extends I2CPMessageReaderRunner implements Runnable {

        public QueuedI2CPMessageReaderRunner() {
            super();
        }
        
        /**
         * Shuts the pumper down.
         */
        @Override
        public void cancelRunner() {
            super.cancelRunner();
            _readerThread.interrupt();
        }
        
        /**
         * Pumps messages from the incoming message queue to the listener.
         */
        @Override
        protected void run2() {
            while (_stayAlive) {
                while (_doRun) {
                    // do read
                    I2CPMessage msg = null;
                    try {
                        msg = in.take();
                        if (msg.getType() == PoisonI2CPMessage.MESSAGE_TYPE) {
                            _listener.disconnected(QueuedI2CPMessageReader.this);
                            cancelRunner();
                        } else {
                            _listener.messageReceived(QueuedI2CPMessageReader.this, msg);
                        }
                    } catch (InterruptedException ie) {
                        // hint that we probably should check the continue running flag
                    }
                }
                // ??? unused
                if (_stayAlive && !_doRun) {
                    // pause .5 secs when we're paused
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException ie) {
                        _listener.disconnected(QueuedI2CPMessageReader.this);
                        cancelRunner();
                    }
                }
            }
        }
    }
}
