// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package global // import "go.opentelemetry.io/otel/internal/global"

import (
	
	
	
	

	
	
)

// meterProvider is a placeholder for a configured SDK MeterProvider.
//
// All MeterProvider functionality is forwarded to a delegate once
// configured.
type meterProvider struct {
	embedded.MeterProvider

	mtx    sync.Mutex
	meters map[il]*meter

	delegate metric.MeterProvider
}

// setDelegate configures p to delegate all MeterProvider functionality to
// provider.
//
// All Meters provided prior to this function call are switched out to be
// Meters provided by provider. All instruments and callbacks are recreated and
// delegated.
//
// It is guaranteed by the caller that this happens only once.
func ( *meterProvider) ( metric.MeterProvider) {
	.mtx.Lock()
	defer .mtx.Unlock()

	.delegate = 

	if len(.meters) == 0 {
		return
	}

	for ,  := range .meters {
		.setDelegate()
	}

	.meters = nil
}

// Meter implements MeterProvider.
func ( *meterProvider) ( string,  ...metric.MeterOption) metric.Meter {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Meter(, ...)
	}

	// At this moment it is guaranteed that no sdk is installed, save the meter in the meters map.

	 := metric.NewMeterConfig(...)
	 := il{
		name:    ,
		version: .InstrumentationVersion(),
		schema:  .SchemaURL(),
		attrs:   .InstrumentationAttributes(),
	}

	if .meters == nil {
		.meters = make(map[il]*meter)
	}

	if ,  := .meters[];  {
		return 
	}

	 := &meter{name: , opts: , instruments: make(map[instID]delegatedInstrument)}
	.meters[] = 
	return 
}

// meter is a placeholder for a metric.Meter.
//
// All Meter functionality is forwarded to a delegate once configured.
// Otherwise, all functionality is forwarded to a NoopMeter.
type meter struct {
	embedded.Meter

	name string
	opts []metric.MeterOption

	mtx         sync.Mutex
	instruments map[instID]delegatedInstrument

	registry list.List

	delegate metric.Meter
}

type delegatedInstrument interface {
	setDelegate(metric.Meter)
}

// instID are the identifying properties of a instrument.
type instID struct {
	// name is the name of the stream.
	name string
	// description is the description of the stream.
	description string
	// kind defines the functional group of the instrument.
	kind reflect.Type
	// unit is the unit of the stream.
	unit string
}

// setDelegate configures m to delegate all Meter functionality to Meters
// created by provider.
//
// All subsequent calls to the Meter methods will be passed to the delegate.
//
// It is guaranteed by the caller that this happens only once.
func ( *meter) ( metric.MeterProvider) {
	.mtx.Lock()
	defer .mtx.Unlock()

	 := .Meter(.name, .opts...)
	.delegate = 

	for ,  := range .instruments {
		.setDelegate()
	}

	var  *list.Element
	for  := .registry.Front();  != nil;  =  {
		 := .Value.(*registration)
		.setDelegate()
		 = .Next()
		.registry.Remove()
	}

	.instruments = nil
	.registry.Init()
}

func ( *meter) ( string,  ...metric.Int64CounterOption) (metric.Int64Counter, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Int64Counter(, ...)
	}

	 := metric.NewInt64CounterConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*siCounter)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Int64Counter), nil
	}
	 := &siCounter{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) (
	 string,
	 ...metric.Int64UpDownCounterOption,
) (metric.Int64UpDownCounter, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Int64UpDownCounter(, ...)
	}

	 := metric.NewInt64UpDownCounterConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*siUpDownCounter)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Int64UpDownCounter), nil
	}
	 := &siUpDownCounter{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) ( string,  ...metric.Int64HistogramOption) (metric.Int64Histogram, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Int64Histogram(, ...)
	}

	 := metric.NewInt64HistogramConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*siHistogram)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Int64Histogram), nil
	}
	 := &siHistogram{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) ( string,  ...metric.Int64GaugeOption) (metric.Int64Gauge, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Int64Gauge(, ...)
	}

	 := metric.NewInt64GaugeConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*siGauge)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Int64Gauge), nil
	}
	 := &siGauge{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) (
	 string,
	 ...metric.Int64ObservableCounterOption,
) (metric.Int64ObservableCounter, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Int64ObservableCounter(, ...)
	}

	 := metric.NewInt64ObservableCounterConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*aiCounter)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Int64ObservableCounter), nil
	}
	 := &aiCounter{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) (
	 string,
	 ...metric.Int64ObservableUpDownCounterOption,
) (metric.Int64ObservableUpDownCounter, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Int64ObservableUpDownCounter(, ...)
	}

	 := metric.NewInt64ObservableUpDownCounterConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*aiUpDownCounter)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Int64ObservableUpDownCounter), nil
	}
	 := &aiUpDownCounter{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) (
	 string,
	 ...metric.Int64ObservableGaugeOption,
) (metric.Int64ObservableGauge, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Int64ObservableGauge(, ...)
	}

	 := metric.NewInt64ObservableGaugeConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*aiGauge)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Int64ObservableGauge), nil
	}
	 := &aiGauge{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) ( string,  ...metric.Float64CounterOption) (metric.Float64Counter, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Float64Counter(, ...)
	}

	 := metric.NewFloat64CounterConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*sfCounter)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Float64Counter), nil
	}
	 := &sfCounter{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) (
	 string,
	 ...metric.Float64UpDownCounterOption,
) (metric.Float64UpDownCounter, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Float64UpDownCounter(, ...)
	}

	 := metric.NewFloat64UpDownCounterConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*sfUpDownCounter)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Float64UpDownCounter), nil
	}
	 := &sfUpDownCounter{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) (
	 string,
	 ...metric.Float64HistogramOption,
) (metric.Float64Histogram, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Float64Histogram(, ...)
	}

	 := metric.NewFloat64HistogramConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*sfHistogram)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Float64Histogram), nil
	}
	 := &sfHistogram{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) ( string,  ...metric.Float64GaugeOption) (metric.Float64Gauge, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Float64Gauge(, ...)
	}

	 := metric.NewFloat64GaugeConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*sfGauge)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Float64Gauge), nil
	}
	 := &sfGauge{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) (
	 string,
	 ...metric.Float64ObservableCounterOption,
) (metric.Float64ObservableCounter, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Float64ObservableCounter(, ...)
	}

	 := metric.NewFloat64ObservableCounterConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*afCounter)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Float64ObservableCounter), nil
	}
	 := &afCounter{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) (
	 string,
	 ...metric.Float64ObservableUpDownCounterOption,
) (metric.Float64ObservableUpDownCounter, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Float64ObservableUpDownCounter(, ...)
	}

	 := metric.NewFloat64ObservableUpDownCounterConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*afUpDownCounter)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Float64ObservableUpDownCounter), nil
	}
	 := &afUpDownCounter{name: , opts: }
	.instruments[] = 
	return , nil
}

