package tx

// A TransactionSet groups together a collection of transactions,
// providing query interfaces into the collection.
type TransactionSet interface {
	// Add adds a transaction to the set.
	Add(*Transaction)
	// All returns all transactions in the set as a slice. The slice
	// may not be modified safely.
	All() []*Transaction
	// Sorted returns all transactions in the set as a sorted
	// slice. The slice may not be modified safely.
	Sorted(SortOrder) []*Transaction
	// Len returns the number of transactions in the set.
	Len() int
}

// TransactionSetFactory is a function which produces new, empty
// TransactionSets.
type TransactionSetFactory func() TransactionSet

// InMemoryTransactionSet implements the TransactionSet interface by
// holding pointers to all the transactions in memory. Sorts are
// accomplished by redundantly holding the pointers in separate slices
// which are lazily resorted whenever Sort or Percentile are called.
type InMemoryTransactionSet struct {
	txs map[SortOrder][]*Transaction
}

func NewInMemoryTransactionSet() TransactionSet {
	return &InMemoryTransactionSet{
		txs: map[SortOrder][]*Transaction{
			Unsorted: make([]*Transaction, 0),
		},
	}
}

func (imts *InMemoryTransactionSet) Add(tx *Transaction) {
	imts.txs[Unsorted] = append(imts.txs[Unsorted], tx)
}

func (imts *InMemoryTransactionSet) All() []*Transaction {
	return imts.txs[Unsorted]
}

func (imts *InMemoryTransactionSet) Sorted(order SortOrder) []*Transaction {
	if !imts.isSorted(order) {
		imts.sort(order)
	}
	return imts.txs[order]
}

func (imts *InMemoryTransactionSet) Len() int {
	return len(imts.txs[Unsorted])
}

// isSorted returns true if the transactions are already sorted by the
// given SortOrder. This function makes the strong assumption that
// Transactions can only be added to the set, never removed.
func (imts *InMemoryTransactionSet) isSorted(order SortOrder) bool {
	return len(imts.txs[order]) == len(imts.txs[Unsorted])
}

// sort re-sorts the transactions in the set for the given order
func (imts *InMemoryTransactionSet) sort(order SortOrder) {
	imts.txs[order] = Sort(order, imts.txs[Unsorted])
}
