package trace

import (
	"expvar"
	"fmt"
	"sync/atomic"

	"code.justin.tv/common/golibs/pkgpath"
)

func init() {
	pkg, ok := pkgpath.Caller(0)
	if !ok {
		return
	}
	publish(pkg, 0)
}

func publish(pkg string, suffix int) {
	// If a package using chitin imports a package which _also_ uses
	// chitin, and both chitin-importers are vendoring chitin, then the
	// 'publish' function can effectively be run twice. Naively, this
	// would panic as an expvar.Publish gets called with the same
	// variable name twice. So, we catch that panic and add an
	// incrementing index number to the end of the variable name. We'll
	// do this up to 100.
	defer func() {
		if r := recover(); r != nil {
			if suffix > 100 {
				// We've been doing this a long time. Something is very broken
				// - it's better to re-raise the panic to let the owner know
				// things are strange.
				//
				// You might see this panic if there are over a hundred
				// different copies of
				// code.justin.tv/common/chitin/internal/trace getting
				// imported, like through vendoring. If you hit this panic,
				// you should definitely raise an issue with the chitin
				// developers.
				panic(r)
			} else {
				publish(pkg, suffix+1)
			}
		}
	}()

	varname := pkg
	if suffix != 0 {
		varname = fmt.Sprintf("%s-%d", pkg, suffix)
	}
	expvar.Publish(varname, expvar.Func(func() interface{} { return exp.dup() }))
}

type expdata struct {
	NoProcInfo    int64
	NoTransaction int64
	MarshalError  int64
	ShortWrite    int64
	WriteError    int64
	FlushError    int64

	EntropyUnderflow int64
}

func (ed *expdata) dup() *expdata {
	var out expdata

	out.NoProcInfo = atomic.LoadInt64(&ed.NoProcInfo)
	out.NoTransaction = atomic.LoadInt64(&ed.NoTransaction)
	out.MarshalError = atomic.LoadInt64(&ed.MarshalError)
	out.ShortWrite = atomic.LoadInt64(&ed.ShortWrite)
	out.WriteError = atomic.LoadInt64(&ed.WriteError)
	out.FlushError = atomic.LoadInt64(&ed.FlushError)

	out.EntropyUnderflow = atomic.LoadInt64(&ed.EntropyUnderflow)

	return &out
}

var exp expdata
