// 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 muAllContentEncryptionAlgorithm sync.RWMutex
var allContentEncryptionAlgorithm = map[string]ContentEncryptionAlgorithm{}
var muListContentEncryptionAlgorithm sync.RWMutex
var listContentEncryptionAlgorithm []ContentEncryptionAlgorithm
var builtinContentEncryptionAlgorithm = map[string]struct{}{}

func init() {
	// builtin values for ContentEncryptionAlgorithm
	algorithms := make([]ContentEncryptionAlgorithm, 6)
	algorithms[0] = NewContentEncryptionAlgorithm(tokens.A128CBC_HS256)
	algorithms[1] = NewContentEncryptionAlgorithm(tokens.A128GCM)
	algorithms[2] = NewContentEncryptionAlgorithm(tokens.A192CBC_HS384)
	algorithms[3] = NewContentEncryptionAlgorithm(tokens.A192GCM)
	algorithms[4] = NewContentEncryptionAlgorithm(tokens.A256CBC_HS512)
	algorithms[5] = NewContentEncryptionAlgorithm(tokens.A256GCM)

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

// A128CBC_HS256 returns an object representing A128CBC-HS256. Using this value specifies that the content should be encrypted using AES-CBC + HMAC-SHA256 (128).
func A128CBC_HS256() ContentEncryptionAlgorithm {
	return lookupBuiltinContentEncryptionAlgorithm(tokens.A128CBC_HS256)
}

// A128GCM returns an object representing A128GCM. Using this value specifies that the content should be encrypted using AES-GCM (128).
func A128GCM() ContentEncryptionAlgorithm {
	return lookupBuiltinContentEncryptionAlgorithm(tokens.A128GCM)
}

// A192CBC_HS384 returns an object representing A192CBC-HS384. Using this value specifies that the content should be encrypted using AES-CBC + HMAC-SHA384 (192).
func A192CBC_HS384() ContentEncryptionAlgorithm {
	return lookupBuiltinContentEncryptionAlgorithm(tokens.A192CBC_HS384)
}

// A192GCM returns an object representing A192GCM. Using this value specifies that the content should be encrypted using AES-GCM (192).
func A192GCM() ContentEncryptionAlgorithm {
	return lookupBuiltinContentEncryptionAlgorithm(tokens.A192GCM)
}

// A256CBC_HS512 returns an object representing A256CBC-HS512. Using this value specifies that the content should be encrypted using AES-CBC + HMAC-SHA512 (256).
func A256CBC_HS512() ContentEncryptionAlgorithm {
	return lookupBuiltinContentEncryptionAlgorithm(tokens.A256CBC_HS512)
}

// A256GCM returns an object representing A256GCM. Using this value specifies that the content should be encrypted using AES-GCM (256).
func A256GCM() ContentEncryptionAlgorithm {
	return lookupBuiltinContentEncryptionAlgorithm(tokens.A256GCM)
}

func lookupBuiltinContentEncryptionAlgorithm(name string) ContentEncryptionAlgorithm {
	muAllContentEncryptionAlgorithm.RLock()
	v, ok := allContentEncryptionAlgorithm[name]
	muAllContentEncryptionAlgorithm.RUnlock()
	if !ok {
		panic(fmt.Sprintf(`jwa: ContentEncryptionAlgorithm %q not registered`, name))
	}
	return v
}

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

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

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

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

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

// LookupContentEncryptionAlgorithm returns the ContentEncryptionAlgorithm object for the given name.
func LookupContentEncryptionAlgorithm(name string) (ContentEncryptionAlgorithm, bool) {
	muAllContentEncryptionAlgorithm.RLock()
	v, ok := allContentEncryptionAlgorithm[name]
	muAllContentEncryptionAlgorithm.RUnlock()
	return v, ok
}

// RegisterContentEncryptionAlgorithm registers a new ContentEncryptionAlgorithm. 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 RegisterContentEncryptionAlgorithm(algorithms ...ContentEncryptionAlgorithm) {
	muAllContentEncryptionAlgorithm.Lock()
	defer muAllContentEncryptionAlgorithm.Unlock()
	for _, alg := range algorithms {
		if _, ok := builtinContentEncryptionAlgorithm[alg.String()]; ok {
			if existing, ok := allContentEncryptionAlgorithm[alg.String()]; ok && existing != alg {
				continue
			}
			continue
		}
		allContentEncryptionAlgorithm[alg.String()] = alg
	}
	rebuildContentEncryptionAlgorithmLocked()
}

// UnregisterContentEncryptionAlgorithm unregisters a ContentEncryptionAlgorithm from its known database.
// Non-existent entries, as well as built-in algorithms will silently be ignored.
func UnregisterContentEncryptionAlgorithm(algorithms ...ContentEncryptionAlgorithm) {
	muAllContentEncryptionAlgorithm.Lock()
	defer muAllContentEncryptionAlgorithm.Unlock()
	for _, alg := range algorithms {
		if _, ok := builtinContentEncryptionAlgorithm[alg.String()]; ok {
			continue
		}
		delete(allContentEncryptionAlgorithm, alg.String())
	}
	rebuildContentEncryptionAlgorithmLocked()
}

func rebuildContentEncryptionAlgorithmLocked() {
	list := make([]ContentEncryptionAlgorithm, 0, len(allContentEncryptionAlgorithm))
	for _, v := range allContentEncryptionAlgorithm {
		list = append(list, v)
	}
	sort.Slice(list, func(i, j int) bool {
		return list[i].String() < list[j].String()
	})
	muListContentEncryptionAlgorithm.Lock()
	listContentEncryptionAlgorithm = list
	muListContentEncryptionAlgorithm.Unlock()
}

// ContentEncryptionAlgorithms returns a list of all available values for ContentEncryptionAlgorithm.
func ContentEncryptionAlgorithms() []ContentEncryptionAlgorithm {
	muListContentEncryptionAlgorithm.RLock()
	defer muListContentEncryptionAlgorithm.RUnlock()
	return listContentEncryptionAlgorithm
}

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

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