#!/usr/bin/env ruby

def resolve(path)
  if File.directory?(path)
    Dir.entries(path).flat_map do |entry|
      if entry == "." || entry == ".."
        []
      else
        resolve(File.join(path, entry))
      end
    end
  elsif File.file?(path)
    [path]
  else
    warn "#{path}: not found"
    exit
  end
end

def process(path)
  module_name = nil
  module_type = nil
  indentation = ""
  line_number = 0

  File.open(path, "r") do |file|
    file.each_line do |line|
      line.chomp!
      line_number += 1

      if line =~ /^( *).*\bclass ([^ ]+)?( ?extends ([^ ]+))? *$/
        indentation = $1
        module_name = $2 || "(anonymous)"
        module_type = :class
        superclass_name = $4
        result = format_class(module_name, superclass_name)

      elsif line =~ /^( *)([^ .]+)\.extend *$/
        indentation = $1
        module_name = $2
        module_type = :object

      elsif line =~ /^( *)((@[^ ]+)|([^ ]+\.[^ ]+)) *= *$/
        indentation = $1
        module_name = $2
        module_type = :object

      elsif line =~ /^#{indentation}  (@)?([^\s:]+): (.*)[=-]> *$/
        method_sigil = $1
        method_name = $2
        arguments = $3[/\((.*)\)/, 1]
        result = format_method(module_name, module_type, method_sigil, method_name, arguments)

      elsif line =~ /^#{indentation}  @proxyMethod +"(.*?\.)([^"?]+)"/
        method_name = $2
        result = format_method(module_name, module_type, nil, method_name, nil)

      end

      if result
        puts "#{path}:#{line_number} #{result}"
      end
    end
  end
end

def format_class(class_name, superclass_name)
  result = "class #{class_name}"
  result << " extends #{superclass_name}" if superclass_name
  result
end

def format_method(module_name, module_type, method_sigil, method_name, arguments)
  joiner = module_type == :class ? (method_sigil == "@" ? "." : "#") : "."
  result = "#{module_name}#{joiner}#{method_name}"
  result << " (#{arguments})" if arguments
  result
end

paths = ARGV.flat_map { |path| resolve(path) }
paths.each { |path| process(path) }
