import java.io.*;


/**
 *  For reading input streams using the SFP protocol
 *
 *  @version 1.0
 *  @author  Prof. David Bernstein, James madison University
 */
public class SFPInputStream extends InputStream
{
    protected int              available, dataLength;
    protected int              frameType, sequenceNumber;
    protected DataInputStream  in;




    /**
     * Construct a new SFPInputStream
     *
     * @param in   The InputStream to use
     */

    public SFPInputStream(InputStream in)
    {
       this.in = new DataInputStream(in);
       available = 0;
    }




    /**
     * Returns the number of bytes available without blocking
     *
     */
    public int available() throws IOException
    {
       return available;
    }



    /**
     * Decode an array of bytes
     *
     * This version does nothing
     */
    protected void  decode(byte[] b)
    {
       // Do nothing
    }







    /**
     * Get the frame type of the most recently/current message
     * (See SFPConnection for valid frame types)
     *
     * @return  The frame type
     */
    public int getFrameType()
    {
       return frameType;
    }




    /**
     * Closes this input stream
     */
    public void close() throws IOException
    {
       in.close();
    }





    /**
     * Tests if this input stream supports the mark and reset methods
     */
    public boolean markSupported()
    {
       return false;
    }



    /**
     * Reads the next byte of data
     */
    public int read() throws IOException
    {
       byte[] b;
       int    retval;

       b = new byte[1];
       if (available == 0) readHeader();
       retval = read(b,0,1);
       if (retval > 0) retval = (int)(b[0]);

       return retval;
    }





    /**
     * Reads an array of bytes
     *
     * @param b   The buffer into which the data are read
     * @param off The start offset of the data
     * @param len The maximum number of bytes read
     *
     * @return    The number of bytes actually read or -1 if end-of-stream
     */
    public int read(byte[] b, int off, int len) throws IOException
    {
       byte[] tmp;
       int bytesRead, i, length;

       if (available == 0) readHeader();

       if (len < available) length = len;
       else                 length = available;

       tmp = new byte[length];
       bytesRead = in.read(tmp);
	
       // For future use
       decode(tmp);

       if (bytesRead < 0) available = 0;
       else 
       {
          available -= bytesRead;
          for (i=0; i < bytesRead; i++) 
          {
             b[i+off] = tmp[i];
          }
       }

       return bytesRead;
    }





    /**
     * Reads an array of bytes
     *
     * @param b   The buffer into which the data are read
     * @return    The number of bytes actually read or -1 if end-of-stream
     */
    public int read(byte[] b) throws IOException
    {
       if (available == 0) readHeader();
       return read(b, 0, b.length);
    }







    /**
     * Read the SFP header information
     */
    protected void readHeader() throws IOException
    {
       byte[] b;
       char   asterisk;

       b = new byte[2];


       asterisk = (char)(in.readByte());
       frameType = (int)(in.readByte());
       sequenceNumber = (int)(in.readShort());
       dataLength = (int)(in.readShort());

       available = dataLength;
    }






    /**
     * Skips over and discards a given number of bytes
     *
     * Note: Even though n is passed as a long, it is treated as an int
     *
     * @param n  The number of bytes to skip
     */
    public long skip(long n) throws IOException
    {
       byte[]  tmp;
       int     k;

       k = (int)n;
       tmp = new byte[k];


       return read(tmp);

    }

}
