class FlogCLI

def self.load_plugins

def self.load_plugins
  # TODO: I think I want to do this more like hoe's plugin system. Generalize?
  loaded, found = {}, {}
  Gem.find_files("flog/*.rb").reverse.each do |path|
    found[File.basename(path, ".rb").intern] = path
  end
  found.each do |name, plugin|
    next if loaded[name]
    begin
      warn "loading #{plugin}" # if $DEBUG
      loaded[name] = load plugin
    rescue LoadError => e
      warn "error loading #{plugin.inspect}: #{e.message}. skipping..."
    end
  end
  self.plugins.merge loaded
  names = Flog.constants.map {|s| s.to_s}.reject {|n| n =~ /^[A-Z_]+$/}
  names.each do |name|
    # next unless Hoe.plugins.include? name.downcase.intern
    mod = Flog.const_get(name)
    next if Class === mod
    warn "extend #{mod}" if $DEBUG
    # self.extend mod
  end
end

def self.parse_options args = ARGV, extra_options = {}

def self.parse_options args = ARGV, extra_options = {}
  option = {
    :quiet    => false,
    :continue => false,
    :parser   => RubyParser,
  }.merge extra_options
  OptionParser.new do |opts|
    opts.separator "Standard options:"
    opts.on("-a", "--all", "Display all flog results, not top 60%.") do
      option[:all] = true
    end
    opts.on("-b", "--blame", "Include blame information for methods.") do
      option[:blame] = true
    end
    opts.on("-c", "--continue", "Continue despite syntax errors.") do
      option[:continue] = true
    end
    opts.on("-d", "--details", "Show method details.") do
      option[:details] = true
    end
    opts.on("-g", "--group", "Group and sort by class.") do
      option[:group] = true
    end
    opts.on("-h", "--help", "Show this message.") do
      puts opts
      exit
    end
    opts.on("-I dir1,dir2,dir3", Array, "Add to LOAD_PATH.") do |dirs|
      dirs.each do |dir|
        $: << dir
      end
    end
    opts.on("-m", "--methods-only", "Skip code outside of methods.") do
      option[:methods] = true
    end
    opts.on("-q", "--quiet", "Don't show parse errors.") do
      option[:quiet] = true
    end
    opts.on("-e", "--extended", "Put file:line on a separate line (for rubymine & friends).") do
      option[:extended] = true
    end
    opts.on("-s", "--score", "Display total score only.") do
      option[:score] = true
    end
    opts.on("-tN", "--threshold=N", Integer, "Set the report cutoff threshold (def: 60%).") do |n|
      option[:threshold] = n / 100.0
    end
    opts.on("-v", "--verbose", "Display progress during processing.") do
      option[:verbose] = true
    end
    next if self.plugins.empty?
    opts.separator "Plugin options:"
    extra = self.method_scores.grep(/parse_options/) - %w(parse_options)
    extra.sort.each do |msg|
      self.send msg, opts, option
    end
  end.parse! Array(args)
  option
end

def self.plugins

def self.plugins
  @plugins ||= {}
end

def self.run args = ARGV, extra = {}

def self.run args = ARGV, extra = {}
  load_plugins
  expander = PathExpander.new args, "**/*.{rb,rake}"
  files = expander.process
  options = parse_options args, extra
  abort "no files or stdin (-) to process, aborting." if
    files.empty? and args.empty?
  flogger = new options
  flogger.flog(*files)
  flogger.report
end

def flog(*files)

def flog(*files)
  files << "-" if files.empty?
  @flog.flog(*files)
end

def initialize options = {}

def initialize options = {}
  @flog = Flog.new options
end

def output_details io, max = nil

def output_details io, max = nil
  io.puts
  each_by_score max do |class_method, score, call_list|
    self.print_score io, class_method, score
    if option[:details] then
      call_list.sort_by { |k,v| -v }.each do |call, count|
        io.puts "  %6.1f:   %s" % [count, call]
      end
      io.puts
    end
  end
end

def output_details_grouped io, threshold = nil

def output_details_grouped io, threshold = nil
  calculate
  scores.sort_by { |_, n| -n }.each do |klass, total|
    io.puts
    io.puts "%8.1f: %s" % [total, "#{klass} total"]
    method_scores[klass].each do |name, score|
      self.print_score io, name, score
    end
  end
end

def print_score io, name, score

def print_score io, name, score
  location = method_locations[name]
  if location then
    sep = " "
    sep = "%-11s" % "\n" if option[:extended]
    io.puts "%8.1f: %-32s%s%s" % [score, name, sep, location]
  else
    io.puts "%8.1f: %s" % [score, name]
  end
end

def report(io = $stdout)

def report(io = $stdout)
  io.puts "%8.1f: %s" % [total_score, "flog total"]
  io.puts "%8.1f: %s" % [average, "flog/method average"]
  return if option[:score]
  if option[:group] then
    output_details_grouped io, threshold
  else
    output_details io, threshold
  end
ensure
  self.reset
end