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

var BufferedReader;
BufferedReader = Class.create( /** @lends jls.io.BufferedReader.prototype */
{
    /**
     * Creates a BufferedReader.
     * 
     * @param {jls.io.Reader} reader The underlying character reader.
     * @param {Number} size The buffer size.
     * @constructs
     * @class Provides a buffered reader for character reader.
     */
    initialize : function(reader, size) {
        this._reader = reader;
    	this._buffer = CharBuffer.allocate(size || 1024);
        this._buffer.setLimit(0);
        this._mark = -1;
    },
    /**
     * Closes this stream.
     *
     */
    close : function() {
        return this._reader.close();
    },
    /**
     * Flushs this stream.
     *
     */
    flush : function() {
        return this._reader.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.remaining();
        }
        this._buffer.clear();
        var count = this._reader.readCharBuffer(this._buffer);
        this._buffer.flip();
        this._mark = -1;
        return count;
    },
    /**
     * Reads a byte.
     * 
     * @returns {Number} The unsigned byte or -1.
     */
    readChar : function() {
        this._fill();
        return this._buffer.getChar();
    },
    /**
     * Reads this file into a buffer.
     *
     * @param {jls.lang.Buffer} buffer The buffer to read.
     * @returns {Number} the read byte count.
     */
    readCharBuffer : 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;
    },
    /**
     * Reads a line and returns the string.
     *
     * @returns {String} The line.
     */
    readLine : function() {
    	var line = '';
        while (true) {
            if (this._fill() == 0) {
                return null;
            }
            if (this._buffer.remaining() == 0) {
                break;
            }
            var p = this._buffer.position();
            var s = this._buffer.getString();
            var i = s.indexOf(BufferedReader.separator);
        	//jls.logger.warn('readLine() ->' + s + '<- ' + s.length + ', ' + i);
            if (i >= 0) {
            	this._buffer.setPosition(p + i + BufferedReader.separator.length);
                line += s.substr(0, i);
                break;
            }
            line += s;
        }
        //jls.logger.warn('readLine() ->' + line + '<-');
        return line;
    }
});

Object.extend(BufferedReader,
{
    separator : _native.core.properties['line.separator']
});


return BufferedReader;
});
