module Rack
  module SpeedTracer

    class Context
      TRACER_PATH  = /^\/speedtracer/.freeze
      SYMBOL_PATH  = /^\/symbolmanifest.json/.freeze
      CONTENT_TYPE = 'application/json;charset=UTF-8'.freeze

      attr_accessor :db

      def initialize(app, options = {}, &blk)
        options = {
          :storage => Storage::Memory
        }.merge(options)

        @app  = app
        @uuid = UUID.new
        @db = options.delete(:storage).new(options)

        yield self if block_given?
      end

      def call(env)
        case env['PATH_INFO']
        when SYMBOL_PATH
          return Rack::Response.new('', 404).finish

        when TRACER_PATH
          resp = Rack::Response.new('', 200)
          resp['Content-Type'] = CONTENT_TYPE

          case env['REQUEST_METHOD']
            when 'HEAD' then
              # SpeedTracer dispatches HEAD requests to verify the
              # tracer endpoint when it detects the X-TraceUrl
              # header for the first time. After the initial load
              # the verification is cached by the extension.
              #
              # By default, we'll return 200.

            when 'GET' then
              # GET requests for specific trace are generated by
              # the extension when the user expands the network
              # resource tab. Hence, server-side tracer data is
              # request on-demand, and we need to store it for
              # some time.

              qs = Rack::Utils.parse_query(env['QUERY_STRING'])
              if qs['id'] && @db[qs['id']]
                resp.write @db[qs['id']]
              else
                # Invalid request or missing request trace id
                resp.status = 404
              end
            else
              # SpeedTracer should only issue GET & HEAD requests
              resp.status = 400
          end

          return resp.finish
        end

        env['st.id']   = @uuid.generate
        env['st.tracer'] = Tracer.new(env['st.id'], env['REQUEST_METHOD'], env['REQUEST_URI'])

        @status, @headers, @response = @app.call(env)
        @db[env['st.id']] = env['st.tracer'].finish

        # set the TraceUrl header to notify SpeedTracer that
        # serverside meta-data is available for this request
        @headers['X-TraceUrl'] = '/speedtracer?id=' + env['st.id']

        [@status, @headers, @response]
      end
    end

  end
end
