package jp.sourceforge.glad.io.iteration;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;

import jp.sourceforge.glad.collection.closure.Closure;
import jp.sourceforge.glad.collection.exception.BreakException;
import jp.sourceforge.glad.collection.exception.ContinueException;
import jp.sourceforge.glad.collection.iteration.IterationHandler;
import jp.sourceforge.glad.collection.iteration.IterationHandlerSupport;
import jp.sourceforge.glad.io.IORuntimeException;

public class LinesIterationHandler
        extends IterationHandlerSupport<String>
        implements IterationHandler<String> {

    private final BufferedReader reader;
    private final boolean close;

    public LinesIterationHandler(Reader reader) {
        this(getBufferedReader(reader), true);
    }

    public LinesIterationHandler(BufferedReader reader) {
        this(reader, true);
    }

    public LinesIterationHandler(Reader reader, boolean close) {
        this(getBufferedReader(reader), close);
    }

    public LinesIterationHandler(BufferedReader reader, boolean close) {
        this.reader = reader;
        this.close = close;
    }

    static BufferedReader getBufferedReader(Reader reader) {
        if (reader instanceof BufferedReader) {
            return (BufferedReader) reader;
        } else {
            return new BufferedReader(reader);
        }
    }

    protected void doIterate(Closure<String> callback) throws Exception {
        String line;
        while ((line = reader.readLine()) != null) {
            try {
                callback.execute(line);
            } catch (ContinueException e) {
                continue;
            } catch (BreakException e) {
                break;
            }
        }
    }

    @Override
    protected void close() throws IOException {
        if (close) {
            reader.close();
        }
    }

    @Override
    protected void handleCheckedException(Exception e) {
        if (IOException.class.isInstance(e)) {
            handleIOException(IOException.class.cast(e));
        } else {
            super.handleCheckedException(e);
        }
    }

    protected void handleIOException(IOException e) {
        throw new IORuntimeException(e);
    }

}
