define('jls/io/BufferedInputStream', [
  'jls/lang/Class',
  'jls/lang/Exception',
  'jls/lang/ByteBuffer',
  'jls/lang/BufferOverflowException'
], function (
  Class,
  Exception,
  ByteBuffer,
  BufferOverflowException
) {

var BufferedInputStream;
BufferedInputStream = Class.create( /** @lends jls.io.BufferedInputStream.prototype */
{
    /**
     * Creates a BufferedInputStream.
     * 
     * @param {jls.io.InputStream} input The underlying byte input stream.
     * @param {Number} size The buffer size.
     * @constructs
     * @class A character reader for byte input stream.
     */
    initialize : function(input, size) {
        this._in = input;
    	this._buffer = ByteBuffer.allocate(size || 1024);
        this._buffer.setLimit(0);
        this._mark = -1;
    },
    /**
     * Closes this stream.
     *
     */
    close : function() {
        return this._in.close();
    },
    /**
     * Flushs this stream.
     *
     */
    flush : function() {
        return this._in.flush();
    },
    mark : function(limit) {
        if (this._buffer.remaining() == 0) {
            this._buffer.clear();
            this._buffer.setLimit(0);
        }
        if (limit > this._buffer.capacity() - this._buffer.position()) {
            throw new BufferOverflowException();
        }
        this._mark = this._buffer.position();
    },
    /**
     * Tells if this stream supports the mark and reset methods.
     * 
     * @returns {Boolean} if this stream instance supports the mark and reset methods; false otherwise.
     */
    markSupported : function() {
        return true;
    },
    reset : function() {
        if (this._mark < 0) {
            throw new Exception('Invalid mark');
        }
        this._buffer.setPosition(this._mark);
    },
    _fill : function() {
        if (this._buffer.remaining() > 0) {
            return;
        }
        this._buffer.clear();
        this._in.read(this._buffer);
        this._mark = -1;
    },
    /**
     * Reads a byte.
     * 
     * @returns {Number} The unsigned byte or -1.
     */
    readByte : function() {
        this._fill();
        return this._buffer.getByte();
    },
    /**
     * Reads bytes into the specified byte array, starting at the given offset.
     * 
     * @param {ByteArray} barray The destination byte array.
     * @param {Number} offset The offset at which to start storing bytes.
     * @param {Number} length The maximum number of bytes to read.
     * @returns {Number} The total number of bytes read.
     */
    readByteArray : function(barray, offset, length) {
    	offset = offset || 0;
    	length = length || barray.size() - offset;
        var count = 0;
        while (count < length) {
            this._fill();
            if (this._buffer.remaining() == 0) {
                break;
            }
            var l = this._buffer.remaining();
            if (l > length - count) {
                l = length - count;
            }
            barray.memcpy(offset + count, this._buffer.byteArray(), this._buffer.position(), l);
            buffer.incrementPosition(l);
            count += l;
        }
        return count;
    },
    /**
     * Reads this file into a buffer.
     *
     * @param {jls.lang.Buffer} buffer The buffer to read.
     * @returns {Number} the read byte count.
     */
    read : function(buffer) {
        var start = buffer.position();
        while (buffer.remaining() > 0) {
            this._fill();
            if (this._buffer.remaining() == 0) {
                break;
            }
            buffer.putBuffer(this._buffer);
        }
        return buffer.position() - start;
    }
});


return BufferedInputStream;
});
