package com.tecspy.protocol;

import java.io.IOException;

import org.apache.log4j.Logger;

/**
 * Is fed with bytes from an input stream and issues complete messages. The
 * messages are terminated by a single end byte, "etx".
 *
 * @author Michael Erskine
 *
 */
public abstract class EtxMessageByteSink implements ByteSink {
    /** Standard log4j logger */
    protected static Logger log = Logger.getLogger(EtxMessageByteSink.class);

    /**
    * Currently forming message buffer - should be constructed to the expected
    * size of typical messages rather than the maximum
    */
    protected StringBuilder msg;

    /** Message end byte */
    protected byte etx = (byte) 0x03;

    /** Maximum message length */
    protected int maxmsg = 1000;

    /**
    * An indication of the number of bytes read. NB: not necessarily 100%
    * correct.
    */
    public long byteTotal = 0;

    /**
    * A subclass constructor must create the message buffer e.g.: -
    *
    * <code>
    * super();
    * etx = (byte) 0xFE;
    * maxmsg = 1000;
    * msg = new StringBuilder(1000);
    * </code>
    *
    */
    public EtxMessageByteSink() {
    }

    protected abstract void handleMsg();

    /*
    * (non-Javadoc)
    *
    * @see com.ketech.swim.ByteSink#processBytes(byte[], int)
    */
    public int processBytes(byte[] buf, int len) {
        // incrementing the byte total here rather than for each byte
        byteTotal += len;
        for (int i = 0; i < len; i++) { // foreach byte
            // we are waiting for data or etx
            if (buf[i] == etx) {
                // etx is a normal condition - flush
                handleMsg();
                msg.setLength(0);
            } else {
                // normal condition add byte to message
                char c = (char) buf[i];
                if (msg.length() >= maxmsg) {
                    // interested in how this condition is unit tested - somehow
                    // have a log4j logger log to somewhere inparticular that
                    // can be examined
                    log.error("maximum message length exceeded (" + maxmsg
                            + "): buffered data discarded");
                    msg.setLength(0);
                }
                msg.append(c);
            }
        }
        return len;
    }

    /*
    * (non-Javadoc)
    *
    * @see com.ketech.swim.ByteSink#processEof()
    */
    public abstract void processEof();

    /*
    * (non-Javadoc)
    *
    * @see com.ketech.swim.ByteSink#processException(java.io.IOException)
    */
    public abstract void processException(IOException e);
}