require 'irb'
require 'string_class'

=begin
GUIWrapper::GuiIoEmulate をincludeすることで、
デフォルトの出力先を変更することができます。
その場合、 $> に出力先のオブジェクトを代入する必要があります

# $>に代入さえすれば、includeする必要はない?
 
GUIWrapper::GuiIoEmulate と GUIWrapper::GuiConsole で出力先が違うことが
ある場合を想定して、それぞれ違うオブジェクトに出力できるようにしています。
今回の場合は GUIWrapper::GuiIoEmulate の出力先が
GUIWrapper::Guiconsole のオブジェクトになっているので、
GUIWrapper::GuiConsole には buffer_gets と buffer_putc を付け加えています。
=end

=begin
GUIWrapper::GuiIoEmulate は $> に
GUIWrapper::GuiConsole は @irbgui に
出力する値が渡るようにしています。

GUIWrapper::GuiIoEmulate が使用する $> に代入するオブジェクトが
持っていなければならない関数は下の二つです。
buffer_gets(rs)
buffer_putc(str)

GUIWrapper::GuiConsole が使用する @irbgui に代入するオブジェクトが
持っていなければならない関数は下の三つです。
buffer_write(str) # strのサイズは GUIWrapper::GuiConsole で調べます
buffer_gets(rs)
buffer_putc(str)
=end


#
# RubyWin rwclass.cpp より
#
module GUIWrapper

  def obj2str(obj)
    # to_sだけでいける?
    if obj.kind_of?(String)
      str = obj
    elsif obj.kind_of?(Class)
      str = obj.name
    elsif obj.kind_of?(Exception)
      str = obj.to_s
    else
      str = obj.to_s
    end
    str
  end

  module_function :obj2str
  
  module GuiIoEmulate
    
    def gets(rs = $/)
      # rsで指定されたオブジェクトを改行とみなして
      # 一行を読み込み、その値を返す。
      # rsのデフォルトは$/で指定されている
      # 読み込んだ値は$_セットされる。
      # ファイルの終りにnilを返す <= 多分要らない
      str = $>.buffer_gets(rs)

      if $DEBUG 
	STDOUT.print "Wrapper get string: "
	STDOUT.p str
      end

      $_ = str
      str
    end 
    
    def p(*args)
      # 問題はprintの出力先
      # $>を変更したら大丈夫? OKだった
      # 実装を間違えている
      args.each do |obj|
	print obj.inspect, "\n"
      end
      return nil
    end
    
    def putc(obj)
      # デフォルト出力($>)にstrを書き出す
      $>.buffer_putc( GUIWrapper::obj2str(str) ) 
    end
    
  end

  
  class GuiConsole
    
    def initialize(obj)
      @irbgui = obj
    end
    
    def write(obj)
      # objをStringのオブジェクトに変換して@irbguiに渡し、
      # Stringのオブジェクトに変換された時のバイト数を返す。
      # バイト数が必要になるのか分からないが。
      str = GUIWrapper::obj2str(obj)
      result = @irbgui.buffer_write(str)

      if $DEBUG
	STDOUT.print "Wrapper write string: "
	STDOUT.p str
      end
      
      case result
      when true
	str.get_str_byte
      else
	0
      end
    end
    
    def gets(rs = $/)
      str = @irbgui.buffer_gets(rs)
      $_ = str
      str
    end

    alias buffer_gets gets
    
    def buffer_putc(obj)
      @irbgui.buffer_putc( GUIWrapper::obj2str(obj) )
    end
	
    def self.gets(rs = $/)
      str = @irbgui.buffer_gets(rs)
      $_ = str
      str
    end

    # GUIWrapper::GuiIoEmulateでprintを定義すると、
    # 無限ループに入るのにこちらで定義すると、
    # そうならない。謎。
    def print(*args)
      print(*args)
    end
   
  end

end



#
# STDOUT を $stdin にしてるだけ
#
class RubyLex
  
  def initialize
    lex_init
    set_input($stdin)

    @seek = 0
    @exp_line_no = @line_no = 1
    @base_char_no = 0
    @char_no = 0
    @rests = []
    @readed = []
    @here_readed = []

    @indent = 0

    @skip_space = false
    @readed_auto_clean_up = false
    @exception_on_syntax_error = true
  end
  
end

#
# Rubywin rwirb.rb より
# 理解してません(ぉ
#
module IRB

  class IRBWrapperInputMethod < StdioInputMethod
    def gets 
      print @prompt
      @line[@line_no += 1] = GUIWrapper::GuiIoEmulate.gets
    end
  end

  def IRB.start_on_gui
    IRB.initialize(nil)

#   bind = workspace_binding
#   main = eval("self", bind)
    im = IRBWrapperInputMethod.new

#   irb = Irb.new(main, bind, im)
    irb = Irb.new(nil, im)
    @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
    @CONF[:MAIN_CONTEXT] = irb.context

    trap("SIGINT") do
      irb.signal_handle
    end

    catch(:IRB_EXIT) do
      irb.eval_input
    end
    print "\n"
  end
end
