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

package jwa

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

	"github.com/lestrrat-go/jwx/v3/internal/tokens"
)

var muAllKeyEncryptionAlgorithm sync.RWMutex
var allKeyEncryptionAlgorithm = map[string]KeyEncryptionAlgorithm{}
var muListKeyEncryptionAlgorithm sync.RWMutex
var listKeyEncryptionAlgorithm []KeyEncryptionAlgorithm
var builtinKeyEncryptionAlgorithm = map[string]struct{}{}

func init() {
	// builtin values for KeyEncryptionAlgorithm
	algorithms := make([]KeyEncryptionAlgorithm, 19)
	algorithms[0] = NewKeyEncryptionAlgorithm(tokens.A128GCMKW, WithIsSymmetric(true))
	algorithms[1] = NewKeyEncryptionAlgorithm(tokens.A128KW, WithIsSymmetric(true))
	algorithms[2] = NewKeyEncryptionAlgorithm(tokens.A192GCMKW, WithIsSymmetric(true))
	algorithms[3] = NewKeyEncryptionAlgorithm(tokens.A192KW, WithIsSymmetric(true))
	algorithms[4] = NewKeyEncryptionAlgorithm(tokens.A256GCMKW, WithIsSymmetric(true))
	algorithms[5] = NewKeyEncryptionAlgorithm(tokens.A256KW, WithIsSymmetric(true))
	algorithms[6] = NewKeyEncryptionAlgorithm(tokens.DIRECT, WithIsSymmetric(true))
	algorithms[7] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES)
	algorithms[8] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES_A128KW)
	algorithms[9] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES_A192KW)
	algorithms[10] = NewKeyEncryptionAlgorithm(tokens.ECDH_ES_A256KW)
	algorithms[11] = NewKeyEncryptionAlgorithm(tokens.PBES2_HS256_A128KW, WithIsSymmetric(true))
	algorithms[12] = NewKeyEncryptionAlgorithm(tokens.PBES2_HS384_A192KW, WithIsSymmetric(true))
	algorithms[13] = NewKeyEncryptionAlgorithm(tokens.PBES2_HS512_A256KW, WithIsSymmetric(true))
	algorithms[14] = NewKeyEncryptionAlgorithm(tokens.RSA1_5, WithDeprecated(true))
	algorithms[15] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP)
	algorithms[16] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP_256)
	algorithms[17] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP_384)
	algorithms[18] = NewKeyEncryptionAlgorithm(tokens.RSA_OAEP_512)

	RegisterKeyEncryptionAlgorithm(algorithms...)
}

// A128GCMKW returns an object representing AES-GCM key wrap (128) key encryption algorithm.
func A128GCMKW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.A128GCMKW)
}

// A128KW returns an object representing AES key wrap (128) key encryption algorithm.
func A128KW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.A128KW)
}

// A192GCMKW returns an object representing AES-GCM key wrap (192) key encryption algorithm.
func A192GCMKW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.A192GCMKW)
}

// A192KW returns an object representing AES key wrap (192) key encryption algorithm.
func A192KW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.A192KW)
}

// A256GCMKW returns an object representing AES-GCM key wrap (256) key encryption algorithm.
func A256GCMKW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.A256GCMKW)
}

// A256KW returns an object representing AES key wrap (256) key encryption algorithm.
func A256KW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.A256KW)
}

// DIRECT returns an object representing Direct key encryption algorithm.
func DIRECT() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.DIRECT)
}

// ECDH_ES returns an object representing ECDH-ES key encryption algorithm.
func ECDH_ES() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES)
}

// ECDH_ES_A128KW returns an object representing ECDH-ES + AES key wrap (128) key encryption algorithm.
func ECDH_ES_A128KW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES_A128KW)
}

// ECDH_ES_A192KW returns an object representing ECDH-ES + AES key wrap (192) key encryption algorithm.
func ECDH_ES_A192KW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES_A192KW)
}

// ECDH_ES_A256KW returns an object representing ECDH-ES + AES key wrap (256) key encryption algorithm.
func ECDH_ES_A256KW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.ECDH_ES_A256KW)
}

// PBES2_HS256_A128KW returns an object representing PBES2 + HMAC-SHA256 + AES key wrap (128) key encryption algorithm.
func PBES2_HS256_A128KW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.PBES2_HS256_A128KW)
}

// PBES2_HS384_A192KW returns an object representing PBES2 + HMAC-SHA384 + AES key wrap (192) key encryption algorithm.
func PBES2_HS384_A192KW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.PBES2_HS384_A192KW)
}

