module DEBUGGER__::UI_DAP

def process_request req

def process_request req
  raise "not a request: #{req.inspect}" unless req['type'] == 'request'
  args = req.dig('arguments')
  case req['command']
  ## boot/configuration
  when 'launch'
    send_response req
    # `launch` runs on debuggee on the same file system
    UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true
    @nonstop = true
    load_extensions req
  when 'attach'
    send_response req
    UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap')
    if req.dig('arguments', 'nonstop') == true
      @nonstop = true
    else
      @nonstop = false
    end
    load_extensions req
  when 'configurationDone'
    send_response req
    if @nonstop
      @q_msg << 'continue'
    else
      if SESSION.in_subsession?
        send_event 'stopped', reason: 'pause',
                              threadId: 1, # maybe ...
                              allThreadsStopped: true
      end
    end
  when 'setBreakpoints'
    req_path = args.dig('source', 'path')
    path = UI_DAP.local_to_remote_path(req_path)
    if path
      SESSION.clear_line_breakpoints path
      bps = []
      args['breakpoints'].each{|bp|
        line = bp['line']
        if cond = bp['condition']
          bps << SESSION.add_line_breakpoint(path, line, cond: cond)
        else
          bps << SESSION.add_line_breakpoint(path, line)
        end
      }
      send_response req, breakpoints: (bps.map do |bp| {verified: true,} end)
    else
      send_response req, success: false, message: "#{req_path} is not available"
    end
  when 'setFunctionBreakpoints'
    send_response req
  when 'setExceptionBreakpoints'
    process_filter = ->(filter_id, cond = nil) {
      bp =
        case filter_id
        when 'any'
          SESSION.add_catch_breakpoint 'Exception', cond: cond
        when 'RuntimeError'
          SESSION.add_catch_breakpoint 'RuntimeError', cond: cond
        else
          nil
        end
        {
          verified: !bp.nil?,
          message: bp.inspect,
        }
      }
      SESSION.clear_catch_breakpoints 'Exception', 'RuntimeError'
      filters = args.fetch('filters').map {|filter_id|
        process_filter.call(filter_id)
      }
      filters += args.fetch('filterOptions', {}).map{|bp_info|
      process_filter.call(bp_info['filterId'], bp_info['condition'])
    }
    send_response req, breakpoints: filters
  when 'disconnect'
    terminate = args.fetch("terminateDebuggee", false)
    SESSION.clear_all_breakpoints
    send_response req
    if SESSION.in_subsession?
      if terminate
        @q_msg << 'kill!'
      else
        @q_msg << 'continue'
      end
    else
      if terminate
        @q_msg << 'kill!'
        pause
      end
    end
  ## control
  when 'continue'
    @q_msg << 'c'
    send_response req, allThreadsContinued: true
  when 'next'
    begin
      @session.check_postmortem
      @q_msg << 'n'
      send_response req
    rescue PostmortemError
      send_response req,
                    success: false, message: 'postmortem mode',
                    result: "'Next' is not supported while postmortem mode"
    end
  when 'stepIn'
    begin
      @session.check_postmortem
      @q_msg << 's'
      send_response req
    rescue PostmortemError
      send_response req,
                    success: false, message: 'postmortem mode',
                    result: "'stepIn' is not supported while postmortem mode"
    end
  when 'stepOut'
    begin
      @session.check_postmortem
      @q_msg << 'fin'
      send_response req
    rescue PostmortemError
      send_response req,
                    success: false, message: 'postmortem mode',
                    result: "'stepOut' is not supported while postmortem mode"
    end
  when 'terminate'
    send_response req
    exit
  when 'pause'
    send_response req
    Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid)
  when 'reverseContinue'
    send_response req,
                  success: false, message: 'cancelled',
                  result: "Reverse Continue is not supported. Only \"Step back\" is supported."
  when 'stepBack'
    @q_msg << req
  ## query
  when 'threads'
    send_response req, threads: SESSION.managed_thread_clients.map{|tc|
      { id: tc.id,
        name: tc.name,
      }
    }
  when 'evaluate'
    expr = req.dig('arguments', 'expression')
    if /\A\s*,(.+)\z/ =~ expr
      dbg_expr = $1.strip
      dbg_expr.split(';;') { |cmd| @q_msg << cmd }
      send_response req,
                    result: "(rdbg:command) #{dbg_expr}",
                    variablesReference: 0
    else
      @q_msg << req
    end
  when 'stackTrace',
       'scopes',
       'variables',
       'source',
       'completions'
    @q_msg << req
  else
    if respond_to? mid = "custom_dap_request_#{req['command']}"
      __send__ mid, req
    else
      raise "Unknown request: #{req.inspect}"
    end
  end
end