import java.io.*;
import java.util.*;

/**
 * This class implements a buffer that rectifies some
 * problems with asynchronous receive of Lego messages.
 * For reasons that are not completely clear, messages
 * received over the IR interface, will sometimes be
 * broken up into mutiple chunks. The MessageListener
 * client will be notified upon reception of each chunk.
 * To relieve the client of the burdon to buffer and
 * later on assemble theses messages, this class is provided.
 * Message chunks are appended to the buffer using the 
 * append() method. The buffer uses the 0x55ff00 message
 * header as a frame sync to recognize message boundaries.
 * Clients will be notified only upon reception of complete
 * messages.
 */
public class MessageBuffer  {

    private byte[] buf = new byte[128];
    int index = 0;
    private boolean flush = false;
    Vector listeners = new Vector();

    /** add an asynchronous message listener */
    public void addMessageListener(MessageListener l) {
        listeners.addElement(l);
    }

    /** remove an asynchronous message listener */
    public void removeMessageListener(MessageListener l) {
        listeners.removeElement(l);
    }

    /** add a message chunk to the buffer */
    public synchronized void append(byte[] suffix) throws IOException {
        if (index + suffix.length >= buf.length) {
            System.out.println("ERROR: MessageBuffer receive buf full!");
            System.out.println("Probable cause: ambient light interference with IR.");
            throw new RuntimeException("ReceiveBufferOverflow");
        }

        System.arraycopy(suffix, 0, buf, index, suffix.length);
        index += suffix.length;

        // Brick.printMessage("MessageBuffer.append(): buf is now", buf);

        byte[] msg;
        while ((msg = getMsg()) != null) {
            for (int i=0; i= 3 && buf[i] == (byte)0x55 
                && buf[i+1] == (byte)0xff && buf[i+2] == (byte)0x00) {
                return i;
            }
        }

        return -1;
    }

    private byte[] unwrap(byte[] wrapped) {
	if (wrapped.length < 7) return null;

        byte[] msg = new byte[(wrapped.length - 5)/2];
        for (int i=0; i 0) {
            int size = Math.min(buf.length, nextHeader);
            byte[] msg = new byte[size];

            System.arraycopy(buf, 0, msg, 0, size);
            System.arraycopy(buf, size, buf, 0, buf.length - size);
            index -= size;
            // Brick.printMessage("MessageBuffer.getMsg(): buf is now", buf);

            flush = false;
            return unwrap(msg);
        }

        return null;
    }
}