// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cache

import (
	"sync"
)

type watcher struct {
	id       uint64
	callback func()
}

type WatchMap struct {
	mu       sync.Mutex
	nextID   uint64
	watchers map[interface{}][]watcher
}

func NewWatchMap() *WatchMap {
	return &WatchMap{watchers: make(map[interface{}][]watcher)}
}
func (w *WatchMap) Watch(key interface{}, callback func()) func() {
	w.mu.Lock()
	defer w.mu.Unlock()
	id := w.nextID
	w.nextID++
	w.watchers[key] = append(w.watchers[key], watcher{
		id:       id,
		callback: callback,
	})
	return func() {
		// unwatch if invoked
		w.mu.Lock()
		defer w.mu.Unlock()
		// find and delete the watcher entry
		entries := w.watchers[key]
		for i, entry := range entries {
			if entry.id == id {
				// found it
				entries[i] = entries[len(entries)-1]
				entries = entries[:len(entries)-1]
			}
		}
	}
}

func (w *WatchMap) Notify(key interface{}) {
	w.mu.Lock()
	defer w.mu.Unlock()
	for _, entry := range w.watchers[key] {
		entry.callback()
	}
}
