package org.atea.nlptools.macroniser.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.NoSuchElementException;

/**
 * A simple buffered text file reader which can read characters from a file.
 *
 * @author John
 */
public class CharReader
{
    private static final int CHAR_BUFFER_SIZE = 4096;
    private char[] charBuffer;
    private BufferedReader reader;
    private int currentIndex;
    private int lastIndex;

    public CharReader(File file, String charsetEncoding)
        throws IOException
    {
        reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetEncoding));
        charBuffer = new char[CHAR_BUFFER_SIZE];
        currentIndex = lastIndex = 0;
    }

    /**
     * Returns true if the CharReader has another char in its input.
     * @return true if and only if this CharReader has another char.
     */
    public boolean hasNextChar()
    {
        if (currentIndex < lastIndex) {
            return true;
        }
        read();

        return currentIndex < lastIndex;
    }

    /**
     * Returns the next char from this CharReader.
     * @return the next char.
     * @throws NoSuchElementException if no more chars are available
     */
    public char nextChar() throws NoSuchElementException
    {
        checkIndex(currentIndex);
        return charBuffer[currentIndex++];
    }

    /**
     * Looks at the next char from this CharReader without removing it.
     * @return the next char.
     * @throws NoSuchElementException if no more chars are available
     */
    public char peek() throws NoSuchElementException
    {
        checkIndex(currentIndex);
        return charBuffer[currentIndex];
    }

    /**
     * Close the CharReader.
     */
    public void close()
    {
        try {
            reader.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Read a portion of characters into an array.
     */
    private void read()
    {
        try
        {
            lastIndex = reader.read(charBuffer, 0, charBuffer.length);
            currentIndex = 0;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * Throws a NoSuchElementException if the index is less then 0 or greater
     * then char buffer length.
     * @param index Index to check.
     * @throws NoSuchElementException if the index is less then 0 or greater
     * then the char buffer length.
     */
    private void checkIndex(int index) throws NoSuchElementException
    {
        if (index < 0 || index >= charBuffer.length) {
            throw new NoSuchElementException();
        }
    }
}
