/*
Wraps the given http.Handler ServerHTTP function
Will provide accounting metrics for the http.Request / http.Response life-cycle
*/
func (ih *instrumentedHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	requestId, err := uuid.ParseHex(req.Header.Get("X-CF-RequestID"))
	if err != nil {
		requestId, err = GenerateUuid()
		if err != nil {
			log.Printf("failed to generated request ID: %v\n", err)
			requestId = &uuid.UUID{}
		}
		req.Header.Set("X-CF-RequestID", requestId.String())
	}
	rw.Header().Set("X-CF-RequestID", requestId.String())

	startEvent := factories.NewHttpStart(req, events.PeerType_Server, requestId)

	err = ih.emitter.Emit(startEvent)
	if err != nil {
		log.Printf("failed to emit start event: %v\n", err)
	}

	instrumentedWriter := &instrumentedResponseWriter{writer: rw, statusCode: 200}
	ih.handler.ServeHTTP(instrumentedWriter, req)

	stopEvent := factories.NewHttpStop(req, instrumentedWriter.statusCode, instrumentedWriter.contentLength, events.PeerType_Server, requestId)

	err = ih.emitter.Emit(stopEvent)
	if err != nil {
		log.Printf("failed to emit stop event: %v\n", err)
	}
}
/*
Wraps the RoundTrip function of the given RoundTripper.
Will provide accounting metrics for the http.Request / http.Response life-cycle
Callers of RoundTrip are responsible for setting the ‘X-CF-RequestID’ field in the request header if they have one.
Callers are also responsible for setting the ‘X-CF-ApplicationID’ and ‘X-CF-InstanceIndex’ fields in the request header if they are known.
*/
func (irt *instrumentedRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	requestId, err := GenerateUuid()
	if err != nil {
		log.Printf("failed to generated request ID: %v\n", err)
		requestId = &uuid.UUID{}
	}

	httpStart := factories.NewHttpStart(req, events.PeerType_Client, requestId)

	parentRequestId, err := uuid.ParseHex(req.Header.Get("X-CF-RequestID"))
	if err == nil {
		httpStart.ParentRequestId = factories.NewUUID(parentRequestId)
	}

	req.Header.Set("X-CF-RequestID", requestId.String())

	err = irt.emitter.Emit(httpStart)
	if err != nil {
		log.Printf("failed to emit start event: %v\n", err)
	}

	resp, roundTripErr := irt.roundTripper.RoundTrip(req)

	var httpStop *events.HttpStop
	if roundTripErr != nil {
		httpStop = factories.NewHttpStop(req, 0, 0, events.PeerType_Client, requestId)
	} else {
		httpStop = factories.NewHttpStop(req, resp.StatusCode, resp.ContentLength, events.PeerType_Client, requestId)
	}

	err = irt.emitter.Emit(httpStop)
	if err != nil {
		log.Printf("failed to emit stop event: %v\n", err)
	}

	return resp, roundTripErr
}
	Describe("NewHttpStop", func() {
		BeforeEach(func() {
			req.Header.Set("X-CF-ApplicationID", applicationId.String())
		})

		It("should set appropriate fields", func() {
			expectedStopEvent := &events.HttpStop{
				ApplicationId: factories.NewUUID(applicationId),
				RequestId:     factories.NewUUID(requestId),
				Uri:           proto.String("foo.example.com/"),
				PeerType:      events.PeerType_Server.Enum(),
				StatusCode:    proto.Int32(200),
				ContentLength: proto.Int64(3),
			}

			stopEvent := factories.NewHttpStop(req, 200, 3, events.PeerType_Server, requestId)

			Expect(stopEvent.GetTimestamp()).ToNot(BeZero())
			stopEvent.Timestamp = nil

			Expect(stopEvent).To(Equal(expectedStopEvent))
		})
	})

	Describe("StringFromUUID", func() {
		It("returns a string for a UUID", func() {
			id := factories.NewUUID(requestId)
			Expect(factories.StringFromUUID(id)).To(Equal(requestId.String()))
		})
	})
})