// PBES2_HS512_A256KW returns an object representing PBES2 + HMAC-SHA512 + AES key wrap (256) key encryption algorithm.
func PBES2_HS512_A256KW() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.PBES2_HS512_A256KW)
}

// RSA1_5 returns an object representing RSA-PKCS1v1.5 key encryption algorithm.
func RSA1_5() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA1_5)
}

// RSA_OAEP returns an object representing RSA-OAEP-SHA1 key encryption algorithm.
func RSA_OAEP() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP)
}

// RSA_OAEP_256 returns an object representing RSA-OAEP-SHA256 key encryption algorithm.
func RSA_OAEP_256() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP_256)
}

// RSA_OAEP_384 returns an object representing RSA-OAEP-SHA384 key encryption algorithm.
func RSA_OAEP_384() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP_384)
}

// RSA_OAEP_512 returns an object representing RSA-OAEP-SHA512 key encryption algorithm.
func RSA_OAEP_512() KeyEncryptionAlgorithm {
	return lookupBuiltinKeyEncryptionAlgorithm(tokens.RSA_OAEP_512)
}

func lookupBuiltinKeyEncryptionAlgorithm(name string) KeyEncryptionAlgorithm {
	muAllKeyEncryptionAlgorithm.RLock()
	v, ok := allKeyEncryptionAlgorithm[name]
	muAllKeyEncryptionAlgorithm.RUnlock()
	if !ok {
		panic(fmt.Sprintf(`jwa: KeyEncryptionAlgorithm %q not registered`, name))
	}
	return v
}

// KeyEncryptionAlgorithm represents the various encryption algorithms as described in https://tools.ietf.org/html/rfc7518#section-4.1
type KeyEncryptionAlgorithm struct {
	name        string
	deprecated  bool
	isSymmetric bool
}

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

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

// IsSymmetric returns true if the KeyEncryptionAlgorithm object is symmetric. Symmetric algorithms use the same key for both encryption and decryption.
func (s KeyEncryptionAlgorithm) IsSymmetric() bool {
	return s.isSymmetric
}

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

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

// LookupKeyEncryptionAlgorithm returns the KeyEncryptionAlgorithm object for the given name.
func LookupKeyEncryptionAlgorithm(name string) (KeyEncryptionAlgorithm, bool) {
	muAllKeyEncryptionAlgorithm.RLock()
	v, ok := allKeyEncryptionAlgorithm[name]
	muAllKeyEncryptionAlgorithm.RUnlock()
	return v, ok
}

// RegisterKeyEncryptionAlgorithm registers a new KeyEncryptionAlgorithm. 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.
func RegisterKeyEncryptionAlgorithm(algorithms ...KeyEncryptionAlgorithm) {
	muAllKeyEncryptionAlgorithm.Lock()
	for _, alg := range algorithms {
		allKeyEncryptionAlgorithm[alg.String()] = alg
	}
	muAllKeyEncryptionAlgorithm.Unlock()
	rebuildKeyEncryptionAlgorithm()
}

// UnregisterKeyEncryptionAlgorithm unregisters a KeyEncryptionAlgorithm from its known database.
// Non-existent entries, as well as built-in algorithms will silently be ignored.
func UnregisterKeyEncryptionAlgorithm(algorithms ...KeyEncryptionAlgorithm) {
	muAllKeyEncryptionAlgorithm.Lock()
	for _, alg := range algorithms {
		if _, ok := builtinKeyEncryptionAlgorithm[alg.String()]; ok {
			continue
		}
		delete(allKeyEncryptionAlgorithm, alg.String())
	}
	muAllKeyEncryptionAlgorithm.Unlock()
	rebuildKeyEncryptionAlgorithm()
}

func rebuildKeyEncryptionAlgorithm() {
	list := make([]KeyEncryptionAlgorithm, 0, len(allKeyEncryptionAlgorithm))
	muAllKeyEncryptionAlgorithm.RLock()
	for _, v := range allKeyEncryptionAlgorithm {
		list = append(list, v)
	}
	muAllKeyEncryptionAlgorithm.RUnlock()
	sort.Slice(list, func(i, j int) bool {
		return list[i].String() < list[j].String()
	})
	muListKeyEncryptionAlgorithm.Lock()
	listKeyEncryptionAlgorithm = list
	muListKeyEncryptionAlgorithm.Unlock()
}

// KeyEncryptionAlgorithms returns a list of all available values for KeyEncryptionAlgorithm.
func KeyEncryptionAlgorithms() []KeyEncryptionAlgorithm {
	muListKeyEncryptionAlgorithm.RLock()
	defer muListKeyEncryptionAlgorithm.RUnlock()
	return listKeyEncryptionAlgorithm
}

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

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