package com.limegroup.gnutella.udpconnect;

import com.limegroup.gnutella.messages.BadPacketException;

/** 
 *  The keepalive message is used to ensure that any firewalls continue 
 *  to allow passage of UDP messages on the connection.  
 * 
 *  Information about the senders data window for buffered incoming data 
 *  and the highest received data packet is included in the otherwise 
 *  unused data space within the guid.  This will be required in the 
 *  case where Ack messages stop flowing because the data window space 
 *  has gone to zero and only KeepAliveMessages are flowing.  Once the 
 *  data window opens back up, Acks will again provide this information.
 */
public class KeepAliveMessage extends UDPConnectionMessage {

    private long _windowStart;
    private int  _windowSpace;

    /**
     * Construct a new KeepAliveMessage with the specified settings and data
     */
    public KeepAliveMessage(byte connectionID, 
      long windowStart, int windowSpace) {

        super(
          /* his connectionID                 */ connectionID, 
          /* opcode                           */ OP_KEEPALIVE, 
          /* Keepalive has no sequenceNumber  */ 0, 
          /* window Start and Space           */ 
          buildByteArray((int) windowStart & 0xffff, 
			(windowSpace < 0 ? 0 : windowSpace)),
          /* 2 short ints => 4 bytes          */ 4
          );
        _windowStart = windowStart;
        _windowSpace = windowSpace;
    }

    /**
     * Construct a new KeepAliveMessage from the network
     */
    public KeepAliveMessage(
      byte[] guid, byte ttl, byte hops, byte[] payload) 
      throws BadPacketException {

      	super(guid, ttl, hops, payload);

        // Parse the added windowStart and windowSpace information
        _windowStart = (long)
          getShortInt(guid[GUID_DATA_START],guid[GUID_DATA_START+1]);
        _windowSpace = 
          getShortInt(guid[GUID_DATA_START+2],guid[GUID_DATA_START+3]);
    }

    /**
     *  The windowStart is equivalent to the lowest unreceived sequenceNumber
     *  coming from the receiving end of the connection.  It is saying, I have 
     *  received everything up to one minus this. (Note: it rolls)
     */
    public long getWindowStart() {
        return _windowStart;
    }

    /**
     *  Extend the windowStart of incoming messages with the full 8 bytes
	 *  of state
     */
	public void extendWindowStart(long wStart) {
		_windowStart = wStart;
	}

    /**
     *  The windowSpace is a measure of how much more data the receiver can 
     *  receive within its buffer.  This number will go to zero if the 
     *  application on the receiving side is reading data slowly.  If it goes 
     *  to zero then the sender should stop sending.
     */
    public int getWindowSpace() {
        return _windowSpace;
    }

	public String toString() {
		return "KeepAliveMessage DestID:"+getConnectionID()+
          " start:"+_windowStart+" space:"+_windowSpace;
	}
}
