require 'browselist'
require 'simple-i18n'
require 'lib/librefe'
require 'lib/libpiref'
require 'lib/phi-lib'


if $0 == __FILE__
  module ApRBBR
    def self.Message
      SimpleI18N.Message
    end
    self.Message.set_message('message-rbbr.txt')
  end
end


module ApRBBR
  
  # Apolloのモジュールが増えるたびに追加する
  APOLLO_MOD_NAMES = [
    'Phi',
    'Win',
    'Direct',
    'RGUI',
    'Sys',
    'UI',
  ]

  class RefWrapper

    REFE_INDEX = SimpleI18N.Locale.find('index.refe')
    PIRF_INDEX = SimpleI18N.Locale.find('index.pirf')

    TO_DESC = [
      ApRBBR.Message['singleton_methods'],
      ApRBBR.Message['public_methods'],      
    ]
    
    def initialize
      @loaded = false

      @valid = true
      @valid_refe = true
      @valid_pirf = true
      
      @apollo_class_regexp = PhiHierarchy::APOLLO_REGEXP # [ap-dev:1367] 
      @apollo_mod_regexp = APOLLO_MOD_NAMES.collect{|x| '^' + x }.join('|')
    end

    def load_ref
      @refe = load_refe
      @pirf = load_pirf
      @loaded = true

      if @refe.nil? and @pirf.nil?
	@valid = false
	@valid_refe = false
	@valid_pirf = false
      elsif @refe.nil?
	@valid_refe = false
      elsif @pirf.nil?
	@valid_pirf = false
      end
    end
    
    def loaded?
      @loaded
    end

    def valid?
      @valid
    end
    
    def valid_refe?
      @valid_refe
    end
    
    def valid_pirf?
      @valid_pirf
    end
    
    def load_pirf
      begin
	if FileTest::readable?(PIRF_INDEX)
	  return PiIndex.load(PIRF_INDEX)
	else
	  return nil
	end
      rescue
	return nil
      end
    end
    
    def load_refe
      begin
	if FileTest::readable?(REFE_INDEX)
	  return ReFe::Database.load(REFE_INDEX)
	else
	  return nil
	end
      rescue
	return nil
      end
    end
    
    # arr = [ クラスやモジュールの名前, 関数や定数の名前, 関数や定数の種類 ]
    def search(arr)
      if arr[2] == BrowseList::GLOBAL_CONSTANT
	if @valid_refe
	  search_refe_about_global_const(arr[1])
	else
	  return {}
	end
      elsif @apollo_class_regexp =~ arr[0] or @apollo_mod_regexp =~ arr[0]
	if @valid_pirf
	  return search_pirf(arr)
	else
	  return {}
	end
      else
	if @valid_refe
	  return search_refe(arr)
	else
	  return {}
	end
      end
    end
    
    def search_pirf(arr)
      begin
	str = @pirf.search(arr[0], arr[1], arr[2])
      rescue PiIndex::SearchError
	return {}
      end
      {"#{arr[0]}#{BrowseList::KIND2MARK[arr[2]]}#{arr[1]}" => str}
    end
    
    # refeの関数をap-rbbrに合うように変更
    def search_refe(arr)
      class_name = arr[0]
      method_name = arr[1]
      kind = arr[2]
      
      if method_name and class_name
	begin
	  hash = search_refe_about_method( @refe.lookup(class_name, method_name, BrowseList::KIND2MARK[kind]) )
	rescue ReFe::SearchError
	  hash = {}
	end
      else 
	print "BUG at seach_refe\n"
	exit
      end
      hash
    end
    
    def search_refe_about_global_const(const)
      begin 
	hash = search_refe_about_class( @refe.lookup_class(const, nil) )      
      rescue ReFe::SearchError
	return {}
      end
      hash	
    end
    
    def search_refe_about_class(table)
      hash = {}
      
      table.each do |name, desc|
	tmp_str =  '==== ' +  name + " ====\n" + desc
	table.methods( name ).each_with_index do |m,i|
	  if m then
	    tmp_str += '---- ' + TO_DESC[i] + " ----\n"
	    m.sort.each do |m_name| 
	      tmp_str += m_name + ' '
	    end
	  end
	end
	hash[name] = tmp_str
      end
      
      hash
    end
    
    def search_refe_about_method(table)
      hash = {}
      table.each do |name, desc|
	hash[name] = desc.strip
      end
      hash
    end
    
  end


  
  class RefMemo < Phi::Memo

    def initialize(form, compo_name, capt, ref_wrapper)
      super(form, compo_name, capt)
      self.align = Phi::AL_BOTTOM
      self.scroll_bars = Phi::SS_VERTICAL
      self.read_only = true
      self.height = 120
      @can_search = true
      @ref_wrapper = ref_wrapper
    end
    
    def can_search?
      @can_search
    end
    
    def set_searchable(flag)
      if @can_search.nil?
	return false
      end
      
      if flag == true
	@can_search = true
	self.show
	return true
      elsif flag == false
	@can_search = false
	self.hide
	return true
      elsif flag == nil
	@can_seach = nil
	self.hide
	return true
      end
      return false
    end
    
    # スクロールを制御したいが、
    def update(arr)
      unless @can_search
	return false
      end

      # 起動時にロードせずにここで行う
      unless @ref_wrapper.loaded?
	@ref_wrapper.load_ref
      end

      unless @ref_wrapper.valid?
	disable_ref
	return false
      end

      # RefWrapper#searchは検索に失敗すると{}を返す。
      desc_hash = @ref_wrapper.search(arr)
      #self.lines.update{
      self.lines.clear
      if desc_hash.size == 0
	self.lines.add("#{arr[0]}#{BrowseList::KIND2MARK[arr[2]]}#{arr[1]}: ")
	self.lines.add( ApRBBR.Message['refe_search_error'] )
      else
	write_desc(desc_hash)
      end
      #}
    end

    def write_desc(hash)
      hash.each do |k,v|
	self.lines.add( SimpleI18N.Locale.String(k) )
	SimpleI18N.Locale.String(v).each do |l|
	  # スクロールの問題。
	  # updateで逃げるか
	  # ブックマークに登録した方法
	  if /^\s*$/ =~ l
	    #self.lines.add('')
	  else
	    self.lines.add(l.chomp)
	    self.lines.add('')
	  end
	end
      end
    end

    def disable_ref
      @can_search = nil
      self.lines.add("can't restore #{REFE_INDEX}")
    end

  end

