classes/MultiLevelCounter.ps1

class MultiLevelCounter {
    [int[]] $Counters
    [System.Collections.Stack] $History
    [int] $HighestSavedLevel = -1

    MultiLevelCounter([int]$levels) {
        $this.Counters = @(0) * $levels
        $this.History = [System.Collections.Stack]::new()
    }

    [void] Inc([int]$idx) {
        if ($idx -lt 0 -or $idx -ge $this.Counters.Count) {
            throw "Invalid counter index: $idx"
        }

        # Save history only when incrementing a higher-level counter
        if ($idx -lt $this.HighestSavedLevel -or $this.HighestSavedLevel -eq -1) {
            $this.History.Push(@($this.Counters))
            $this.HighestSavedLevel = $idx
        }

        # Increment the selected counter
        $this.Counters[$idx]++

        # Reset all lower counters
        for ($i = $idx + 1; $i -lt $this.Counters.Count; $i++) {
            $this.Counters[$i] = 0
        }
    }

    [void] Dec([int]$idx) {
        if ($idx -lt 0 -or $idx -ge $this.Counters.Count) {
            throw "Invalid counter index: $idx"
        }

        $this.Counters[$idx]--

        if ($this.Counters[$idx] -lt 0) {
            # Underflow – restore previous saved state if any
            if ($this.History.Count -gt 0) {
                $this.Counters = @($this.History.Pop())
                # Update highest saved level if possible
                if ($this.History.Count -gt 0) {
                    $peek = $this.History.Peek()
                    $this.HighestSavedLevel = ($peek.Count - 1) - ($peek | ForEach-Object {$_})[-1]
                } else {
                    $this.HighestSavedLevel = -1
                }
            }
            else {
                # Nothing to restore, clamp to zero
                $this.Counters = @(0) * $this.Counters.Count
                $this.HighestSavedLevel = -1
            }
        }
    }

    [void] IncLast() { $this.Inc($this.Counters.Count - 1) }
    [void] DecLast() { $this.Dec($this.Counters.Count - 1) }

    [string] ToString() {
        return 'Counters = [' + ($this.Counters -join ', ') + ']'
    }
}