package channelz
import (
	
	
	
	
)
type entry interface {
	
	addChild(id int64, e entry)
	
	deleteChild(id int64)
	
	triggerDelete()
	
	deleteSelfIfReady()
	
	getParentID() int64
	Entity
}
type channelMap struct {
	mu               sync.RWMutex
	topLevelChannels map[int64]struct{}
	channels         map[int64]*Channel
	subChannels      map[int64]*SubChannel
	sockets          map[int64]*Socket
	servers          map[int64]*Server
}
func () *channelMap {
	return &channelMap{
		topLevelChannels: make(map[int64]struct{}),
		channels:         make(map[int64]*Channel),
		subChannels:      make(map[int64]*SubChannel),
		sockets:          make(map[int64]*Socket),
		servers:          make(map[int64]*Server),
	}
}
func ( *channelMap) ( int64,  *Server) {
	.mu.Lock()
	defer .mu.Unlock()
	.cm = 
	.servers[] = 
}
func ( *channelMap) ( int64,  *Channel,  bool,  int64) {
	.mu.Lock()
	defer .mu.Unlock()
	.trace.cm = 
	.channels[] = 
	if  {
		.topLevelChannels[] = struct{}{}
	} else if  := .channels[];  != nil {
		.addChild(, )
	} else {
		logger.Infof("channel %d references invalid parent ID %d", , )
	}
}
func ( *channelMap) ( int64,  *SubChannel,  int64) {
	.mu.Lock()
	defer .mu.Unlock()
	.trace.cm = 
	.subChannels[] = 
	if  := .channels[];  != nil {
		.addChild(, )
	} else {
		logger.Infof("subchannel %d references invalid parent ID %d", , )
	}
}
func ( *channelMap) ( *Socket) {
	.mu.Lock()
	defer .mu.Unlock()
	.cm = 
	.sockets[.ID] = 
	if .Parent == nil {
		logger.Infof("normal socket %d has no parent", .ID)
	}
	.Parent.(entry).addChild(.ID, )
}
func ( *channelMap) ( int64) {
	.mu.Lock()
	defer .mu.Unlock()
	.findEntry().triggerDelete()
}
type tracedChannel interface {
	getChannelTrace() *ChannelTrace
	incrTraceRefCount()
	decrTraceRefCount()
	getRefName() string
}
func ( *channelMap) ( int64) {
	 := .findEntry()
	if ,  := .(tracedChannel);  {
		.decrTraceRefCount()
		.deleteSelfIfReady()
	}
}
func ( *channelMap) ( int64) entry {
	if ,  := .channels[];  {
		return 
	}
	if ,  := .subChannels[];  {
		return 
	}
	if ,  := .servers[];  {
		return 
	}
	if ,  := .sockets[];  {
		return 
	}
	return &dummyEntry{idNotFound: }
}
func ( *channelMap) ( int64) entry {
	if ,  := .sockets[];  {
		delete(.sockets, )
		return 
	}
	if ,  := .subChannels[];  {
		delete(.subChannels, )
		return 
	}
	if ,  := .channels[];  {
		delete(.channels, )
		delete(.topLevelChannels, )
		return 
	}
	if ,  := .servers[];  {
		delete(.servers, )
		return 
	}
	return &dummyEntry{idNotFound: }
}
func ( *channelMap) ( int64,  *TraceEvent) {
	.mu.Lock()
	defer .mu.Unlock()
	 := .findEntry()
	,  := .(tracedChannel)
	if ! {
		return
	}
	.getChannelTrace().append(&traceEvent{Desc: .Desc, Severity: .Severity, Timestamp: time.Now()})
	if .Parent != nil {
		 := .findEntry(.getParentID())
		var  RefChannelType
		switch .(type) {
		case *Channel:
			 = RefChannel
		case *SubChannel:
			 = RefSubChannel
		}
		if ,  := .(tracedChannel);  {
			.getChannelTrace().append(&traceEvent{
				Desc:      .Parent.Desc,
				Severity:  .Parent.Severity,
				Timestamp: time.Now(),
				RefID:     ,
				RefName:   .getRefName(),
				RefType:   ,
			})
			.incrTraceRefCount()
		}
	}
}
type int64Slice []int64
func ( int64Slice) () int           { return len() }
func ( int64Slice) (,  int)      { [], [] = [], [] }
func ( int64Slice) (,  int) bool { return [] < [] }
func ( map[int64]string) map[int64]string {
	 := make(map[int64]string)
	for ,  := range  {
		[] = 
	}
	return 
}
func ( *channelMap) ( int64,  int) ([]*Channel, bool) {
	if  <= 0 {
		 = EntriesPerPage
	}
	.mu.RLock()
	defer .mu.RUnlock()
	 := int64(len(.topLevelChannels))
	 := make([]int64, 0, )
	for  := range .topLevelChannels {
		 = append(, )
	}
	sort.Sort(int64Slice())
	 := sort.Search(len(), func( int) bool { return [] >=  })
	 := true
	var  []*Channel
	for ,  := range [:] {
		if len() ==  {
			 = false
			break
		}
		if ,  := .channels[];  {
			 = append(, )
		}
	}
	return , 
}
func ( *channelMap) ( int64,  int) ([]*Server, bool) {
	if  <= 0 {
		 = EntriesPerPage
	}
	.mu.RLock()
	defer .mu.RUnlock()
	 := make([]int64, 0, len(.servers))
	for  := range .servers {
		 = append(, )
	}
	sort.Sort(int64Slice())
	 := sort.Search(len(), func( int) bool { return [] >=  })
	 := true
	var  []*Server
	for ,  := range [:] {
		if len() ==  {
			 = false
			break
		}
		if ,  := .servers[];  {
			 = append(, )
		}
	}
	return , 
}
func ( *channelMap) ( int64,  int64,  int) ([]*Socket, bool) {
	if  <= 0 {
		 = EntriesPerPage
	}
	.mu.RLock()
	defer .mu.RUnlock()
	,  := .servers[]
	if ! {
		
		return nil, true
	}
	 := .sockets
	 := make([]int64, 0, len())
	 := make([]*Socket, 0, min(len(), ))
	for  := range  {
		 = append(, )
	}
	sort.Sort(int64Slice())
	 := sort.Search(len(), func( int) bool { return [] >=  })
	 := true
	for ,  := range [:] {
		if len() ==  {
			 = false
			break
		}
		if ,  := .sockets[];  {
			 = append(, )
		}
	}
	return , 
}
func ( *channelMap) ( int64) *Channel {
	.mu.RLock()
	defer .mu.RUnlock()
	return .channels[]
}
func ( *channelMap) ( int64) *SubChannel {
	.mu.RLock()
	defer .mu.RUnlock()
	return .subChannels[]
}
func ( *channelMap) ( int64) *Socket {
	.mu.RLock()
	defer .mu.RUnlock()
	return .sockets[]
}
func ( *channelMap) ( int64) *Server {
	.mu.RLock()
	defer .mu.RUnlock()
	return .servers[]
}
type dummyEntry struct {
	
	idNotFound int64
	Entity
}
func ( *dummyEntry) () string {
	return fmt.Sprintf("non-existent entity #%d", .idNotFound)
}
func ( *dummyEntry) () int64 { return .idNotFound }
func ( *dummyEntry) ( int64,  entry) {
	
	logger.Infof("attempt to add child of type %T with id %d to a parent (id=%d) that doesn't currently exist", , , .idNotFound)
}
func ( *dummyEntry) ( int64) {
	
	logger.Infof("attempt to delete child with id %d from a parent (id=%d) that doesn't currently exist", , .idNotFound)
}
func ( *dummyEntry) () {
	logger.Warningf("attempt to delete an entry (id=%d) that doesn't currently exist", .idNotFound)
}
func (*dummyEntry) () {
	
}
func (*dummyEntry) () int64 {
	return 0
}
type Entity interface {
	isEntity()
	fmt.Stringer
	id() int64
}