// Code generated by sysl DO NOT EDIT.
package petshopmodel

import (
	"encoding/json"

	"github.com/anz-bank/decimal"
	"github.com/anz-bank/sysl/language/go/pkg/relgom/relgomlib"
	"github.com/arr-ai/frozen"
	"github.com/arr-ai/hash"
)

// breedPK is the Key for Breed.
type breedPK struct {
	breedID int64
}

func (k breedPK) Hash(seed uintptr) uintptr {
	seed = hash.Interface(k.breedID, seed)
	return seed
}

func (k breedPK) Equal(i interface{}) bool {
	if l, ok := i.(breedPK); ok {
		return (k == l)
	}
	return false
}

// breedData is the internal representation of a tuple in the model.
type breedData struct {
	breedPK
	breedName   *string
	species     *string
	numLegs     *int64
	avgLifespan *decimal.Decimal64
	avgWeight   *decimal.Decimal64
	legRank     *int64
}

// MarshalJSON implements json.Marshaler.
func (d *breedData) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		BreedID     int64              `json:"breedId,omitempty"`
		BreedName   *string            `json:"breedName,omitempty"`
		Species     *string            `json:"species,omitempty"`
		NumLegs     *int64             `json:"numLegs,omitempty"`
		AvgLifespan *decimal.Decimal64 `json:"avgLifespan,omitempty"`
		AvgWeight   *decimal.Decimal64 `json:"avgWeight,omitempty"`
		LegRank     *int64             `json:"legRank,omitempty"`
	}{BreedID: d.breedID, BreedName: d.breedName, Species: d.species, NumLegs: d.numLegs, AvgLifespan: d.avgLifespan, AvgWeight: d.avgWeight, LegRank: d.legRank})
}

// UnmarshalJSON implements json.Unmarshaler.
func (d *breedData) UnmarshalJSON(data []byte) error {
	var u struct {
		BreedID     int64              `json:"breedId,omitempty"`
		BreedName   *string            `json:"breedName,omitempty"`
		Species     *string            `json:"species,omitempty"`
		NumLegs     *int64             `json:"numLegs,omitempty"`
		AvgLifespan *decimal.Decimal64 `json:"avgLifespan,omitempty"`
		AvgWeight   *decimal.Decimal64 `json:"avgWeight,omitempty"`
		LegRank     *int64             `json:"legRank,omitempty"`
	}
	if err := json.Unmarshal(data, &u); err != nil {
		return err
	}
	*d = breedData{breedPK: breedPK{breedID: u.BreedID}, breedName: u.BreedName, species: u.Species, numLegs: u.NumLegs, avgLifespan: u.AvgLifespan, avgWeight: u.AvgWeight, legRank: u.LegRank}
	return nil
}

// Breed is the public representation tuple in the model.
type Breed struct {
	data  *breedData
	model PetShopModel
}

// BreedID gets the breedId attribute from the Breed.
func (t Breed) BreedID() int64 {
	return t.data.breedID
}

// BreedName gets the breedName attribute from the Breed.
func (t Breed) BreedName() *string {
	return t.data.breedName
}

// Species gets the species attribute from the Breed.
func (t Breed) Species() *string {
	return t.data.species
}

// NumLegs gets the numLegs attribute from the Breed.
func (t Breed) NumLegs() *int64 {
	return t.data.numLegs
}

// AvgLifespan gets the avgLifespan attribute from the Breed.
func (t Breed) AvgLifespan() *decimal.Decimal64 {
	return t.data.avgLifespan
}

// AvgWeight gets the avgWeight attribute from the Breed.
func (t Breed) AvgWeight() *decimal.Decimal64 {
	return t.data.avgWeight
}

// LegRank gets the legRank attribute from the Breed.
func (t Breed) LegRank() *int64 {
	return t.data.legRank
}

// BreedBuilder builds an instance of Breed in the model.
type BreedBuilder struct {
	data  breedData
	model PetShopModel
	mask  [1]uint64
	apply func(t *breedData) (frozen.Map, error)
}

// WithBreedName sets the breedName attribute of the BreedBuilder.
func (b *BreedBuilder) WithBreedName(value string) *BreedBuilder {
	relgomlib.UpdateMaskForFieldButPanicIfAlreadySet(&b.mask[0], (uint64(1) << 1))
	b.data.breedName = &value
	return b
}

// WithSpecies sets the species attribute of the BreedBuilder.
func (b *BreedBuilder) WithSpecies(value string) *BreedBuilder {
	relgomlib.UpdateMaskForFieldButPanicIfAlreadySet(&b.mask[0], (uint64(1) << 2))
	b.data.species = &value
	return b
}

// WithNumLegs sets the numLegs attribute of the BreedBuilder.
func (b *BreedBuilder) WithNumLegs(value int64) *BreedBuilder {
	relgomlib.UpdateMaskForFieldButPanicIfAlreadySet(&b.mask[0], (uint64(1) << 3))
	b.data.numLegs = &value
	return b
}

// WithAvgLifespan sets the avgLifespan attribute of the BreedBuilder.
func (b *BreedBuilder) WithAvgLifespan(value decimal.Decimal64) *BreedBuilder {
	relgomlib.UpdateMaskForFieldButPanicIfAlreadySet(&b.mask[0], (uint64(1) << 4))
	b.data.avgLifespan = &value
	return b
}

