// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package client

import (
	
	
	
	
)

// Channel number:
//
//	0x4000 through 0x7FFF: These values are the allowed channel
//	numbers (16,383 possible values).
const (
	minChannelNumber uint16 = 0x4000
	maxChannelNumber uint16 = 0x7fff
)

type bindingState int32

const (
	bindingStateIdle bindingState = iota
	bindingStateRequest
	bindingStateReady
	bindingStateRefresh
	bindingStateFailed
)

type binding struct {
	number       uint16          // Read-only
	st           bindingState    // Thread-safe (atomic op)
	addr         net.Addr        // Read-only
	mgr          *bindingManager // Read-only
	muBind       sync.Mutex      // Thread-safe, for ChannelBind ops
	_refreshedAt time.Time       // Protected by mutex
	mutex        sync.RWMutex    // Thread-safe
}

func ( *binding) ( bindingState) {
	atomic.StoreInt32((*int32)(&.st), int32())
}

func ( *binding) () bindingState {
	return bindingState(atomic.LoadInt32((*int32)(&.st)))
}

func ( *binding) ( time.Time) {
	.mutex.Lock()
	defer .mutex.Unlock()

	._refreshedAt = 
}

func ( *binding) () time.Time {
	.mutex.RLock()
	defer .mutex.RUnlock()

	return ._refreshedAt
}

// Thread-safe binding map.
type bindingManager struct {
	chanMap map[uint16]*binding
	addrMap map[string]*binding
	next    uint16
	mutex   sync.RWMutex
}

func newBindingManager() *bindingManager {
	return &bindingManager{
		chanMap: map[uint16]*binding{},
		addrMap: map[string]*binding{},
		next:    minChannelNumber,
	}
}

func ( *bindingManager) () uint16 {
	 := .next
	if .next == maxChannelNumber {
		.next = minChannelNumber
	} else {
		.next++
	}

	return 
}

func ( *bindingManager) ( net.Addr) *binding {
	.mutex.Lock()
	defer .mutex.Unlock()

	 := &binding{
		number:       .assignChannelNumber(),
		addr:         ,
		mgr:          ,
		_refreshedAt: time.Now(),
	}

	.chanMap[.number] = 
	.addrMap[.addr.String()] = 

	return 
}

func ( *bindingManager) ( net.Addr) (*binding, bool) {
	.mutex.RLock()
	defer .mutex.RUnlock()

	,  := .addrMap[.String()]

	return , 
}

func ( *bindingManager) ( uint16) (*binding, bool) {
	.mutex.RLock()
	defer .mutex.RUnlock()

	,  := .chanMap[]

	return , 
}

func ( *bindingManager) ( net.Addr) bool {
	.mutex.Lock()
	defer .mutex.Unlock()

	,  := .addrMap[.String()]
	if ! {
		return false
	}

	delete(.addrMap, .String())
	delete(.chanMap, .number)

	return true
}

func ( *bindingManager) ( uint16) bool {
	.mutex.Lock()
	defer .mutex.Unlock()

	,  := .chanMap[]
	if ! {
		return false
	}

	delete(.addrMap, .addr.String())
	delete(.chanMap, )

	return true
}

func ( *bindingManager) () int {
	.mutex.RLock()
	defer .mutex.RUnlock()

	return len(.chanMap)
}