package net.i2p.client.streaming.impl;

import net.i2p.I2PAppContext;
import net.i2p.util.Log;

/**
 * <p>Scheduler used for locally created connections where we have not yet
 * sent the initial SYN packet.</p>
 *
 * <h2>Entry conditions:</h2>
 * <ul>
 * <li>Locally created</li>
 * <li>No packets sent or received</li>
 * </ul>
 *
 * <h2>Events:</h2>
 * <ul>
 * <li>Message flush (explicitly, through a full buffer, or stream closure)</li>
 * <li>Initial delay timeout (causing implicit flush of any data available)</li>
 * </ul>
 *
 * <h2>Next states:</h2>
 * <ul>
 * <li>{@link SchedulerConnecting connecting} - after sending a packet</li>
 * </ul>
 */
class SchedulerPreconnect extends SchedulerImpl {
    
    public SchedulerPreconnect(I2PAppContext ctx) {
        super(ctx);
    }
    
    public boolean accept(Connection con) {
        return (con != null) && 
               (con.getSendStreamId() <= 0) &&
               (con.getLastSendId() < 0);
    }
    
    public void eventOccurred(Connection con) {
        if (con.getNextSendTime() < 0)
            con.setNextSendTime(_context.clock().now() + con.getOptions().getConnectDelay());
        
        long timeTillSend = con.getNextSendTime() - _context.clock().now();
        if (timeTillSend <= 0) {
            if (_log.shouldLog(Log.DEBUG))
                _log.debug("Send available for the SYN on " + con);
            con.sendAvailable();
            con.setNextSendTime(-1);
        } else {
            if (_log.shouldLog(Log.DEBUG))
                _log.debug("Wait " + timeTillSend + " before sending the SYN on " + con);
            reschedule(timeTillSend, con);
        }
    }
}
