require 'java'

include_class "org.jruby.util.StringIOImpl"

class StringIO
  def self.open(string="",mode=nil)
    strio = StringIO.new(string,mode)
    val = strio
    if block_given?
      begin
        val = yield strio
      ensure
        strio.close
      end
    end
    val
  end

  def initialize(string="",mode=nil)
    @impl = StringIOImpl.new(string)
    @close_read = false
    @close_write = false
  end

  def <<(arg); @impl.write(arg.to_s); self; end
  def binmode; true; end
  def close() close_read; close_write; end
  def closed?() closed_read? && closed_write?; end
  def close_read() @close_read = true; end
  def closed_read?() @close_read; end
  def close_write() @close_write = true; end
  def closed_write?() @close_write; end

  def each(sep=$/)
    line = gets(sep)
    while line != nil
      yield(line)
      line = gets(sep)
    end
  end
  def each_byte() @impl.slice.each_byte; end
  def each_line() each; end
  def eof() @impl.isEof; end
  def eof?() @impl.isEof; end
  def fcntl; raise NotImplementedError; end
  def fileno; nil; end
  def flush; self; end
  def fsync; 0; end
  def getc() 
    @impl.getc
  end
  def gets(sep=$/)
    @impl.gets(sep)
  end
  def isatty; nil; end
  def tty?; nil; end
  def length() @impl.length; end
  def lineno() @impl.lineno; end
  def lineno=(val) @impl.setLineno(val); end
  def path() nil; end
  def pid() nil; end
  def pos; @impl.getPos; end
  def tell; @impl.getPos; end
  def pos=(val); @impl.pos(val); end
  def print(obj=$_, *rest)
    @impl.write(obj.to_s)
    rest.each { |arg| @impl.write(arg.to_s) }
    @impl.write($\.to_s)
    nil
  end
  def printf(*args) @impl.write(sprintf(*args)); end
  def putc(obj) @impl.write(obj.to_s); end
  def puts(*args) @impl.write(args.join("\n") + "\n"); end
  def read(*args); @impl.read(args); end
  def readchar(); @impl.readchar; end
  alias readline gets
  def readlines(sep=$/)
    lns = []
    while !eof?
      lns << gets(sep)
    end
    lns
  end
  def reopen(str, mode=nil) 
    if StringIO === str
      @impl = str.impl
      @closed_read = str.closed_read?
      @closed_write = str.closed_write?
    else
      @impl = StringIOImpl.new(str)
    end
    self
  end
  def rewind() @impl.rewind; 0; end
  def seek(amount, whence=IO::SEEK_SET)
    if (whence == IO::SEEK_CUR)
      @impl.pos(@pos + amount)
    elsif (whence == IO::SEEK_END)
      @impl.pos(length + amount)
    else
      @impl.pos(amount)
    end
    0
  end
  def size; @impl.string.length; end
  def string; @impl.string; end
  def string=(str); reopen(str); end
  def sync; true; end
  def sync=(val); val; end
  def syswrite(s); @impl.write(s); end
  def truncate(len); @impl.truncate(len); 0; end
  def ungetc(ch); @impl.ungetc(ch); nil; end
  def write(s); @impl.write(s); end
  protected 
  def impl
    @impl
  end
end
