#!/usr/bin/env ruby
# -*- ruby -*-

# Copyright 2000, 2001 by Jim Weirich (jweirich@one.net).
# All rights reserved.

# Permission is granted for use, copying, modification, distribution,
# and distribution of modified versions of this work as long as the
# above copyright notice is included.

require 'gem/utils'
require 'tk'

module Gem

  # ====================================================================
  class CommandObserver
    
    attr_accessor :command
    
    def initialize (&command)
      fail "No block given" if not block_given?
      @command = command
    end
    
    def update
      @command.call
    end
  end
  
  
  # ====================================================================
  class ListingWidget
    def initialize (parent, title, container=nil)
      p = {'fill'=>'both', 'expand'=>true, 'side'=>'left'}
      @widget = (container ? container : TkFrame.new(parent) { pack p } )
      TkLabel.new(@widget) {
	text title
	pack ( 'fill'=>'none', 'expand'=>false, 'side'=>'top', 'anchor'=>'w' )
      }
      @list = TkListbox.new(@widget) { height 3; width 15; pack p }
      sb = TkScrollbar.new (@widget)
      sb.command (proc { |*args| @list.yview *args })
      sb.pack ('fill'=>'y', 'side'=>'right')
      @list.yscrollcommand (proc { |a,b| sb.set(a,b) })
#TBD      @select_action = proc { puts "Do Nothing" }
      @list.bind ("ButtonRelease-1") { 
	index = @list.curselection[0]
	@model.select (index) if index.is_a?(Integer)
      }
    end
    
    def use_model (model)
      @model = model
      @model.add_observer(self)
    end
    
    def update
      top, bottom = @list.yview
      @list.delete (0, "end")
      @model.items.each {|item| @list.insert ("end", item)}
      @list.yview ('moveto', top)
      highlight (@model.selection_index)
    end 
    
    def highlight (index)
      return if index < 0
      @list.selection_clear (0, 'end')
      @list.selection_set (index)
      @list.see (index)
    end
  end
  
  
  # ====================================================================
  class ClassBrowser
    include GemUtils
    
    def initialize
      finder = MethodFinder.new
      
      root = TkRoot.new { title "Gem Finder (#{REV})" }
      
      buttons = TkFrame.new {
	pack ( 'fill'=>'x', 'expand'=>false, 'side'=>'bottom' )
      }
      TkButton.new(buttons) {
	text 'Exit'
	command proc { exit }
	pack ( 'fill'=>'x', 'expand'=>false, 'side'=>'right')
      }
      
      flat_button = TkCheckButton.new (buttons) {
	text 'Flat View'
	pack ( 'fill'=>'x', 'expand'=>false, 'side'=>'left')
      }
      
      private_button = TkCheckButton.new (buttons) {
	text 'Private'
	pack ( 'fill'=>'x', 'expand'=>false, 'side'=>'left')
      }
      
      cm_button = TkCheckButton.new (buttons) {
	text 'Class Methods'
	variable TkVariable.new ($checked)
	pack ( 'fill'=>'x', 'expand'=>false, 'side'=>'left')
      }
      
      sys_button = TkCheckButton.new (buttons) {
	text 'System'
	pack ( 'fill'=>'x', 'expand'=>false, 'side'=>'left')
      }
      sys_button.select
      
      labels = TkFrame.new { pack ( 'fill'=>'x', 'expand'=>false ) }
      class_label = TkLabel.new(labels) {
	text "Class: "
	pack ( 'fill'=>'none',
	      'expand'=>false,
	      'side'=>'left',
	      'anchor'=>'w')
      }
      class_label = TkLabel.new (labels) {
	relief 'groove'
	width 15
	pack ( 'fill'=>'x',
	      'expand'=>true,
	      'side'=>'left',
	      'anchor'=>'w')
      }
      parent_label = TkButton.new (labels) {
	text ""
	width 15
	pack ( 'fill'=>'x',
	      'expand'=>true,
	      'side'=>'right',
	      'anchor'=>'w')
      }
      TkLabel.new(labels) {
	text "Parent: "
	pack ( 'fill'=>'none',
	      'expand'=>false,
	      'side'=>'right',
	      'anchor'=>'w')
      }
      
      windows = TkFrame.new { pack ('fill'=>'both', 'expand'=>true) }
      
      browser = ClassBrowserModel.new (finder)
      
      class_list  = ListingWidget.new (windows, "Classes")
      class_list.use_model (browser.class_model)
      
      center_frame = TkFrame.new(windows) {
	pack ('fill'=>'both', 'expand'=>true, 'side'=>'left')
      }
      center_top_frame = TkFrame.new (center_frame) {
	pack ('fill'=>'both', 'expand'=>true, 'side'=>'top')
      }
      center_bottom_frame = TkFrame.new (center_frame) {
	pack ('fill'=>'both', 'expand'=>true, 'side'=>'top')
      }
      
      child_list  = ListingWidget.new (center_top_frame,
				       "Subclasses",
				       center_top_frame)
      child_list.use_model(browser.child_model)
      
      module_list = ListingWidget.new (center_bottom_frame,
				       "Included Modules",
				       center_bottom_frame)
      module_list.use_model(browser.module_model)
      
      method_list = ListingWidget.new (windows, "Methods")
      method_list.use_model(browser.method_model)
      
      parent_label.command proc {
	class_name = parent_label.text
	if class_name.is_a?(String) and (class_name!="") then
	  browser.class_model.select_name(parent_label.text)
	end
      }
      
      browser.class_model.add_observer CommandObserver.new {
	class_label.text (browser.class_model.selection)
	parent_label.text (parent_name_of(browser.class_model.selection))
      }
      
      cm_button.command proc {
	finder.use_class_methods = ! finder.use_class_methods
	browser.class_model.notify
      }
      flat_button.command proc {
	finder.flat = ! finder.flat
	browser.class_model.notify
      }
      private_button.command proc {
	finder.show_private = ! finder.show_private
	browser.class_model.notify
      }
      sys_button.command proc {
	browser.class_model.include_system = ! browser.class_model.include_system
      }

      browser.fill
    end
  end
  
  
end
