/* ***************************************************************************+
 * ITX package (cnrg.itx) for telephony application programming.              *
 * Copyright (c) 1999  Cornell University, Ithaca NY.                         *
 * A copy of the license is distributed with this package.  Look in the docs  *
 * directory, filename GPL.  Contact information: bergmark@cs.cornell.edu     *
 ******************************************************************************/


package cnrg.itx.datax.devices;

/**
 * Class to implement the forward error correction mechanism. This class will
 * be used to construct FEC buffers from single byte buffers.
 * (July 1999 addition) No created buffer will be less than 1 byte in size.
 */
class FECBuffer
{
	/**
	 * Constant for specifying the number of packets to be used for
	 * Forward Error Correction.
	 */
	private static final int numFECPackets = 3;
	
	/**
	 * Attribute for storing the previous packets sent for Forward Error
	 * Correction.
	 */
	byte[][] fecBuffer;

	/**
	 * attribute to hold packet size.
	 */
	private int iPacketSize;
	
	/**
	 * Constant for the value of a silence byte.
	 */
	private static final byte SILENCE = 127;
	
	/**
	 * Default constructor for the FECBuffer object.
	 */
	public FECBuffer(int iPacketSize)
	{
		this.iPacketSize = iPacketSize;
		
		// Initialize the size of the buffer and put in silence values as
		// the initial packets.
		fecBuffer = new byte[numFECPackets][];
		
		for (int i=0; i<numFECPackets; i++)
		{
			fecBuffer[i] = new byte[iPacketSize];
			
			for (int j=0; j<iPacketSize; j++)
			{
				fecBuffer[i][j] = SILENCE;
			}
		}	
	}
	
	/**
	 * Accessor to get the number of FEC packets.
	 * @return int the number of FEC packets
	 */
	public int getNumFECPackets()
	{
		return numFECPackets;
	}
	
	/**
	 * Method to get one of the buffers from the FEC buffer.
	 * @param index the index of the buffer to get
	 * @return byte[] the corresponding byte array for the buffer
	 */
	public byte[] getBuffer(int index)
	{
		return fecBuffer[index];
	}
	
	/**
	 * Method to construct a FEC packet from a buffer.
	 * @param packet the buffer that needs to be forward error corrected
	 * @return byte[] the forward error corrected byte array
	 */
	public byte[] pack(byte[] packet)
	{
		// Shift the byte arrays by one position down and insert the current
		// packet as the first one
		for (int i=numFECPackets-1; i>0; i--)
		{
			fecBuffer[i] = fecBuffer[i-1];
		}
		
		// Insert the primary packet in the first slot
		fecBuffer[0] = packet;
		
		// Put in the amount of space needed for storing the buffer sizes
		int packetSize = 2*numFECPackets;
		
		// Add the number of buffer lengths in the fecBuffer
		for (int i=0; i<numFECPackets; i++)
		{
			packetSize += fecBuffer[i].length;
		}
		
		// Make the new buffer
		byte[] fecPacket = new byte[packetSize];
			
		// Initialize index to point to skip the buffer lenght and point to
		// the data area of the first buffer.
		int index = 2*numFECPackets;
		
		// Copy the all the buffers
		for (int i=0; i<numFECPackets; i++)
		{
			// Put in the buffer size at the appropriate place in the FEC packet
			setShort(fecPacket, 2*i, (short)fecBuffer[i].length);
			
			// Copy the buffer to the FEC packet
			System.arraycopy(fecBuffer[i], 0, fecPacket, index, fecBuffer[i].length);
			index += fecBuffer[i].length;
		}
		
		// Return the FEC packet
		return fecPacket;
	}
	
	/**
	 * Method to put in a FEC packet and split it into its components.
	 * @param fecPacket the byte array for all the packets
	 * @return byte[] the primary packet from the FEC array
	 */
	public byte[] unpack(byte[] fecPacket)
	{
		// Initialize index to skip the buffer length fields and point to the
		// data of the first buffer in the FEC packet
		int index = 2*numFECPackets;
		
		for (int i=0; i<numFECPackets; i++)
		{
			// Get the size of the packet in bytes
			int packetSize = getShort(fecPacket, 2*i);
			
			// Make the new byte array
			fecBuffer[i] = new byte[packetSize];
			
			// Fill the array with the data
			System.arraycopy(fecPacket, index, fecBuffer[i], 0, packetSize);
			index += packetSize;

		}
		
		// Return the primary buffer which is the first one
		return fecBuffer[0];
	}
	
	/**
	 * Method to set a short(16 bit) value in a byte array.
	 * @param packet the byte array to put the value in
	 * @param pos the position at which the bytes need to be put
	 * @param value the short value to be put
	 */
	private void setShort(byte[] packet, int pos, short value)
	{
		packet[pos+0] = (byte)(value >> 8);
		packet[pos+1] = (byte)(value);
	}

	/**
	 * Method to get a short(16 bit) value from a position in a byte array.
	 * @param packet the byte array to get the value from
	 * @param pos the position from which to get the 16 bit value
	 */
	private short getShort(byte[] packet, int pos)
	{
		return (short)((((int)(packet[pos+0]) << 8) & 0x0000ff00) +
					   (((int)(packet[pos+1]) << 0) & 0x000000ff));
	}
}
