package datastructures

type Set struct {
	elements map[any]bool
}

func (s *Set) Add(el any) {
	s.elements[el] = true
}

func (s *Set) Remove(el any) {
	delete(s.elements, el)
}

func (s *Set) IsEmpty() bool {
	return s.Size() == 0
}

func (s *Set) Size() int {
	return len(s.elements)
}

func (s *Set) Has(el any) bool {
	_, ok := s.elements[el]
	return ok
}

func (s *Set) Difference(set Set) Set {
	d := s.Copy()
	for k := range d.elements {
		if set.Has(k) {
			d.Remove(k)
		}
	}

	return d
}

func (s *Set) IsSubset(t Set) bool {
	for k := range s.elements {
		if !t.Has(k) {
			return false
		}
	}
	return true
}

func (s *Set) List() []any {
	list := make([]any, s.Size())
	for k := range s.elements {
		list = append(list, k)
	}
	return list
}

func (s *Set) Copy() Set {
	c := NewSet()
	for k := range s.elements {
		c.Add(k)
	}
	return c
}

// NewSet creates a new instance of Set
func NewSet() Set {
	return Set{elements: make(map[any]bool)}
}

// Union determines the OR relationship on all sets under consideration
func Union(sets ...Set) Set {
	u := sets[0].Copy()
	for _, set := range sets[1:] {
		for k := range set.elements {
			u.Add(k)
		}
	}
	return u
}

// Intersection determines the AND relationship of all sets under consideration
func Intersection(sets ...Set) Set {
	i := sets[0].Copy()
	for k := range i.elements {
		for _, set := range sets[1:] {
			if !set.Has(k) {
				i.Remove(k)
			}
		}
	}
	return i
}
