// package dict_topic_sub -- потокобезопасный словарь подписчиков локальной шины
package dict_topic_sub

import (
	"sync"

	. "gitp78su.ipnodns.ru/svi/kern/v2/kc/helpers"
	. "gitp78su.ipnodns.ru/svi/kern/v2/krn/kalias"
	"gitp78su.ipnodns.ru/svi/kern/v2/krn/kbus/dict_sub_hook"
	"gitp78su.ipnodns.ru/svi/kern/v2/krn/kctx"
	. "gitp78su.ipnodns.ru/svi/kern/v2/krn/ktypes"
)

type tReadReq struct {
	topic  ATopic
	binMsg []byte
}

// dictTopicSub -- потокобезопасный словарь подписчиков
type dictTopicSub struct {
	sync.RWMutex
	ctx           IKernelCtx
	dictTopicHook map[ATopic]IDictSubHook
}

// NewDictTopicSub -- возвращает потокобезопасный словарь подписчиков
func NewDictTopicSub() IDictTopicSub {
	sf := &dictTopicSub{
		ctx:           kctx.GetKernelCtx(),
		dictTopicHook: map[ATopic]IDictSubHook{},
	}
	return sf
}

// Read -- вызывает обработчики при поступлении события
func (sf *dictTopicSub) Read(topic ATopic, binMsg []byte) {
	sf.RLock()
	defer sf.RUnlock()
	Hassert(topic != "", "dictTopicSub.Read(): topic is empty")
	msg := &tReadReq{
		topic:  topic,
		binMsg: binMsg,
	}
	dictHook := sf.dictTopicHook[msg.topic]
	if dictHook == nil {
		return
	}
	dictHook.Read(msg.binMsg)
}

// Subscribe -- подписывает обработчик на топик
func (sf *dictTopicSub) Subscribe(handler IBusHandlerSubscribe) {
	sf.Lock()
	defer sf.Unlock()
	Hassert(handler != nil, "dictTopicSub.Subscribe(): IBusHandlerSubscribe==nil")
	topic := handler.Topic()
	Hassert(topic != "", "dictTopicSub.Subscribe(): topic is empty")
	dictSubHook := sf.dictTopicHook[topic]
	if dictSubHook == nil {
		dictSubHook = dict_sub_hook.NewDictSubHook()
		sf.dictTopicHook[topic] = dictSubHook
	}
	dictSubHook.Subscribe(handler)
}

// Unsubscribe -- отписывает обработчик
func (sf *dictTopicSub) Unsubscribe(handler IBusHandlerSubscribe) {
	sf.Lock()
	defer sf.Unlock()
	if handler == nil {
		return
	}
	topic := handler.Topic()
	dictSubHook := sf.dictTopicHook[topic]
	if dictSubHook == nil {
		return
	}
	dictSubHook.Unsubscribe(handler)
}
