#
# searcher.rb
#
# Copyright (c) 2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU Lesser General Public License version 2 or later.
#

module ReFe

  class MethodSearcher

    include TraceUtils

    def initialize( ctable, mtable, policy )
      @class_table = ctable
      @method_table = mtable
      @policy = policy
    end

    def search( keys )
      case keys.size
      when 0
        @policy.print_names @class_table.classes

      when 1
        key, = keys
        if key.index(?.) or key.index(?#) or key.index(?,)
          c, t, m = key.split(/([\.\#\,])/, 2)
          t = '#' if t == ','
          c = nil if c.empty?
          m = nil if m.empty?
          try c, t, m
        elsif /\A[A-Z]/ === key
          try key, nil, nil
        else
          try nil, nil, key
        end

      when 2
        c, m = keys
        c, t, = c.split(/([\.\#\,])/, 2)
        t = '#' if t == ','
        try c, t, m
      
      when 3
        try(*keys)

      else
        raise '[ReFe BUG] argv > 3'
      end
    end

    private

    def try( c, t, m )
      if (c and m) or t
        trace 'search: type = Method'
        print_method @method_table.complete(c, t, m)
      else
        first = true
        begin
          if c
            trace 'search: type = Class'
            print_class @class_table.complete(c)
          else
            trace 'search: type = Method'
            print_method @method_table.complete(c, t, m)
          end
        rescue ReFe::CompletionError
          if first
            first = false
            c, m = m, c
            trace 'search: RETRY'
            retry
          end
          raise ReFe::CompletionError, "no such class or method: #{c || m}"
        end
      end
    end

    def print_class( results )
      unless @policy.should_print_content?(results)
        @policy.print_names results
        return
      end
      results.sort.each do |klass|
        print '==== ', klass, " ====\n"
        puts @class_table[klass]
        puts '---- Singleton methods ----'
        @policy.packed_print @method_table.singleton_methods_of(klass)
        puts '---- Instance methods ----'
        @policy.packed_print @method_table.instance_methods_of(klass)
      end
    end

    def print_method( results )
      if @policy.should_print_content?(results)
        results.sort.each do |name|
          puts name
          puts @method_table[name]
        end
      else
        @policy.print_names results
      end
    end

  end


  class FunctionSearcher

    def initialize( table, policy )
      @table = table
      @policy = policy
    end

    def search( keys )
      results = @table.complete(keys)
      if @policy.should_print_content?(results)
        results.sort.each do |name|
          puts @table[name]
        end
      else
        @policy.print_names results
      end
    end

  end


  class OutputPolicy

    def OutputPolicy.new2( opts )
      new(opts['all'], opts['short'], opts['line'])
    end

    def initialize( all, short, line )
      @all = all
      @short = short
      @line = line
    end

    def should_print_content?( results )
      return false if @short
      return true if @all
      results.size == 1
    end

    def print_names( list )
      if @line
        list.sort.each do |i|
          puts i
        end
      else
        packed_print list
      end
    end

    LINE_MAX = 60

    def packed_print( list )
      len = 0
      sep = ''
      list.sort.each do |word|
        if len != 0 and (len + sep.size + word.size > LINE_MAX)
          sep = "\n"; len = 0
        end
        print sep, word; len += sep.size + word.size
        sep = ' '
      end
      puts
    end

  end

end
