package net.minecraft.client.sounds;

import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.function.Predicate;
import java.util.Objects;
import java.util.stream.Stream;
import java.util.function.Consumer;
import com.mojang.blaze3d.audio.Channel;
import java.util.concurrent.CompletableFuture;
import com.google.common.collect.Sets;
import java.util.concurrent.Executor;
import com.mojang.blaze3d.audio.Library;
import java.util.Set;

public class ChannelAccess {
    private final Set<ChannelHandle> channels;
    private final Library library;
    private final Executor executor;
    
    public ChannelAccess(final Library dfu, final Executor executor) {
        this.channels = Sets.<ChannelHandle>newIdentityHashSet();
        this.library = dfu;
        this.executor = executor;
    }
    
    public CompletableFuture<ChannelHandle> createHandle(final Library.Pool c) {
        final CompletableFuture<ChannelHandle> completableFuture3 = new CompletableFuture<ChannelHandle>();
        final Channel dft4;
        ChannelHandle a5;
        final CompletableFuture<ChannelHandle> completableFuture4;
        this.executor.execute(() -> {
            dft4 = this.library.acquireChannel(c);
            if (dft4 != null) {
                a5 = new ChannelHandle(dft4);
                this.channels.add(a5);
                completableFuture4.complete(a5);
            }
            else {
                completableFuture4.complete(null);
            }
            return;
        });
        return completableFuture3;
    }
    
    public void executeOnChannels(final Consumer<Stream<Channel>> consumer) {
        this.executor.execute(() -> consumer.accept(this.channels.stream().<Channel>map(a -> a.channel).filter(Objects::nonNull)));
    }
    
    public void scheduleTick() {
        final Iterator<ChannelHandle> iterator2;
        ChannelHandle a3;
        this.executor.execute(() -> {
            iterator2 = this.channels.iterator();
            while (iterator2.hasNext()) {
                a3 = iterator2.next();
                a3.channel.updateStream();
                if (a3.channel.stopped()) {
                    a3.release();
                    iterator2.remove();
                }
            }
        });
    }
    
    public void clear() {
        this.channels.forEach(ChannelHandle::release);
        this.channels.clear();
    }
    
    public class ChannelHandle {
        @Nullable
        private Channel channel;
        private boolean stopped;
        
        public boolean isStopped() {
            return this.stopped;
        }
        
        public ChannelHandle(final Channel dft) {
            this.channel = dft;
        }
        
        public void execute(final Consumer<Channel> consumer) {
            ChannelAccess.this.executor.execute(() -> {
                if (this.channel != null) {
                    consumer.accept(this.channel);
                }
            });
        }
        
        public void release() {
            this.stopped = true;
            ChannelAccess.this.library.releaseChannel(this.channel);
            this.channel = null;
        }
    }
}
