/* 
 * E-XML Library:  For XML, XML-RPC, HTTP, and related.
 * Copyright (C) 2002-2008  Elias Ross
 * 
 * genman@noderunner.net
 * http://noderunner.net/~genman
 * 
 * 1025 NE 73RD ST
 * SEATTLE WA 98115
 * USA
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * $Id$
 */

package net.noderunner.http;

import java.io.IOException;
import java.io.InputStream;

/**
 * An InputStream wrapper which allows only a certain number of bytes to be
 * read. This is used in conjunction reading from HTTP requests or responses
 * with supplied <code>Content-Length</code> headers. This stream is
 * unsynchronized.
 * 
 * @author Elias Ross
 * 
 * @see LimitedOutputStream
 * 
 */
public class LimitedInputStream extends InputStream {

	/**
	 * Number of bytes that can be read.
	 */
	private int remaining;

	/**
	 * The underlying input stream.
	 */
	private InputStream stream;

	/**
	 * Constructs a limited input stream.
	 * 
	 * @param stream
	 *            Must be non-null.
	 * @param lengthLimit
	 *            limit of bytes of input.
	 */
	public LimitedInputStream(InputStream stream, int lengthLimit) {
		if (stream == null)
			throw new IllegalArgumentException("InputStream parameter is null");
		this.stream = stream;
		this.remaining = lengthLimit;
	}

	/**
	 * Closes the underlying input stream.
	 */
	public void close() throws IOException {
		stream.close();
	}

	/**
	 * Reads up to <code>len</code> bytes of data from the input stream into
	 * an array of bytes, possibly less if the read limit is reached.
	 */
	public int read(byte b[], int off, int len) throws IOException {
		if (remaining == 0)
			return -1;
		if (len > remaining)
			len = remaining;
		int got = stream.read(b, off, len);
		if (got != -1)
			remaining -= got;
		return got;
	}

	/** Calls the wrapped stream. */
	public int available() throws IOException {
		return stream.available();
	}

	/** Calls the wrapped stream. */
	public boolean markSupported() {
		return stream.markSupported();
	}

	/** Calls the wrapped stream. */
	public void reset() throws IOException {
		stream.reset();
	}

	/** Calls the wrapped stream. */
	public void mark(int readlimit) {
		stream.mark(readlimit);
	}

	/**
	 * Reads and returns a single byte from this input stream, or -1 if end of
	 * file or the read limit has been encountered.
	 */
	public int read() throws IOException {
		if (remaining == 0)
			return -1;
		int r = stream.read();
		if (r != -1)
			remaining--;
		return r;
	}

	/**
	 * Returns a debug string.
	 */
	public String toString() {
		return "LimitedInputStream " + " stream=" + stream + " remaining=" + remaining;
	}
}
