#!/usr/bin/env ruby

$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
require 'optparse'
require 'ostruct'

DEBUGGER_TYPE = if RUBY_VERSION < "2.0"
  require 'debugger'
  :debugger
else
  require 'byebug'
  :byebug
end

require 'debugger_xml'

if DEBUGGER_TYPE == :debugger
  PROXY_CLASS = DebuggerXml::DebuggerProxy
  PRINTER_CLASS = Printers::Xml
else
  PROXY_CLASS = DebuggerXml::ByebugProxy
  PRINTER_CLASS = Byebug::Printers::Xml
end

class RdebugVim

  def initialize
    check_argv!
    DebuggerXml.wait_for_start = true
    @proxy = PROXY_CLASS.new
    @proxy.tracing = false
    @proxy.printer = PRINTER_CLASS.new
    @proxy.set_rdebug_script(File.expand_path($0))
    @proxy.set_prog_script(options.script)
    install_interruption_hander
    DebuggerXml.logger = if options.debug_mode
      DebuggerXml::Vim::Logger.new(options.logger_file)
    else
      DebuggerXml::FakeLogger.new
    end
  end

  def run
    DebuggerXml.start_for_vim(@proxy, options)
    bt = @proxy.debug_load
    if bt
      print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n"
      print "Uncaught exception: #{bt}\n"
    end
  end

  private

    def check_argv!
      if ARGV.empty?
        puts opts
        puts
        puts "Must specify a script to run"
        exit(1)
      end
    end

    def install_interruption_hander
      trap('INT') { @proxy.interrupt_last }
    end

    def options
      opts
      @options
    end

    def opts
      @opts ||= begin
        @options = OpenStruct.new
        opts = OptionParser.new do |opts|
          opts.banner = %{
            Using rdebug-vim
            Usage: rdebug-vim is supposed to be called from vim-ruby-debugger.
            The command line interface to 'debugger' is rdebug.
          }.gsub(/^\s*/, '')
          opts.separator ""
          opts.separator "Options:"
          opts.on("-f", "--file FILE", String, "File for communication with Vim") { |file| @options.file = file }
          opts.on("-o", "--output FILE", String, "File where standard/error output is sent to") do |file|
            @options.output_file = file
          end
          opts.on("-s", "--socket FILE", String, "Socket file to communicate with debugger") do |file|
            @options.socket = file
          end
          opts.on("-lf", "--logger_file FILE", String, "File for logging") { |file| @options.logger_file = file }
          opts.on("-dm", "--debug_mode MODE", Integer, "Debug mode") { |mode| @options.debug_mode = mode == 1 }
          opts.on("-ve", "--vim_executable FILE", String, "Vim executable file (e.g., 'mvim')") do |file|
            @options.vim_executable = file
          end
          opts.on("-vs", "--vim_servername NAME", String, "Vim servername (e.g., 'VIM')") do |name|
            @options.vim_servername = name
          end
          opts.on("-spr", "--separator NAME", String, "Output results separator") do |name|
            @options.separator = name
          end
          opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") { |path| $LOAD_PATH.unshift(path) }
        end
        opts.parse!
        @options.script = ARGV.shift
      end
    end

end

RdebugVim.new.run
