#
#   Copyright (C) 2006 Eriko Sato
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2, or (at your option)
#   any later version.
#
#   This program 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 General Public License for more details.
#
#   You should have received a copyED of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

module Kz
  class SandBox
    def initialize(kz)
      @kz = kz
      @binding = binding
    end

    def evaluate(statements, file=__FILE__, line=__LINE__)
      eval(statements, @binding, file, line)
    end
  end

  class RubyDialog
    def initialize(kz)
      @kz = kz
      @sandbox = SandBox.new(@kz)
      @default_font_size = 14
      init_dialog
      @dialog.show_all
    end
    
    def init_dialog
      @dialog = Gtk::Dialog.new
      @dialog.set_size_request(400, 300)
      @dialog.signal_connect("destroy") do |widget, event|
        false
      end
      init_text_view
      init_buttons
    end
    
    def init_text_view
      @view = Gtk::TextView.new
      @view.set_wrap_mode(Gtk::TextTag::WRAP_WORD_CHAR)
      @buffer = @view.buffer
      init_eval_mark
      init_tags
      @view.signal_connect("key_press_event") do |widget, event|
        handle_input(event)
        false
      end
      @buffer.signal_connect_after("insert_text") do |widget, iter, text, len|
        start = @buffer.get_iter_at_offset(iter.offset - len)
        @buffer.apply_tag(@all_tag, start, iter)
        false
      end
      sw = add_scrooled_window(@view)
      @dialog.vbox.pack_start(sw, true, true, 0)
    end

    def init_eval_mark
      start_iter = @buffer.start_iter
      @eval_mark = @buffer.create_mark("ruby-start", start_iter, true)
    end

    def init_tags
      result_tag_prop = {:foreground => "HotPink"}
      @result_tag = @buffer.create_tag("result", result_tag_prop)
      all_tag_prop = {
        :family => "monospace",
        :size_points => @default_font_size
      }
      @all_tag = @buffer.create_tag("all", all_tag_prop)
    end

    def handle_input(event)
      case event.keyval
      when Gdk::Keyval::GDK_Return
        text = @buffer.get_text(@buffer.get_iter_at_mark(@eval_mark),
                                @buffer.end_iter)
        if /\A\s*\z/m !~ text
          @buffer.insert(@buffer.end_iter, "\n>> ")
          @buffer.insert(@buffer.end_iter,
                         eval_text(text).inspect,
                         @result_tag)
        end
        @buffer.place_cursor(@buffer.end_iter)
        @buffer.move_mark(@eval_mark, @buffer.end_iter)
      end
    end
    
    def add_scrooled_window(widget)
      sw = Gtk::ScrolledWindow.new
      sw.border_width = 5
      sw.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
      sw.add(widget)
      sw
    end
    
    def init_buttons
      init_spin_button
      init_exit_button
    end

    def init_spin_button
      adjustment = Gtk::Adjustment.new(@default_font_size, 8, 72, 1, 4, 0)
      button = Gtk::SpinButton.new(adjustment, 1, 0)
      button.signal_connect("value-changed") do |widget, type|
        @all_tag.size_points = widget.value
        false
      end
      @dialog.action_area.add(button)
      @dialog.action_area.set_child_secondary(button, true)
    end
    
    def init_exit_button
      button = Gtk::Button.new("Exit")
      button.signal_connect("clicked") do |widget, event|
        @dialog.destroy
      end
      @dialog.action_area.add(button)
    end

    def eval_text(text)
      @sandbox.evaluate(text)
    rescue Exception
      $!
    end
  end
end
