/*
 * LineReader.java
 *
 * Created on March 16, 2003, 3:55 PM
 */

package com.jscape.util;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

/**
 * @author vglass
 */
public class LineReader
        extends FilterInputStream {

    private char[] delim = { '\r', '\n' };
    private boolean hasDelimiter = false;
    private boolean endOfStream = false;

    /**
     * Constructs a new LineReader instance.
     *
     * @param in the InputStream this LineReader is to reading from.
     */
    public LineReader(InputStream in) {
        super(in);
    }

    /**
     * Constructs a new LineReader instance.
     * Default line terminator is CRLF (carriage return followed by a line feed).
     *
     * @param in    the InputStream this LineReader is to reading from.
     * @param delim a char[] representing the line terminator
     */
    public LineReader(InputStream in, char[] delim) {
        this(in);
        this.delim = delim;
    }

    /**
     * Checks if last line reading was terminated with delimiter.
     *
     * @return true if terminated with delimiter, false otherwise.
     */
    public boolean hasDelimiter() {
        return hasDelimiter;
    }

    /**
     * Reads line from InputStream.
     *
     * @param encoding the character encoding to use when reading converting data to a String
     *
     * @return returns line reading or null if end of InputStream reached
     *
     * @throws IOException if an I/O related error occurs
     */
    public String readLine(String encoding)
            throws IOException {
        hasDelimiter = false;
        ByteBuffer buffer = new ByteBuffer();
        int count = 0;

        if (endOfStream) {
            return null;
        }

        while (true) {
            if (endOfStream) {
                break;
            }

            int b = in.read();

            // check for end of stream
            if (b == -1) {
                endOfStream = true;
                break;
            }

            // appending byte to buffer
            buffer.append((byte) b);

            // check if delimiter found
            if (delim[count] == b) {
                count++;
            } else {
                // reset counter
                if (count != 0) {
                    count = 0;
                }

                // check again for match
                if (delim[count] == b) {
                    count++;
                }
            }

            // all delimiters match
            if (count == delim.length) {
                hasDelimiter = true;
                break;
            }
        }

        // build result
        byte[] data = null;

        if (hasDelimiter) {
            if (endOfStream && buffer.length() == delim.length) {
                return null;
            } else {
                data = new byte[buffer.length() - delim.length];
            }
        } else {
            data = new byte[buffer.length()];
        }
        System.arraycopy(buffer.toByteArray(), 0, data, 0, data.length);

        // return result
        if (encoding != null) {
            return new String(data, Charset.forName(encoding));
        } else {
            return new String(data, Charset.defaultCharset());
        }
    }


    /**
     * Reads line from InputStream
     *
     * @return returns line reading or a String of zero length if end of InputStream reached
     *
     * @throws IOException if an I/O related error occurs
     */
    public String readLine()
            throws IOException {
        return readLine(null);
    }

}

