// Code generated by tools/cmd/genjwa/main.go. DO NOT EDIT.

package jwa

import (
	"encoding/json"
	"fmt"
	"sort"
	"sync"
)

var muAllKeyType sync.RWMutex
var allKeyType = map[string]KeyType{}
var muListKeyType sync.RWMutex
var listKeyType []KeyType
var builtinKeyType = map[string]struct{}{}

func init() {
	// builtin values for KeyType
	algorithms := make([]KeyType, 4)
	algorithms[0] = NewKeyType("EC")
	algorithms[1] = NewKeyType("OKP")
	algorithms[2] = NewKeyType("oct")
	algorithms[3] = NewKeyType("RSA")

	RegisterKeyType(algorithms...)
	for _, alg := range algorithms {
		builtinKeyType[alg.String()] = struct{}{}
	}
}

// EC returns an object representing EC. Elliptic Curve
func EC() KeyType {
	return lookupBuiltinKeyType("EC")
}

var invalidKeyType = NewKeyType("")

// InvalidKeyType returns an object representing invalid key type. Invalid KeyType
func InvalidKeyType() KeyType {
	return invalidKeyType
}

// OKP returns an object representing OKP. Octet string key pairs
func OKP() KeyType {
	return lookupBuiltinKeyType("OKP")
}

// OctetSeq returns an object representing oct. Octet sequence (used to represent symmetric keys)
func OctetSeq() KeyType {
	return lookupBuiltinKeyType("oct")
}

// RSA returns an object representing RSA. RSA
func RSA() KeyType {
	return lookupBuiltinKeyType("RSA")
}

func lookupBuiltinKeyType(name string) KeyType {
	muAllKeyType.RLock()
	v, ok := allKeyType[name]
	muAllKeyType.RUnlock()
	if !ok {
		panic(fmt.Sprintf(`jwa: KeyType %q not registered`, name))
	}
	return v
}

// KeyType represents the key type ("kty") that are supported
type KeyType struct {
	name       string
	deprecated bool
}

func (s KeyType) String() string {
	return s.name
}

// IsDeprecated returns true if the KeyType object is deprecated.
func (s KeyType) IsDeprecated() bool {
	return s.deprecated
}

// EmptyKeyType returns an empty KeyType object, used as a zero value.
func EmptyKeyType() KeyType {
	return KeyType{}
}

// NewKeyType creates a new KeyType object with the given name.
func NewKeyType(name string, options ...NewAlgorithmOption) KeyType {
	var deprecated bool
	for _, option := range options {
		switch option.Ident() {
		case identDeprecated{}:
			if err := option.Value(&deprecated); err != nil {
				panic("jwa.NewKeyType: WithDeprecated option must be a boolean")
			}
		}
	}
	return KeyType{name: name, deprecated: deprecated}
}

// LookupKeyType returns the KeyType object for the given name.
func LookupKeyType(name string) (KeyType, bool) {
	muAllKeyType.RLock()
	v, ok := allKeyType[name]
	muAllKeyType.RUnlock()
	return v, ok
}

// RegisterKeyType registers a new KeyType. The signature value must be immutable
// and safe to be used by multiple goroutines, as it is going to be shared with all other users of this library.
//
// Registration is process-global. Built-in identifiers such as RS256 are
// reserved and cannot be replaced by callers after init has completed; use a
// distinct name for third-party algorithms.
func RegisterKeyType(algorithms ...KeyType) {
	muAllKeyType.Lock()
	defer muAllKeyType.Unlock()
	for _, alg := range algorithms {
		if _, ok := builtinKeyType[alg.String()]; ok {
			if existing, ok := allKeyType[alg.String()]; ok && existing != alg {
				continue
			}
			continue
		}
		allKeyType[alg.String()] = alg
	}
	rebuildKeyTypeLocked()
}

// UnregisterKeyType unregisters a KeyType from its known database.
// Non-existent entries, as well as built-in algorithms will silently be ignored.
func UnregisterKeyType(algorithms ...KeyType) {
	muAllKeyType.Lock()
	defer muAllKeyType.Unlock()
	for _, alg := range algorithms {
		if _, ok := builtinKeyType[alg.String()]; ok {
			continue
		}
		delete(allKeyType, alg.String())
	}
	rebuildKeyTypeLocked()
}

func rebuildKeyTypeLocked() {
	list := make([]KeyType, 0, len(allKeyType))
	for _, v := range allKeyType {
		list = append(list, v)
	}
	sort.Slice(list, func(i, j int) bool {
		return list[i].String() < list[j].String()
	})
	muListKeyType.Lock()
	listKeyType = list
	muListKeyType.Unlock()
}

// KeyTypes returns a list of all available values for KeyType.
func KeyTypes() []KeyType {
	muListKeyType.RLock()
	defer muListKeyType.RUnlock()
	return listKeyType
}

// MarshalJSON serializes the KeyType object to a JSON string.
func (s KeyType) MarshalJSON() ([]byte, error) {
	return json.Marshal(s.String())
}

// UnmarshalJSON deserializes the JSON string to a KeyType object.
func (s *KeyType) UnmarshalJSON(data []byte) error {
	var name string
	if err := json.Unmarshal(data, &name); err != nil {
		return fmt.Errorf(`failed to unmarshal KeyType: %w`, err)
	}
	v, ok := LookupKeyType(name)
	if !ok {
		return fmt.Errorf(`unknown KeyType: %q`, name)
	}
	*s = v
	return nil
}
