package collection

import (
	. "gitea.zaclys.com/bvaudour/gob/option"
)

// Stack représente une pile d’élément.
// Une pile est une collection où les éléments suivant la logique “dernier arrivé, premier servi“.
type Stack[T any] struct {
	first *chain[T]
	size  uint
}

// Len retourne le nombre d’éléments de la pile.
func (s Stack[T]) Len() uint {
	return s.size
}

// Push ajoute tous les éléments d’entrée dans la pile.
func (s *Stack[T]) Push(elems ...T) {
	for _, e := range elems {
		s.first = prevChain(e, s.first)
		s.size++
	}
}

// Pop dépile le premier élément de la pile et le retourne.
func (s *Stack[T]) Pop() (e Option[T]) {
	if s.size > 0 {
		e = Some(s.first.value)
		s.first = s.first.next
		s.size--
	}

	return
}

// ToSlice convertit une pile en slice.
func (s *Stack[T]) ToSlice() (sl []T) {
	sl = make([]T, s.size)
	c := s.first
	for i := uint(0); i < s.size; i++ {
		sl[i] = c.value
		c = c.next
	}

	return
}

// ToQueue convertit une pile en file.
func (s *Stack[T]) ToQueue() (q *Queue[T]) {
	q = &Queue[T]{
		first: s.first,
		size:  s.size,
	}

	var c = s.first
	for i := uint(1); i < s.size; i++ {
		c = c.next
	}
	q.last = c

	return
}

// NewStack retourne une pile initialisée à partir des données d’entrées.
func NewStack[T any](elems ...T) (s *Stack[T]) {
	s = new(Stack[T])
	s.Push(elems...)

	return
}