// WithAvgWeight sets the avgWeight attribute of the BreedBuilder.
func (b *BreedBuilder) WithAvgWeight(value decimal.Decimal64) *BreedBuilder {
	relgomlib.UpdateMaskForFieldButPanicIfAlreadySet(&b.mask[0], (uint64(1) << 5))
	b.data.avgWeight = &value
	return b
}

// WithLegRank sets the legRank attribute of the BreedBuilder.
func (b *BreedBuilder) WithLegRank(value int64) *BreedBuilder {
	relgomlib.UpdateMaskForFieldButPanicIfAlreadySet(&b.mask[0], (uint64(1) << 6))
	b.data.legRank = &value
	return b
}

var breedStaticMetadata = &relgomlib.EntityTypeStaticMetadata{PKMask: []uint64{0x1}, RequiredMask: []uint64{0x0}}

// Apply applies the built Breed.
func (b *BreedBuilder) Apply() (PetShopModel, Breed, error) {
	relgomlib.PanicIfRequiredFieldsNotSet(b.mask[:], breedStaticMetadata.RequiredMask, ",,,,,,")
	set, err := b.apply(&b.data)
	if err != nil {
		return PetShopModel{}, Breed{}, err
	}
	model := b.model.relations.With(breedKey, breedRelationData{set})
	return PetShopModel{model}, Breed{&b.data, b.model}, nil
}

// breedRelationData represents a set of Breed.
type breedRelationData struct {
	set frozen.Map
}

// Count returns the number of tuples in d.
func (d breedRelationData) Count() int {
	return d.set.Count()
}

// MarshalJSON implements json.Marshaler.
func (d breedRelationData) MarshalJSON() ([]byte, error) {
	a := make([]*breedData, 0, d.set.Count())
	for i := d.set.Range(); i.Next(); {
		a = append(a, i.Value().(*breedData))
	}
	return json.Marshal(a)
}

// UnmarshalJSON implements json.Unmarshaler.
func (d *breedRelationData) UnmarshalJSON(data []byte) error {
	a := []*breedData{}
	if err := json.Unmarshal(data, &a); err != nil {
		return err
	}
	set := frozen.NewMap()
	for _, e := range a {
		set = set.With(e.breedPK, e)
	}
	*d = breedRelationData{set}
	return nil
}

// BreedRelation represents a set of Breed.
type BreedRelation struct {
	breedRelationData
	model PetShopModel
}

// Insert creates a builder to insert a new Breed.
func (r BreedRelation) Insert() *BreedBuilder {
	model, id := r.model.newID()
	return &BreedBuilder{model: model, apply: func(t *breedData) (frozen.Map, error) {
		t.breedID = int64(id)
		set := r.model.GetBreed().set.With(t.breedPK, t)
		return set, nil
	}}
}

// Update creates a builder to update t in the model.
func (r BreedRelation) Update(t Breed) *BreedBuilder {
	b := &BreedBuilder{data: *t.data, model: r.model, apply: func(t *breedData) (frozen.Map, error) {
		set := r.model.GetBreed().set.With(t.breedPK, t)
		return set, nil
	}}
	copy(b.mask[:], breedStaticMetadata.PKMask)
	return b
}

// Delete deletes t from the model.
func (r BreedRelation) Delete(t Breed) (PetShopModel, error) {
	set := r.model.GetBreed().set.Without(frozen.NewSet(t.data.breedPK))
	relations := r.model.relations.With(breedKey, breedRelationData{set: set})
	return PetShopModel{relations: relations}, nil
}

// Lookup searches Breed by primary key.
func (r BreedRelation) Lookup(breedID int64) (Breed, bool) {
	if t, has := r.set.Get(breedPK{breedID: breedID}); has {
		return Breed{data: t.(*breedData), model: r.model}, true
	}
	return Breed{}, false
}

// DeleteWhere deletes tuples matching `where` from r.
func (r BreedRelation) DeleteWhere(where func(t Breed) bool) (PetShopModel, error) {
	model := r.model
	for i := r.Iterator(); i.MoveNext(); {
		t := i.Current()
		if where(t) {
			var err error
			if model, err = model.GetBreed().Delete(t); err != nil {
				return PetShopModel{}, err
			}
		}
	}
	return model, nil
}

// Iterator returns an iterator over Breed tuples in r.
func (r BreedRelation) Iterator() BreedIterator {
	return &breedIterator{model: r.model, i: r.set.Range()}
}

// breedIterator provides for iteration over a set of breedIterator tuples.
type BreedIterator interface {
	MoveNext() bool
	Current() Breed
}

type breedIterator struct {
	model PetShopModel
	i     *frozen.MapIterator
	t     *Breed
}

// MoveNext implements seq.Setable.
func (i *breedIterator) MoveNext() bool {
	if i.i.Next() {
		i.t = &Breed{data: i.i.Value().(*breedData), model: i.model}
		return true
	}
	return false
}

// Current implements seq.Setable.
func (i *breedIterator) Current() Breed {
	if i.t == nil {
		panic("no current Breed")
	}
	return *i.t
}
