// 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"
)

// employeeManagesEmployeePK is the Key for EmployeeManagesEmployee.
type employeeManagesEmployeePK struct {
	bossID   int64
	minionID int64
}

func (k employeeManagesEmployeePK) Hash(seed uintptr) uintptr {
	seed = hash.Interface(k.bossID, seed)
	seed = hash.Interface(k.minionID, seed)
	return seed
}

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

// employeeManagesEmployeeData is the internal representation of a tuple in the model.
type employeeManagesEmployeeData struct {
	employeeManagesEmployeePK
}

// MarshalJSON implements json.Marshaler.
func (d *employeeManagesEmployeeData) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		BossID   int64 `json:"bossId,omitempty"`
		MinionID int64 `json:"minionId,omitempty"`
	}{BossID: d.bossID, MinionID: d.minionID})
}

// UnmarshalJSON implements json.Unmarshaler.
func (d *employeeManagesEmployeeData) UnmarshalJSON(data []byte) error {
	var u struct {
		BossID   int64 `json:"bossId,omitempty"`
		MinionID int64 `json:"minionId,omitempty"`
	}
	if err := json.Unmarshal(data, &u); err != nil {
		return err
	}
	*d = employeeManagesEmployeeData{employeeManagesEmployeePK: employeeManagesEmployeePK{bossID: u.BossID, minionID: u.MinionID}}
	return nil
}

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

// EmployeeViaBossID gets the Employee corresponding to the bossId attribute from t.
func (t EmployeeManagesEmployee) EmployeeViaBossID() Employee {
	u, _ := t.model.GetEmployee().Lookup(t.data.bossID)
	return u
}

// EmployeeViaMinionID gets the Employee corresponding to the minionId attribute from t.
func (t EmployeeManagesEmployee) EmployeeViaMinionID() Employee {
	u, _ := t.model.GetEmployee().Lookup(t.data.minionID)
	return u
}

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

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

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

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

// Apply applies the built EmployeeManagesEmployee.
func (b *EmployeeManagesEmployeeBuilder) Apply() (PetShopModel, EmployeeManagesEmployee, error) {
	relgomlib.PanicIfRequiredFieldsNotSet(b.mask[:], employeeManagesEmployeeStaticMetadata.RequiredMask, "bossId,minionId")
	set, err := b.apply(&b.data)
	if err != nil {
		return PetShopModel{}, EmployeeManagesEmployee{}, err
	}
	model := b.model.relations.With(employeeManagesEmployeeKey, employeeManagesEmployeeRelationData{set})
	return PetShopModel{model}, EmployeeManagesEmployee{&b.data, b.model}, nil
}

// employeeManagesEmployeeRelationData represents a set of EmployeeManagesEmployee.
type employeeManagesEmployeeRelationData struct {
	set frozen.Map
}

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

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

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

// EmployeeManagesEmployeeRelation represents a set of EmployeeManagesEmployee.
type EmployeeManagesEmployeeRelation struct {
	employeeManagesEmployeeRelationData
	model PetShopModel
}

// Insert creates a builder to insert a new EmployeeManagesEmployee.
func (r EmployeeManagesEmployeeRelation) Insert() *EmployeeManagesEmployeeBuilder {
	return &EmployeeManagesEmployeeBuilder{model: r.model, apply: func(t *employeeManagesEmployeeData) (frozen.Map, error) {
		set := r.model.GetEmployeeManagesEmployee().set.With(t.employeeManagesEmployeePK, t)
		return set, nil
	}}
}

// Update creates a builder to update t in the model.
func (r EmployeeManagesEmployeeRelation) Update(t EmployeeManagesEmployee) *EmployeeManagesEmployeeBuilder {
	b := &EmployeeManagesEmployeeBuilder{data: *t.data, model: r.model, apply: func(t *employeeManagesEmployeeData) (frozen.Map, error) {
		set := r.model.GetEmployeeManagesEmployee().set.With(t.employeeManagesEmployeePK, t)
		return set, nil
	}}
	copy(b.mask[:], employeeManagesEmployeeStaticMetadata.PKMask)
	return b
}

// Delete deletes t from the model.
func (r EmployeeManagesEmployeeRelation) Delete(t EmployeeManagesEmployee) (PetShopModel, error) {
	set := r.model.GetEmployeeManagesEmployee().set.Without(frozen.NewSet(t.data.employeeManagesEmployeePK))
	relations := r.model.relations.With(employeeManagesEmployeeKey, employeeManagesEmployeeRelationData{set: set})
	return PetShopModel{relations: relations}, nil
}

// Lookup searches EmployeeManagesEmployee by primary key.
func (r EmployeeManagesEmployeeRelation) Lookup(bossID int64, minionID int64) (EmployeeManagesEmployee, bool) {
	if t, has := r.set.Get(employeeManagesEmployeePK{bossID: bossID, minionID: minionID}); has {
		return EmployeeManagesEmployee{data: t.(*employeeManagesEmployeeData), model: r.model}, true
	}
	return EmployeeManagesEmployee{}, false
}

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

// Iterator returns an iterator over EmployeeManagesEmployee tuples in r.
func (r EmployeeManagesEmployeeRelation) Iterator() EmployeeManagesEmployeeIterator {
	return &employeeManagesEmployeeIterator{model: r.model, i: r.set.Range()}
}

// employeeManagesEmployeeIterator provides for iteration over a set of employeeManagesEmployeeIterator tuples.
type EmployeeManagesEmployeeIterator interface {
	MoveNext() bool
	Current() EmployeeManagesEmployee
}

type employeeManagesEmployeeIterator struct {
	model PetShopModel
	i     *frozen.MapIterator
	t     *EmployeeManagesEmployee
}

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

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