package main

// these are sentinel errors. Look at article in pointers_errors dictory README.md
// var (
// 	ErrNotFound   = errors.New("could not find word you were looking for")
// 	ErrWordExists = errors.New("key already exists, Add failed")
// )

// Instead we implement our own type that implements the error interface
// This has more benefits because you can do type checks instead of comparing error strings
// or sentinel errors. See the article https://dave.cheney.net/2016/04/07/constant-errors
const (
	ErrNotFound         = DictionaryErr("could not find word you were looking for")
	ErrWordExists       = DictionaryErr("key already exists, Add failed")
	ErrWordDoesNotExist = DictionaryErr("key already exists, Add failed")
)

type DictionaryErr string

func (e DictionaryErr) Error() string {
	return string(e)
}

type Dictionary map[string]string

func (d Dictionary) Search(word string) (string, error) {
	val, ok := d[word]
	if !ok {
		return val, ErrNotFound
	}

	return val, nil
}

// Ok...this works because a map value is a pointer to a runtime.hmap structure
// So when you pass the map reference to this function it's actually copying the
// pointer so no need to &d get mem pointer.
func (d Dictionary) Add(word, definition string) error {
	_, ok := d[word]
	if ok {
		return ErrWordExists
	}

	d[word] = definition
	return nil

	// The authors alt implementation
	// _, err := d.Search(word)

	// switch err {
	// case ErrNotFound:
	// 	d[word] = definition
	// case nil:
	// 	return ErrWordExists
	// default:
	// 	return err
	// }

	// return nil
}

func (d Dictionary) Update(word, definition string) error {
	_, ok := d[word]
	if !ok {
		return ErrWordDoesNotExist
	}
	d[word] = definition
	return nil
}

func (d Dictionary) Delete(word string) {
	//Go has a built-in function delete that works on maps. It takes two arguments. The first is the map and the second is the key to be removed.
	delete(d, word)
}