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

package jwa

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

var muAllEllipticCurveAlgorithm sync.RWMutex
var allEllipticCurveAlgorithm = map[string]EllipticCurveAlgorithm{}
var muListEllipticCurveAlgorithm sync.RWMutex
var listEllipticCurveAlgorithm []EllipticCurveAlgorithm
var builtinEllipticCurveAlgorithm = map[string]struct{}{}

func init() {
	// builtin values for EllipticCurveAlgorithm
	algorithms := make([]EllipticCurveAlgorithm, 7)
	algorithms[0] = NewEllipticCurveAlgorithm("Ed25519")
	algorithms[1] = NewEllipticCurveAlgorithm("Ed448")
	algorithms[2] = NewEllipticCurveAlgorithm("P-256")
	algorithms[3] = NewEllipticCurveAlgorithm("P-384")
	algorithms[4] = NewEllipticCurveAlgorithm("P-521")
	algorithms[5] = NewEllipticCurveAlgorithm("X25519")
	algorithms[6] = NewEllipticCurveAlgorithm("X448")

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

// Ed25519 returns an object representing Ed25519 algorithm for EdDSA operations.
func Ed25519() EllipticCurveAlgorithm {
	return lookupBuiltinEllipticCurveAlgorithm("Ed25519")
}

// Ed448 returns an object representing Ed448 algorithm for EdDSA operations.
func Ed448() EllipticCurveAlgorithm {
	return lookupBuiltinEllipticCurveAlgorithm("Ed448")
}

var invalidEllipticCurve = NewEllipticCurveAlgorithm("P-invalid")

// InvalidEllipticCurve returns an object representing an invalid elliptic curve.
func InvalidEllipticCurve() EllipticCurveAlgorithm {
	return invalidEllipticCurve
}

// P256 returns an object representing P-256 algorithm for ECDSA operations.
func P256() EllipticCurveAlgorithm {
	return lookupBuiltinEllipticCurveAlgorithm("P-256")
}

// P384 returns an object representing P-384 algorithm for ECDSA operations.
func P384() EllipticCurveAlgorithm {
	return lookupBuiltinEllipticCurveAlgorithm("P-384")
}

// P521 returns an object representing P-521 algorithm for ECDSA operations.
func P521() EllipticCurveAlgorithm {
	return lookupBuiltinEllipticCurveAlgorithm("P-521")
}

// X25519 returns an object representing X25519 algorithm for ECDH operations.
func X25519() EllipticCurveAlgorithm {
	return lookupBuiltinEllipticCurveAlgorithm("X25519")
}

// X448 returns an object representing X448 algorithm for ECDH operations.
func X448() EllipticCurveAlgorithm {
	return lookupBuiltinEllipticCurveAlgorithm("X448")
}

func lookupBuiltinEllipticCurveAlgorithm(name string) EllipticCurveAlgorithm {
	muAllEllipticCurveAlgorithm.RLock()
	v, ok := allEllipticCurveAlgorithm[name]
	muAllEllipticCurveAlgorithm.RUnlock()
	if !ok {
		panic(fmt.Sprintf(`jwa: EllipticCurveAlgorithm %q not registered`, name))
	}
	return v
}

// EllipticCurveAlgorithm represents the algorithms used for EC keys
type EllipticCurveAlgorithm struct {
	name       string
	deprecated bool
}

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

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

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

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

// LookupEllipticCurveAlgorithm returns the EllipticCurveAlgorithm object for the given name.
func LookupEllipticCurveAlgorithm(name string) (EllipticCurveAlgorithm, bool) {
	muAllEllipticCurveAlgorithm.RLock()
	v, ok := allEllipticCurveAlgorithm[name]
	muAllEllipticCurveAlgorithm.RUnlock()
	return v, ok
}

// RegisterEllipticCurveAlgorithm registers a new EllipticCurveAlgorithm. 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 RegisterEllipticCurveAlgorithm(algorithms ...EllipticCurveAlgorithm) {
	muAllEllipticCurveAlgorithm.Lock()
	defer muAllEllipticCurveAlgorithm.Unlock()
	for _, alg := range algorithms {
		if _, ok := builtinEllipticCurveAlgorithm[alg.String()]; ok {
			if existing, ok := allEllipticCurveAlgorithm[alg.String()]; ok && existing != alg {
				continue
			}
			continue
		}
		allEllipticCurveAlgorithm[alg.String()] = alg
	}
	rebuildEllipticCurveAlgorithmLocked()
}

// UnregisterEllipticCurveAlgorithm unregisters a EllipticCurveAlgorithm from its known database.
// Non-existent entries, as well as built-in algorithms will silently be ignored.
func UnregisterEllipticCurveAlgorithm(algorithms ...EllipticCurveAlgorithm) {
	muAllEllipticCurveAlgorithm.Lock()
	defer muAllEllipticCurveAlgorithm.Unlock()
	for _, alg := range algorithms {
		if _, ok := builtinEllipticCurveAlgorithm[alg.String()]; ok {
			continue
		}
		delete(allEllipticCurveAlgorithm, alg.String())
	}
	rebuildEllipticCurveAlgorithmLocked()
}

func rebuildEllipticCurveAlgorithmLocked() {
	list := make([]EllipticCurveAlgorithm, 0, len(allEllipticCurveAlgorithm))
	for _, v := range allEllipticCurveAlgorithm {
		list = append(list, v)
	}
	sort.Slice(list, func(i, j int) bool {
		return list[i].String() < list[j].String()
	})
	muListEllipticCurveAlgorithm.Lock()
	listEllipticCurveAlgorithm = list
	muListEllipticCurveAlgorithm.Unlock()
}

// EllipticCurveAlgorithms returns a list of all available values for EllipticCurveAlgorithm.
func EllipticCurveAlgorithms() []EllipticCurveAlgorithm {
	muListEllipticCurveAlgorithm.RLock()
	defer muListEllipticCurveAlgorithm.RUnlock()
	return listEllipticCurveAlgorithm
}

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

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