// Package goemitter
package goemitter

import (
	"sync"
)

type EventEmitter struct {
	callbacks     map[string][]func(args ...interface{})
	onceCallbacks map[string][]func(args ...interface{})
	lock          sync.Mutex
}

func (e *EventEmitter) On(event string, callback func(args ...interface{})) {
	e.lock.Lock()
	defer e.lock.Unlock()

	if _, ok := e.callbacks[event]; !ok {
		e.callbacks[event] = []func(args ...interface{}){callback}
	} else {
		e.callbacks[event] = append(e.callbacks[event], callback)
	}
}

func (e *EventEmitter) Once(event string, callback func(args ...interface{})) {
	e.lock.Lock()
	defer e.lock.Unlock()

	if _, ok := e.onceCallbacks[event]; !ok {
		e.onceCallbacks[event] = []func(args ...interface{}){callback}
	} else {
		e.onceCallbacks[event] = append(e.onceCallbacks[event], callback)
	}
}

func (e *EventEmitter) Emit(event string, data ...interface{}) {
	e.lock.Lock()
	defer e.lock.Unlock()

	if callbacks, ok := e.callbacks[event]; ok {
		for _, callback := range callbacks {
			go callback(data...)
		}
	}

	if onceCallbacks, ok := e.onceCallbacks[event]; ok {
		for _, callback := range onceCallbacks {
			go callback(data...)

		}
		e.onceCallbacks[event] = []func(args ...interface{}){}
	}
}

func (e *EventEmitter) EmitSync(event string, data ...interface{}) {
	e.lock.Lock()
	defer e.lock.Unlock()

	if callbacks, ok := e.callbacks[event]; ok {
		for _, callback := range callbacks {
			callback(data...)
		}
	}

	if onceCallbacks, ok := e.onceCallbacks[event]; ok {
		for _, callback := range onceCallbacks {
			callback(data...)

		}
		e.onceCallbacks[event] = []func(args ...interface{}){}
	}
}

func NewEmitter() *EventEmitter {
	ret := &EventEmitter{}
	ret.callbacks = make(map[string][]func(args ...interface{}))
	ret.onceCallbacks = make(map[string][]func(args ...interface{}))
	return ret
}
