class Capybara::Driver::Terminus < Capybara::Driver::Base
  attr_reader :options

  NULL_APP = lambda do |env|
    [200, {'Content-Type' => 'text/html'}, ['']]
  end

  def initialize(app = nil, options = {})
    @app         = Terminus::Proxy[app || NULL_APP]
    @options     = options
    @rack_server = Capybara::Server.new(@app)

    @rack_server.boot
    sleep(0.1) until Terminus.server_running?(@rack_server)
    Terminus.register_local_port(@rack_server.port)
  end

  def find_css(css)
    browser.find_css(css, self)
  end

  def find_xpath(xpath)
    browser.find_xpath(xpath, self)
  end
  alias :find :find_xpath

  def invalid_element_errors
    [::Terminus::ObsoleteElementError]
  end

  def needs_server?
    true
  end

  def visit(path)
    h, s = Capybara.app_host, @rack_server
    path = "#{h || "http://#{s.host}:#{s.port}"}#{path}" unless path =~ /^https?:\/\//
    browser.visit(path)
  end

  def wait?
    true
  end

  extend Forwardable
  def_delegators :browser, :body,
                           :current_url,
                           :debugger,
                           :evaluate_script,
                           :execute_script,
                           :go_back,
                           :go_forward,
                           :html,
                           :reset!,
                           :response_headers,
                           :save_screenshot,
                           :source,
                           :status_code,
                           :title

  def within_window(name)
    name = name['id'] unless String === name
    current_browser = browser
    Terminus.browser = browser.id + '/' + name
    result = yield
    Terminus.browser = current_browser
    result
  end
  alias :within_frame :within_window

private

  def browser
    Terminus.ensure_browsers
    Terminus.browser
  end
end

# Capybara 0.3.9 looks in the Capybara::Driver namespace for appropriate
# drivers. 0.4 uses this registration API instead.
if Capybara.respond_to?(:register_driver)
  Capybara.register_driver :terminus do |app|
    Capybara::Driver::Terminus.new(app)
  end
end

# We use WEBrick to boot the test app, because if we use Thin (the default) the
# slow response used to test Ajax resynchronization blocks the event loop. This
# stops Terminus receiving messages and causes false positives: the client is
# not really waiting for Ajax to complete, it's just having its messages blocked
# because EventMachine is frozen.

Capybara.server do |app, port|
  handler = Rack::Handler.get('webrick')
  logger  = Terminus.debug ? Logger.new(STDOUT) : WEBrick::Log.new(nil, 0)
  handler.run(app, :Port => port, :AccessLog => [], :Logger => logger)
end