end

if $0 == __FILE__
  table = {
    'ARGV' => ['Object', 'ARGV', ApRBBR::BrowseList::GLOBAL_CONSTANT],
    'ARGF' => ['Object', 'ARGF', ApRBBR::BrowseList::PUBLIC_METHOD],
    'Object#to_s' => ['Object', 'to_s', ApRBBR::BrowseList::PUBLIC_METHOD],
    'Phi::Form#show' => ['Phi::Form', 'show', ApRBBR::BrowseList::PUBLIC_METHOD]
  }
  

  form = Phi::Form.new
  ref = ApRBBR::RefWrapper.new
  memo = ApRBBR::RefMemo.new(form, :memo1, '', ref)
  memo.align = Phi::AL_CLIENT
  
  panel = Phi::Panel.new(form)
  panel.align = Phi::AL_TOP

  cb = Phi::ComboBox.new(panel)
  cb.align = Phi::AL_LEFT
  cb.width = ( panel.width / 3 * 2 ).to_i
  table.keys.each do |str|
    cb.items.add(str)
  end
  panel.height = cb.height

  btn = Phi::Button.new(panel)
  btn.align = Phi::AL_RIGHT
  btn.caption = 'show refence'
  btn.width = ( panel.width / 3 ).to_i

  btn.on_click = proc do
    p cb.text
    memo.update(table[cb.text])
  end
  
  form.show
  Phi.mainloop
end
