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

package jwa

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

var muAllSignatureAlgorithm sync.RWMutex
var allSignatureAlgorithm = map[string]SignatureAlgorithm{}
var muListSignatureAlgorithm sync.RWMutex
var listSignatureAlgorithm []SignatureAlgorithm
var builtinSignatureAlgorithm = map[string]struct{}{}

func init() {
	// builtin values for SignatureAlgorithm
	algorithms := make([]SignatureAlgorithm, 15)
	algorithms[0] = NewSignatureAlgorithm("ES256")
	algorithms[1] = NewSignatureAlgorithm("ES256K")
	algorithms[2] = NewSignatureAlgorithm("ES384")
	algorithms[3] = NewSignatureAlgorithm("ES512")
	algorithms[4] = NewSignatureAlgorithm("EdDSA")
	algorithms[5] = NewSignatureAlgorithm("HS256", WithIsSymmetric(true))
	algorithms[6] = NewSignatureAlgorithm("HS384", WithIsSymmetric(true))
	algorithms[7] = NewSignatureAlgorithm("HS512", WithIsSymmetric(true))
	algorithms[8] = NewSignatureAlgorithm("none")
	algorithms[9] = NewSignatureAlgorithm("PS256")
	algorithms[10] = NewSignatureAlgorithm("PS384")
	algorithms[11] = NewSignatureAlgorithm("PS512")
	algorithms[12] = NewSignatureAlgorithm("RS256")
	algorithms[13] = NewSignatureAlgorithm("RS384")
	algorithms[14] = NewSignatureAlgorithm("RS512")

	RegisterSignatureAlgorithm(algorithms...)
}

// ES256 returns an object representing ECDSA signature algorithm using P-256 curve and SHA-256.
func ES256() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("ES256")
}

// ES256K returns an object representing ECDSA signature algorithm using secp256k1 curve and SHA-256.
func ES256K() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("ES256K")
}

// ES384 returns an object representing ECDSA signature algorithm using P-384 curve and SHA-384.
func ES384() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("ES384")
}

// ES512 returns an object representing ECDSA signature algorithm using P-521 curve and SHA-512.
func ES512() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("ES512")
}

// EdDSA returns an object representing EdDSA signature algorithms.
func EdDSA() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("EdDSA")
}

// HS256 returns an object representing HMAC signature algorithm using SHA-256.
func HS256() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("HS256")
}

// HS384 returns an object representing HMAC signature algorithm using SHA-384.
func HS384() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("HS384")
}

// HS512 returns an object representing HMAC signature algorithm using SHA-512.
func HS512() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("HS512")
}

// NoSignature returns an object representing the lack of a signature algorithm. Using this value specifies that the content should not be signed, which you should avoid doing.
func NoSignature() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("none")
}

// PS256 returns an object representing RSASSA-PSS signature algorithm using SHA-256 and MGF1-SHA256.
func PS256() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("PS256")
}

// PS384 returns an object representing RSASSA-PSS signature algorithm using SHA-384 and MGF1-SHA384.
func PS384() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("PS384")
}

// PS512 returns an object representing RSASSA-PSS signature algorithm using SHA-512 and MGF1-SHA512.
func PS512() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("PS512")
}

// RS256 returns an object representing RSASSA-PKCS-v1.5 signature algorithm using SHA-256.
func RS256() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("RS256")
}

// RS384 returns an object representing RSASSA-PKCS-v1.5 signature algorithm using SHA-384.
func RS384() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("RS384")
}

// RS512 returns an object representing RSASSA-PKCS-v1.5 signature algorithm using SHA-512.
func RS512() SignatureAlgorithm {
	return lookupBuiltinSignatureAlgorithm("RS512")
}

func lookupBuiltinSignatureAlgorithm(name string) SignatureAlgorithm {
	muAllSignatureAlgorithm.RLock()
	v, ok := allSignatureAlgorithm[name]
	muAllSignatureAlgorithm.RUnlock()
	if !ok {
		panic(fmt.Sprintf(`jwa: SignatureAlgorithm %q not registered`, name))
	}
	return v
}

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

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

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

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

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

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

// LookupSignatureAlgorithm returns the SignatureAlgorithm object for the given name.
func LookupSignatureAlgorithm(name string) (SignatureAlgorithm, bool) {
	muAllSignatureAlgorithm.RLock()
	v, ok := allSignatureAlgorithm[name]
	muAllSignatureAlgorithm.RUnlock()
	return v, ok
}

// RegisterSignatureAlgorithm registers a new SignatureAlgorithm. 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 RegisterSignatureAlgorithm(algorithms ...SignatureAlgorithm) {
	muAllSignatureAlgorithm.Lock()
	for _, alg := range algorithms {
		allSignatureAlgorithm[alg.String()] = alg
	}
	muAllSignatureAlgorithm.Unlock()
	rebuildSignatureAlgorithm()
}

// UnregisterSignatureAlgorithm unregisters a SignatureAlgorithm from its known database.
// Non-existent entries, as well as built-in algorithms will silently be ignored.
func UnregisterSignatureAlgorithm(algorithms ...SignatureAlgorithm) {
	muAllSignatureAlgorithm.Lock()
	for _, alg := range algorithms {
		if _, ok := builtinSignatureAlgorithm[alg.String()]; ok {
			continue
		}
		delete(allSignatureAlgorithm, alg.String())
	}
	muAllSignatureAlgorithm.Unlock()
	rebuildSignatureAlgorithm()
}

func rebuildSignatureAlgorithm() {
	list := make([]SignatureAlgorithm, 0, len(allSignatureAlgorithm))
	muAllSignatureAlgorithm.RLock()
	for _, v := range allSignatureAlgorithm {
		list = append(list, v)
	}
	muAllSignatureAlgorithm.RUnlock()
	sort.Slice(list, func(i, j int) bool {
		return list[i].String() < list[j].String()
	})
	muListSignatureAlgorithm.Lock()
	listSignatureAlgorithm = list
	muListSignatureAlgorithm.Unlock()
}

// SignatureAlgorithms returns a list of all available values for SignatureAlgorithm.
func SignatureAlgorithms() []SignatureAlgorithm {
	muListSignatureAlgorithm.RLock()
	defer muListSignatureAlgorithm.RUnlock()
	return listSignatureAlgorithm
}

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

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