package callgraph

import (
	"time"

	"code.justin.tv/release/trace/pbmsg"
)

// callEndpoint represents one endpoint in a call (ie client or server)
type callEndpoint struct {
	// svc is how the end identifies itself. typically, this is in the
	// style repo/binary, for example,
	// code.justin.tv/release/trace/pbreport.
	svc string
	// host is the fqdn that the end believes itself to be running on
	host string
	// peer is the fqdn of the peer that the end thinks its talking to
	peer string
	// pid is the process id that the end believes itself to be running under
	pid int32
	// start is the earliest timestamp reported from this end
	start *time.Time
	// end is the latest timestamp reported from this end
	end *time.Time
	// nanos is end - start
	nanos time.Duration
}

func (ce *callEndpoint) from(e *pbmsg.Event) {
	ce.svc = e.GetSvcname()
	ce.host = e.GetHostname()
	ce.pid = e.GetPid()

	extra := e.GetExtra()
	if extra != nil {
		if peer := extra.GetPeer(); peer != "" {
			ce.peer = peer
		}
	}
	ce.fillTimes(e)
}

func (ce *callEndpoint) fillTimes(e *pbmsg.Event) {
	request := isRequestEvent(e)
	timestamp := time.Unix(0, e.GetTime())
	if request {
		if ce.start == nil || timestamp.Before(*ce.start) {
			ce.start = &timestamp
		}
	} else {
		if ce.end == nil || timestamp.After(*ce.end) {
			ce.end = &timestamp
		}
	}
	if ce.start != nil && ce.end != nil {
		ce.nanos = ce.end.Sub(*ce.start)
	}

}

// call provides a reduced summary of a set of events
type call struct {
	client callEndpoint
	server callEndpoint
	rpc    RPCAnnotation
}

// update updates the call with information from a single event.
func (c *call) update(e *pbmsg.Event) {
	if isClientEvent(e) {
		c.client.from(e)
	} else {
		c.server.from(e)
	}

	if c.rpc == nil {
		c.rpc = newAnnotation(e, c)
	} else {
		c.rpc.Fill(e, c)
	}
}
