func (s *InMemorySyncState) IsAppMarkedInStage(app argov1alpha1.Application, stage syncv1alpha1.ProgressiveSyncStage) bool {
	s.Mutex.Lock()
	defer s.Mutex.Unlock()
	value, ok := s.SyncedAtStage[app.Name]
	if ok && value == stage.Name {
		return true
	}
	return false
}
IsAppMarkedInStage returns whether the application is marked in the specified stage
package utils
import (
	"sync"
	syncv1alpha1 "github.com/Skyscanner/applicationset-progressive-sync/api/v1alpha1"
	argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
	"k8s.io/apimachinery/pkg/util/intstr"
)
type ProgressiveSyncState interface {
	MarkAppAsSynced(app argov1alpha1.Application, stage syncv1alpha1.ProgressiveSyncStage)
	RefreshState(apps []argov1alpha1.Application, stage syncv1alpha1.ProgressiveSyncStage)
	IsAppMarkedInStage(app argov1alpha1.Application, stage syncv1alpha1.ProgressiveSyncStage) bool
	GetMaxTargets(stage syncv1alpha1.ProgressiveSyncStage) int
	GetMaxParallel(stage syncv1alpha1.ProgressiveSyncStage) int
	SetHashedSpec(hashedSpec string)
	GetHashedSpec() string
}
type ProgressiveSyncStateManager interface {
	Get(name string) (ProgressiveSyncState, error)
}
type InMemorySyncState struct {
	Name                string
	HashedSpec          string
	SyncedAtStage       map[string]string  
	SyncedAppsPerStage  map[string]int     
	MaxTargetsPerStage  map[string]int
	MaxParallelPerStage map[string]int
	Mutex               *sync.Mutex
}
type ProgressiveSyncStateManagerImpl struct {
	syncStates map[string]ProgressiveSyncState
	Mutex      *sync.Mutex
}
func newProgressiveSyncState(name string) ProgressiveSyncState {
	return &InMemorySyncState{
		Name:                name,
		HashedSpec:          "",
		SyncedAtStage:       make(map[string]string),
		SyncedAppsPerStage:  make(map[string]int),
		MaxTargetsPerStage:  make(map[string]int),
		MaxParallelPerStage: make(map[string]int),
		Mutex:               &sync.Mutex{},
	}
}
func NewProgressiveSyncManager() ProgressiveSyncStateManager {
	return &ProgressiveSyncStateManagerImpl{
		syncStates: make(map[string]ProgressiveSyncState),
		Mutex:      &sync.Mutex{},
	}
}
func (p *ProgressiveSyncStateManagerImpl) Get(name string) (ProgressiveSyncState, error) {
	p.Mutex.Lock()
	defer p.Mutex.Unlock()
	_, ok := p.syncStates[name]
	if !ok {
		p.syncStates[name] = newProgressiveSyncState(name)
	}
	return p.syncStates[name], nil
}
func (s *InMemorySyncState) MarkAppAsSynced(app argov1alpha1.Application, stage syncv1alpha1.ProgressiveSyncStage) {
	s.Mutex.Lock()
	defer s.Mutex.Unlock()
	s.SyncedAtStage[app.Name] = stage.Name
	val, ok := s.SyncedAppsPerStage[stage.Name]
	if !ok {
		s.SyncedAppsPerStage[stage.Name] = 1
	} else {
		if val+1 > s.MaxTargetsPerStage[stage.Name] {
			s.SyncedAppsPerStage[stage.Name] = s.MaxTargetsPerStage[stage.Name]
		} else {
			s.SyncedAppsPerStage[stage.Name] = val + 1
		}
	}
}
func (s *InMemorySyncState) getUnmarkedApps(apps []argov1alpha1.Application, stage syncv1alpha1.ProgressiveSyncStage) []argov1alpha1.Application {
	unmarkedApps := make([]argov1alpha1.Application, 0)
	for _, app := range apps {
		if _, ok := s.SyncedAtStage[app.Name]; !ok {
			unmarkedApps = append(unmarkedApps, app)
		}
	}
	return unmarkedApps
}