// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package ice

import 

// OnConnectionStateChange sets a handler that is fired when the connection state changes.
func ( *Agent) ( func(ConnectionState)) error {
	.onConnectionStateChangeHdlr.Store()

	return nil
}

// OnSelectedCandidatePairChange sets a handler that is fired when the final candidate.
// pair is selected.
func ( *Agent) ( func(Candidate, Candidate)) error {
	.onSelectedCandidatePairChangeHdlr.Store()

	return nil
}

// OnCandidate sets a handler that is fired when new candidates gathered. When
// the gathering process complete the last candidate is nil.
func ( *Agent) ( func(Candidate)) error {
	.onCandidateHdlr.Store()

	return nil
}

func ( *Agent) ( *CandidatePair) {
	if ,  := .onSelectedCandidatePairChangeHdlr.Load().(func(Candidate, Candidate));  &&  != nil {
		(.Local, .Remote)
	}
}

func ( *Agent) ( Candidate) {
	if ,  := .onCandidateHdlr.Load().(func(Candidate));  &&  != nil {
		()
	}
}

func ( *Agent) ( ConnectionState) {
	if ,  := .onConnectionStateChangeHdlr.Load().(func(ConnectionState));  &&  != nil {
		()
	}
}

type handlerNotifier struct {
	sync.Mutex
	running   bool
	notifiers sync.WaitGroup

	connectionStates    []ConnectionState
	connectionStateFunc func(ConnectionState)

	candidates    []Candidate
	candidateFunc func(Candidate)

	selectedCandidatePairs []*CandidatePair
	candidatePairFunc      func(*CandidatePair)

	// State for closing
	done chan struct{}
}

func ( *handlerNotifier) ( bool) {
	if  {
		// if we were closed ungracefully before, we now
		// want ot wait.
		defer .notifiers.Wait()
	}

	.Lock()

	select {
	case <-.done:
		.Unlock()

		return
	default:
	}
	close(.done)
	.Unlock()
}

func ( *handlerNotifier) ( ConnectionState) {
	.Lock()
	defer .Unlock()

	select {
	case <-.done:
		return
	default:
	}

	 := func() {
		defer .notifiers.Done()
		for {
			.Lock()
			if len(.connectionStates) == 0 {
				.running = false
				.Unlock()

				return
			}
			 := .connectionStates[0]
			.connectionStates = .connectionStates[1:]
			.Unlock()
			.connectionStateFunc()
		}
	}

	.connectionStates = append(.connectionStates, )
	if !.running {
		.running = true
		.notifiers.Add(1)
		go ()
	}
}

func ( *handlerNotifier) ( Candidate) {
	.Lock()
	defer .Unlock()

	select {
	case <-.done:
		return
	default:
	}

	 := func() {
		defer .notifiers.Done()
		for {
			.Lock()
			if len(.candidates) == 0 {
				.running = false
				.Unlock()

				return
			}
			 := .candidates[0]
			.candidates = .candidates[1:]
			.Unlock()
			.candidateFunc()
		}
	}

	.candidates = append(.candidates, )
	if !.running {
		.running = true
		.notifiers.Add(1)
		go ()
	}
}

func ( *handlerNotifier) ( *CandidatePair) {
	.Lock()
	defer .Unlock()

	select {
	case <-.done:
		return
	default:
	}

	 := func() {
		defer .notifiers.Done()
		for {
			.Lock()
			if len(.selectedCandidatePairs) == 0 {
				.running = false
				.Unlock()

				return
			}
			 := .selectedCandidatePairs[0]
			.selectedCandidatePairs = .selectedCandidatePairs[1:]
			.Unlock()
			.candidatePairFunc()
		}
	}

	.selectedCandidatePairs = append(.selectedCandidatePairs, )
	if !.running {
		.running = true
		.notifiers.Add(1)
		go ()
	}
}