package observer

import "sync"

type (
	Event string

	OnNotify func(data interface{}, args ...interface{})

	Listener struct {
		OnNotify OnNotify
	}

	Observer interface {
		AddListener(event Event, listener Listener)
		Remove(event Event)
		Notify(event Event, data interface{}, args ...interface{})
	}

	ObserverImpl struct {
		listeners map[Event][]Listener
	}
)

var (
	obs               *ObserverImpl
	singletonObserver sync.Once
)

func NewObserver() *ObserverImpl {
	singletonObserver.Do(func() {
		obs = &ObserverImpl{}
	})
	return obs
}

func (o *ObserverImpl) AddListener(event Event, listener Listener) {
	if o.listeners == nil {
		o.listeners = map[Event][]Listener{}
	}
	o.listeners[event] = append(o.listeners[event], listener)
}

func (o *ObserverImpl) Remove(event Event) {
	delete(o.listeners, event)
}

func (o *ObserverImpl) Notify(event Event, data interface{}, args ...interface{}) {
	if listeners, ok := o.listeners[event]; !ok {
		return
	} else {
		for _, listener := range listeners {
			go listener.OnNotify(data, args...)
		}
	}
}