func ( *meter) (
	 string,
	 ...metric.Float64ObservableGaugeOption,
) (metric.Float64ObservableGauge, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.Float64ObservableGauge(, ...)
	}

	 := metric.NewFloat64ObservableGaugeConfig(...)
	 := instID{
		name:        ,
		kind:        reflect.TypeOf((*afGauge)(nil)),
		description: .Description(),
		unit:        .Unit(),
	}
	if ,  := .instruments[];  {
		return .(metric.Float64ObservableGauge), nil
	}
	 := &afGauge{name: , opts: }
	.instruments[] = 
	return , nil
}

// RegisterCallback captures the function that will be called during Collect.
func ( *meter) ( metric.Callback,  ...metric.Observable) (metric.Registration, error) {
	.mtx.Lock()
	defer .mtx.Unlock()

	if .delegate != nil {
		return .delegate.RegisterCallback(unwrapCallback(), unwrapInstruments()...)
	}

	 := &registration{instruments: , function: }
	 := .registry.PushBack()
	.unreg = func() error {
		.mtx.Lock()
		_ = .registry.Remove()
		.mtx.Unlock()
		return nil
	}
	return , nil
}

func unwrapInstruments( []metric.Observable) []metric.Observable {
	 := make([]metric.Observable, 0, len())

	for ,  := range  {
		if ,  := .(unwrapper);  {
			 = append(, .unwrap())
		} else {
			 = append(, )
		}
	}

	return 
}

type registration struct {
	embedded.Registration

	instruments []metric.Observable
	function    metric.Callback

	unreg   func() error
	unregMu sync.Mutex
}

type unwrapObs struct {
	embedded.Observer
	obs metric.Observer
}

// unwrapFloat64Observable returns an expected metric.Float64Observable after
// unwrapping the global object.
func unwrapFloat64Observable( metric.Float64Observable) metric.Float64Observable {
	if ,  := .(unwrapper);  {
		if ,  := .unwrap().(metric.Float64Observable);  {
			// Note: if the unwrapped object does not
			// unwrap as an observable for either of the
			// predicates here, it means an internal bug in
			// this package.  We avoid logging an error in
			// this case, because the SDK has to try its
			// own type conversion on the object.  The SDK
			// will see this and be forced to respond with
			// its own error.
			//
			// This code uses a double-nested if statement
			// to avoid creating a branch that is
			// impossible to cover.
			 = 
		}
	}
	return 
}

// unwrapInt64Observable returns an expected metric.Int64Observable after
// unwrapping the global object.
func unwrapInt64Observable( metric.Int64Observable) metric.Int64Observable {
	if ,  := .(unwrapper);  {
		if ,  := .unwrap().(metric.Int64Observable);  {
			// See the comment in unwrapFloat64Observable().
			 = 
		}
	}
	return 
}

func ( *unwrapObs) ( metric.Float64Observable,  float64,  ...metric.ObserveOption) {
	.obs.ObserveFloat64(unwrapFloat64Observable(), , ...)
}

func ( *unwrapObs) ( metric.Int64Observable,  int64,  ...metric.ObserveOption) {
	.obs.ObserveInt64(unwrapInt64Observable(), , ...)
}

func unwrapCallback( metric.Callback) metric.Callback {
	return func( context.Context,  metric.Observer) error {
		return (, &unwrapObs{obs: })
	}
}

func ( *registration) ( metric.Meter) {
	.unregMu.Lock()
	defer .unregMu.Unlock()

	if .unreg == nil {
		// Unregister already called.
		return
	}

	,  := .RegisterCallback(unwrapCallback(.function), unwrapInstruments(.instruments)...)
	if  != nil {
		GetErrorHandler().Handle()
		return
	}

	.unreg = .Unregister
}

func ( *registration) () error {
	.unregMu.Lock()
	defer .unregMu.Unlock()
	if .unreg == nil {
		// Unregister already called.
		return nil
	}

	var  error
	, .unreg = .unreg(), nil
	return 
}