#!/usr/bin/env ruby_ap

=begin
  $Author: moriq $
  $Date: 2003-07-23 10:51:28 +0900 (豌ｴ, 23 7 2003) $

  This program is free software.
  You can distribute/modify this program under
  the terms of the Ruby Distribute License.

=end

=begin
TODO
メソッド区切りのところにアイコン

ツリーごとMarshal(ぉ

挫折
ImageIndexがないのでアイコンは付けられない。

仕様?
p Dir.pwdを実行するとapollo.exeではスクリプトのあるところが
カレントディレクトリになるが、bashからだと、スクリプトを実行
した時にいたディレクトリがカレントディレクトリになる。

バグ 
-r debugをしようとすると止まる

=end

$:.push( File::dirname($0) )

require 'phi'
require 'dialogs'
#require 'editor'

require 'observer'
require 'kconv'

require 'version'
require 'simple-i18n'

module ApRBBR

  def self.Message
    SimpleI18N.Message
  end
  
  self.Message.set_message('message-rbbr.txt')

end

require 'phi-tree'
require 'browselist'
require 'ref'
autoload(:ExtraDialog, 'extra-dlg')

module ApRBBR

  class BrowseEdit < Phi::Edit

    def initialize(form, com_name)
      super(form, com_name)
#     self.align = Phi::AL_CLIENT
#     self.height = 23
      self.text = ''
      self.read_only = true
    end

    def update(modul)
      message = 
	if Class === modul
	  "class #{modul.name}"
	else # Module
	  "module #{modul.name}"
	end
      if Class === modul and Object != modul
	message << " < #{modul.superclass.name}"
      end
      included_modules_at = modul.included_modules_at
      unless included_modules_at.empty?
	message << "; include " << included_modules_at.join(", ")
      end
      self.text = message
    end

  end

  class Browser < Phi::Form
    
    def initialize
      super
      msg = ApRBBR.Message
      self.caption = (msg['ap-rbbr'])
      self.width = 600
      self.height = 500
      self.position = Phi::PO_SCREEN_CENTER

      create_menu

      @ref_wrapper = RefWrapper.new

      page_control = Phi::PageControl.new(self, :page_control1)
      page_control.align = Phi::AL_CLIENT

      class_tab = Phi::TabSheet.new(page_control, :class_tab1, msg['class_tab'])
      module_tab = Phi::TabSheet.new(page_control, :module_tab1, msg['module_tab'])
          
      @class_index = ApRBBR::ClassTree.new(class_tab, :class_index1)
      class_splitter = Phi::Splitter.new(class_tab)
      class_splitter.align = Phi::AL_RIGHT
      class_splitter.align = Phi::AL_LEFT
      class_panel = Phi::Panel.new(class_tab)
      class_panel.align = Phi::AL_CLIENT

      class_list = BrowseList.new(class_panel, :class_list1)
      class_list_ref_splitter = Phi::Splitter.new(class_panel)
      class_list_ref_splitter.align = Phi::AL_BOTTOM
      @class_ref = RefMemo.new(class_panel, :class_ref1, msg['ref_memo'], @ref_wrapper)
    
      @module_index = ApRBBR::ModuleTree.new(module_tab, :module_index1)
      module_splitter = Phi::Splitter.new(module_tab)
      #module_splitter.left = @module_index.width + 1
      #module_splitter.align = Phi::AL_RIGHT
      module_splitter.align = Phi::AL_LEFT
      module_panel = Phi::Panel.new(module_tab)
      module_panel.align = Phi::AL_CLIENT

      module_list = BrowseList.new(module_panel, :module_list1)
      module_list_ref_splitter = Phi::Splitter.new(module_panel)
      module_list_ref_splitter.align = Phi::AL_BOTTOM
      @module_ref = RefMemo.new(module_panel, :module_ref1, msg['ref_memo'], @ref_wrapper)

      edit = BrowseEdit.new(self, :edit1)
      edit.align = Phi::AL_TOP

      tool_panel = Phi::Panel.new(self, :tool_panel1)
      tool_panel.height = 32
      tool_panel.caption = ''
      tool_panel.align = Phi::AL_TOP
      tool_panel.bevel_width = 2

      create_tool_btn(tool_panel)

      # updateを実行させるオブジェクトの設定
      @class_index.add_observer(edit)
      @module_index.add_observer(edit)
      @class_index.add_observer(class_list)
      @module_index.add_observer(module_list)

      # Refeの結果を表示
      class_list.add_observer(@class_ref)
      module_list.add_observer(@module_ref)
      
      # 初めてモジュールタブがアクティブになったときに
      # ノードを付加する。
      module_tab.on_show = proc do 
	if @module_index.items.count == 0
	  @module_index.update
	  @module_index.width = @class_index.width
	  module_splitter.left = @module_index.left + @module_index.width + 1
	end
      end

    end

    def create_menu
      msg = ApRBBR.Message
      Phi.new_menu(self, :menu1, [
        Phi.new_item(msg['menu_file'], '', :mi_file).add(
          Phi.new_item(msg['menu_load_lib'], 'Ctrl+L', :mi_load_library),
	  Phi.new_item(msg['menu_load_script'], 'Ctrl+S', :mi_load_script),
          Phi.new_line,
          Phi.new_item(msg['menu_close'], '', :mi_exit) 
	),
        Phi.new_item(msg['menu_search'], '', :mi_search).add(
          Phi.new_item(msg['menu_class_search'], 'Ctrl+F', :mi_class_search)
        ),
        Phi.new_item(msg['menu_tree'], '', :mi_tree).add(
          Phi.new_item(msg['menu_expand_all'], '', :mi_expand_all)
        ),
	Phi.new_item(msg['menu_help'], '', :mi_help).add(
	  Phi.new_item(msg['menu_about'], '', :mi_about)
	),
      ])
      menu_attr_flatten

      self.mi_load_library.on_click = proc do
	dlg = ExtraDialog::QueryDialog.new(:query_dlg, msg['query_lib_dlg'])
	result = dlg.show_modal
	case result 
	when Phi::MR_OK
	  lib_name = dlg.text.strip
	  begin
	    unless lib_name.empty?
	      require(lib_name) 
	      Module.update_metainfo
	      @class_index.update
	      @module_index.update
	    end
	  rescue LoadError
	    Phi::message_dlg( ("#{$!}\n" + lib_name + ": " + msg['require_error']), Phi::MT_ERROR, [Phi::MB_OK], 0)
	  end
	end
      end

      self.mi_load_script.on_click = proc do
	dlg = Phi::OpenDialog.new
	dlg.filter = msg['file_dlg_filter']
	if dlg.execute
	  begin
	    filename = File::expand_path(dlg.file_name)
	    load(filename) unless filename.nil?
	    Module.update_metainfo
	    @class_index.update
	    @module_index.update
	  rescue ScriptError 
	    Phi::message_dlg($!, Phi::MT_ERROR, [Phi::MB_OK], 0)
	  rescue 
	    Phi::message_dlg($!, Phi::MT_ERROR, [Phi::MB_OK], 0)
	  end
	end
      end

      self.mi_exit.on_click = proc do
	exit
      end

      self.mi_class_search.on_click = proc do
	dlg = ExtraDialog::QueryDialog.new(:query_dlg, msg['query_class_dlg'])
	result = dlg.show_modal
	case result 
	when Phi::MR_OK
	  class_name = dlg.text.strip
	  unless class_name.empty?
	    result = @class_index.search_class(class_name)
	    unless result
	      case @class_index.contents 
	      when ApRBBR::ClassTree::WHOLE_TREE
		Phi::message_dlg(class_name + ': ' + msg['class_search_error'], Phi::MT_ERROR, [Phi::MB_OK], 0)
	      when 
		Phi::message_dlg(class_name + ': ' + msg['apollo_class_search_error'], Phi::MT_ERROR, [Phi::MB_OK], 0)
	      end
	    end
	  end
	end
      end

      # スクロールの問題
      self.mi_expand_all.on_click = proc do
	case self.page_control1.active_page.caption
	when ApRBBR.Message['class_tab']
	  active_index = @class_index	  
	when ApRBBR.Message['module_tab']
	  active_index = @module_index
	end
      
	nodes = active_index.items
	nodes.update do 
	  nodes.each_node_defined_in_aprbbr do |node|
	    node.expand(true)
	  end
	end
      end

    end

    def create_tool_btn(panel)
      btn_arr = []

      show_whole_tree_btn = Phi::SpeedButton.new(panel, :show_whole_tree_btn1)
      show_whole_tree_btn.flat = true
      show_whole_tree_btn.group_index = 1
      show_whole_tree_btn.down = true
      show_whole_tree_btn.width = 55
      show_whole_tree_btn.left = panel.left + 4 
      show_whole_tree_btn.caption = 'ALL'
      show_whole_tree_btn.on_click = proc do
	if @class_index.contents == ApRBBR::ClassTree::APOLLO_ONLY
	  @class_index.set_contents(ApRBBR::ClassTree::WHOLE_TREE)
	  @class_index.update
	end
      end
      btn_arr.push(show_whole_tree_btn)

      show_apollo_tree_btn = Phi::SpeedButton.new(panel, :show_apollo_tree_btn1)
      show_apollo_tree_btn.flat = true 
      show_apollo_tree_btn.group_index = 1
      show_apollo_tree_btn.width = 55
      show_apollo_tree_btn.left = show_whole_tree_btn.left + show_whole_tree_btn.width
      show_apollo_tree_btn.caption = 'Apollo'
      show_apollo_tree_btn.on_click = proc do
	if @class_index.contents == ApRBBR::ClassTree::WHOLE_TREE
	  @class_index.set_contents(ApRBBR::ClassTree::APOLLO_ONLY)
	  @class_index.update
	end
      end
      btn_arr.push(show_apollo_tree_btn)

      show_ref_btn = Phi::SpeedButton.new(panel, :show_refe_btn1)
      show_ref_btn.allow_all_up = 0
      show_ref_btn.flat = true
      show_ref_btn.width = 55
      show_ref_btn.group_index = 2
      show_ref_btn.left = show_apollo_tree_btn.left + show_apollo_tree_btn.width + 5
      show_ref_btn.caption = 'reference'
      show_ref_btn.on_click = proc do
	if @ref_wrapper.valid?
	  if show_ref_btn.down?
	    @class_ref.set_searchable(true)
	    @module_ref.set_searchable(true)
	  else
	    @class_ref.set_searchable(false)
	    @module_ref.set_searchable(false)
	  end
	end
      end
      btn_arr.push(show_ref_btn)

      if @ref_wrapper
	show_ref_btn.down = true
      else
	show_ref_btn.enabled = false
      end
      
      set_tool_bar_btns_looks(panel, btn_arr)
    end

    def set_tool_bar_btns_looks(panel, arr)
      btn_size = panel.height - 8
      arr.each_index do |num|
	btn = arr[num]
	btn.top = panel.top + 4
	btn.height = btn_size
      end
    end

  end

  def self.main
    window = Browser.new
    window.show
    Phi.mainloop
  end

end

if $0 == __FILE__
  ApRBBR.main
end
