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

import (
	"encoding/json"

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

// employeeTendsPetPK is the Key for EmployeeTendsPet.
type employeeTendsPetPK struct {
	employeeID int64
	petID      int64
}

func (k employeeTendsPetPK) Hash(seed uintptr) uintptr {
	seed = hash.Interface(k.employeeID, seed)
	seed = hash.Interface(k.petID, seed)
	return seed
}

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

// employeeTendsPetData is the internal representation of a tuple in the model.
type employeeTendsPetData struct {
	employeeTendsPetPK
}

// MarshalJSON implements json.Marshaler.
func (d *employeeTendsPetData) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		EmployeeID int64 `json:"employeeId,omitempty"`
		PetID      int64 `json:"petId,omitempty"`
	}{EmployeeID: d.employeeID, PetID: d.petID})
}

// UnmarshalJSON implements json.Unmarshaler.
func (d *employeeTendsPetData) UnmarshalJSON(data []byte) error {
	var u struct {
		EmployeeID int64 `json:"employeeId,omitempty"`
		PetID      int64 `json:"petId,omitempty"`
	}
	if err := json.Unmarshal(data, &u); err != nil {
		return err
	}
	*d = employeeTendsPetData{employeeTendsPetPK: employeeTendsPetPK{employeeID: u.EmployeeID, petID: u.PetID}}
	return nil
}

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

// Employee gets the Employee corresponding to the employeeId attribute from t.
func (t EmployeeTendsPet) Employee() Employee {
	u, _ := t.model.GetEmployee().Lookup(t.data.employeeID)
	return u
}

// Pet gets the Pet corresponding to the petId attribute from t.
func (t EmployeeTendsPet) Pet() Pet {
	u, _ := t.model.GetPet().Lookup(t.data.petID)
	return u
}

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

// WithEmployee sets the employeeId attribute of the EmployeeTendsPetBuilder from t.
func (b *EmployeeTendsPetBuilder) WithEmployee(t Employee) *EmployeeTendsPetBuilder {
	relgomlib.UpdateMaskForFieldButPanicIfAlreadySet(&b.mask[0], (uint64(1) << 0))
	b.data.employeeID = t.data.employeeID
	return b
}

// WithPet sets the petId attribute of the EmployeeTendsPetBuilder from t.
func (b *EmployeeTendsPetBuilder) WithPet(t Pet) *EmployeeTendsPetBuilder {
	relgomlib.UpdateMaskForFieldButPanicIfAlreadySet(&b.mask[0], (uint64(1) << 1))
	b.data.petID = t.data.petID
	return b
}

var employeeTendsPetStaticMetadata = &relgomlib.EntityTypeStaticMetadata{PKMask: []uint64{0x3}, RequiredMask: []uint64{0x3}}

// Apply applies the built EmployeeTendsPet.
func (b *EmployeeTendsPetBuilder) Apply() (PetShopModel, EmployeeTendsPet, error) {
	relgomlib.PanicIfRequiredFieldsNotSet(b.mask[:], employeeTendsPetStaticMetadata.RequiredMask, "employeeId,petId")
	set, err := b.apply(&b.data)
	if err != nil {
		return PetShopModel{}, EmployeeTendsPet{}, err
	}
	model := b.model.relations.With(employeeTendsPetKey, employeeTendsPetRelationData{set})
	return PetShopModel{model}, EmployeeTendsPet{&b.data, b.model}, nil
}

// employeeTendsPetRelationData represents a set of EmployeeTendsPet.
type employeeTendsPetRelationData struct {
	set frozen.Map
}

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

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

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

// EmployeeTendsPetRelation represents a set of EmployeeTendsPet.
type EmployeeTendsPetRelation struct {
	employeeTendsPetRelationData
	model PetShopModel
}

// Insert creates a builder to insert a new EmployeeTendsPet.
func (r EmployeeTendsPetRelation) Insert() *EmployeeTendsPetBuilder {
	return &EmployeeTendsPetBuilder{model: r.model, apply: func(t *employeeTendsPetData) (frozen.Map, error) {
		set := r.model.GetEmployeeTendsPet().set.With(t.employeeTendsPetPK, t)
		return set, nil
	}}
}

// Update creates a builder to update t in the model.
func (r EmployeeTendsPetRelation) Update(t EmployeeTendsPet) *EmployeeTendsPetBuilder {
	b := &EmployeeTendsPetBuilder{data: *t.data, model: r.model, apply: func(t *employeeTendsPetData) (frozen.Map, error) {
		set := r.model.GetEmployeeTendsPet().set.With(t.employeeTendsPetPK, t)
		return set, nil
	}}
	copy(b.mask[:], employeeTendsPetStaticMetadata.PKMask)
	return b
}

// Delete deletes t from the model.
func (r EmployeeTendsPetRelation) Delete(t EmployeeTendsPet) (PetShopModel, error) {
	set := r.model.GetEmployeeTendsPet().set.Without(frozen.NewSet(t.data.employeeTendsPetPK))
	relations := r.model.relations.With(employeeTendsPetKey, employeeTendsPetRelationData{set: set})
	return PetShopModel{relations: relations}, nil
}

// Lookup searches EmployeeTendsPet by primary key.
func (r EmployeeTendsPetRelation) Lookup(employeeID int64, petID int64) (EmployeeTendsPet, bool) {
	if t, has := r.set.Get(employeeTendsPetPK{employeeID: employeeID, petID: petID}); has {
		return EmployeeTendsPet{data: t.(*employeeTendsPetData), model: r.model}, true
	}
	return EmployeeTendsPet{}, false
}

// DeleteWhere deletes tuples matching `where` from r.
func (r EmployeeTendsPetRelation) DeleteWhere(where func(t EmployeeTendsPet) 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.GetEmployeeTendsPet().Delete(t); err != nil {
				return PetShopModel{}, err
			}
		}
	}
	return model, nil
}

// Iterator returns an iterator over EmployeeTendsPet tuples in r.
func (r EmployeeTendsPetRelation) Iterator() EmployeeTendsPetIterator {
	return &employeeTendsPetIterator{model: r.model, i: r.set.Range()}
}

// employeeTendsPetIterator provides for iteration over a set of employeeTendsPetIterator tuples.
type EmployeeTendsPetIterator interface {
	MoveNext() bool
	Current() EmployeeTendsPet
}

type employeeTendsPetIterator struct {
	model PetShopModel
	i     *frozen.MapIterator
	t     *EmployeeTendsPet
}

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

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