// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package attribute

// Iterator allows iterating over the set of attributes in order, sorted by
// key.
type Iterator struct {
	storage *Set
	idx     int
}

// MergeIterator supports iterating over two sets of attributes while
// eliminating duplicate values from the combined set. The first iterator
// value takes precedence.
type MergeIterator struct {
	one     oneIterator
	two     oneIterator
	current KeyValue
}

type oneIterator struct {
	iter Iterator
	done bool
	attr KeyValue
}

// Next moves the iterator to the next position.
// Next reports whether there are more attributes.
func (i *Iterator) Next() bool {
	i.idx++
	return i.idx < i.Len()
}

// Label returns current KeyValue. Must be called only after Next returns
// true.
//
// Deprecated: Use Attribute instead.
func (i *Iterator) Label() KeyValue {
	return i.Attribute()
}

// Attribute returns the current KeyValue of the Iterator. It must be called
// only after Next returns true.
func (i *Iterator) Attribute() KeyValue {
	kv, _ := i.storage.Get(i.idx)
	return kv
}

// IndexedLabel returns current index and attribute. Must be called only
// after Next returns true.
//
// Deprecated: Use IndexedAttribute instead.
func (i *Iterator) IndexedLabel() (int, KeyValue) {
	return i.idx, i.Attribute()
}

// IndexedAttribute returns current index and attribute. Must be called only
// after Next returns true.
func (i *Iterator) IndexedAttribute() (int, KeyValue) {
	return i.idx, i.Attribute()
}

// Len returns a number of attributes in the iterated set.
func (i *Iterator) Len() int {
	return i.storage.Len()
}

// ToSlice is a convenience function that creates a slice of attributes from
// the passed iterator. The iterator is set up to start from the beginning
// before creating the slice.
func (i *Iterator) ToSlice() []KeyValue {
	l := i.Len()
	if l == 0 {
		return nil
	}
	i.idx = -1
	slice := make([]KeyValue, 0, l)
	for i.Next() {
		slice = append(slice, i.Attribute())
	}
	return slice
}

// NewMergeIterator returns a MergeIterator for merging two attribute sets.
// Duplicates are resolved by taking the value from the first set.
func NewMergeIterator(s1, s2 *Set) MergeIterator {
	mi := MergeIterator{
		one: makeOne(s1.Iter()),
		two: makeOne(s2.Iter()),
	}
	return mi
}

func makeOne(iter Iterator) oneIterator {
	oi := oneIterator{
		iter: iter,
	}
	oi.advance()
	return oi
}

func (oi *oneIterator) advance() {
	if oi.done = !oi.iter.Next(); !oi.done {
		oi.attr = oi.iter.Attribute()
	}
}

// Next moves the iterator to the next position.
// Next reports whether there is another attribute available.
func (m *MergeIterator) Next() bool {
	if m.one.done && m.two.done {
		return false
	}
	if m.one.done {
		m.current = m.two.attr
		m.two.advance()
		return true
	}
	if m.two.done {
		m.current = m.one.attr
		m.one.advance()
		return true
	}
	if m.one.attr.Key == m.two.attr.Key {
		m.current = m.one.attr // first iterator attribute value wins
		m.one.advance()
		m.two.advance()
		return true
	}
	if m.one.attr.Key < m.two.attr.Key {
		m.current = m.one.attr
		m.one.advance()
		return true
	}
	m.current = m.two.attr
	m.two.advance()
	return true
}

// Label returns the current value after Next() returns true.
//
// Deprecated: Use Attribute instead.
func (m *MergeIterator) Label() KeyValue {
	return m.current
}

// Attribute returns the current value after Next() returns true.
func (m *MergeIterator) Attribute() KeyValue {
	return m.current
}
