// 
// Decompiled by Procyon v0.6.0
// 

package io.sentry.featureflags;

import java.util.Map;
import java.util.Collections;
import io.sentry.ScopeType;
import java.util.LinkedHashMap;
import io.sentry.SentryOptions;
import java.util.Iterator;
import java.util.List;
import io.sentry.protocol.FeatureFlag;
import java.util.ArrayList;
import io.sentry.protocol.FeatureFlags;
import io.sentry.ISentryLifecycleToken;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import io.sentry.util.AutoClosableReentrantLock;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CopyOnWriteArrayList;
import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Internal
public final class FeatureFlagBuffer implements IFeatureFlagBuffer
{
    @NotNull
    private volatile CopyOnWriteArrayList<FeatureFlagEntry> flags;
    @NotNull
    private final AutoClosableReentrantLock lock;
    private int maxSize;
    
    private FeatureFlagBuffer(final int maxSize) {
        this.lock = new AutoClosableReentrantLock();
        this.maxSize = maxSize;
        this.flags = new CopyOnWriteArrayList<FeatureFlagEntry>();
    }
    
    private FeatureFlagBuffer(final int maxSize, @NotNull final CopyOnWriteArrayList<FeatureFlagEntry> flags) {
        this.lock = new AutoClosableReentrantLock();
        this.maxSize = maxSize;
        this.flags = flags;
    }
    
    private FeatureFlagBuffer(@NotNull final FeatureFlagBuffer other) {
        this.lock = new AutoClosableReentrantLock();
        this.maxSize = other.maxSize;
        this.flags = new CopyOnWriteArrayList<FeatureFlagEntry>(other.flags);
    }
    
    @Override
    public void add(@Nullable final String flag, @Nullable final Boolean result) {
        if (flag == null || result == null) {
            return;
        }
        try (final ISentryLifecycleToken ignored = this.lock.acquire()) {
            for (int size = this.flags.size(), i = 0; i < size; ++i) {
                final FeatureFlagEntry entry = this.flags.get(i);
                if (entry.flag.equals(flag)) {
                    this.flags.remove(i);
                    break;
                }
            }
            this.flags.add(new FeatureFlagEntry(flag, result, System.nanoTime()));
            if (this.flags.size() > this.maxSize) {
                this.flags.remove(0);
            }
        }
    }
    
    @Nullable
    @Override
    public FeatureFlags getFeatureFlags() {
        final List<FeatureFlag> featureFlags = new ArrayList<FeatureFlag>();
        for (final FeatureFlagEntry entry : this.flags) {
            featureFlags.add(entry.toFeatureFlag());
        }
        return new FeatureFlags(featureFlags);
    }
    
    @NotNull
    @Override
    public IFeatureFlagBuffer clone() {
        return new FeatureFlagBuffer(this);
    }
    
    @NotNull
    public static IFeatureFlagBuffer create(@NotNull final SentryOptions options) {
        final int maxFeatureFlags = options.getMaxFeatureFlags();
        if (maxFeatureFlags > 0) {
            return new FeatureFlagBuffer(maxFeatureFlags);
        }
        return NoOpFeatureFlagBuffer.getInstance();
    }
    
    @NotNull
    public static IFeatureFlagBuffer merged(@NotNull final SentryOptions options, @Nullable final IFeatureFlagBuffer globalBuffer, @Nullable final IFeatureFlagBuffer isolationBuffer, @Nullable final IFeatureFlagBuffer currentBuffer) {
        final int maxSize = options.getMaxFeatureFlags();
        if (maxSize <= 0) {
            return NoOpFeatureFlagBuffer.getInstance();
        }
        return merged(maxSize, (globalBuffer instanceof FeatureFlagBuffer) ? ((FeatureFlagBuffer)globalBuffer) : null, (isolationBuffer instanceof FeatureFlagBuffer) ? ((FeatureFlagBuffer)isolationBuffer) : null, (currentBuffer instanceof FeatureFlagBuffer) ? ((FeatureFlagBuffer)currentBuffer) : null);
    }
    
    @NotNull
    private static IFeatureFlagBuffer merged(final int maxSize, @Nullable final FeatureFlagBuffer globalBuffer, @Nullable final FeatureFlagBuffer isolationBuffer, @Nullable final FeatureFlagBuffer currentBuffer) {
        final CopyOnWriteArrayList<FeatureFlagEntry> globalFlags = (globalBuffer == null) ? null : globalBuffer.flags;
        final CopyOnWriteArrayList<FeatureFlagEntry> isolationFlags = (isolationBuffer == null) ? null : isolationBuffer.flags;
        final CopyOnWriteArrayList<FeatureFlagEntry> currentFlags = (currentBuffer == null) ? null : currentBuffer.flags;
        final int globalSize = (globalFlags == null) ? 0 : globalFlags.size();
        final int isolationSize = (isolationFlags == null) ? 0 : isolationFlags.size();
        final int currentSize = (currentFlags == null) ? 0 : currentFlags.size();
        if (globalSize == 0 && isolationSize == 0 && currentSize == 0) {
            return NoOpFeatureFlagBuffer.getInstance();
        }
        int globalIndex = globalSize - 1;
        int isolationIndex = isolationSize - 1;
        int currentIndex = currentSize - 1;
        FeatureFlagEntry globalEntry = (globalFlags == null || globalIndex < 0) ? null : globalFlags.get(globalIndex);
        FeatureFlagEntry isolationEntry = (isolationFlags == null || isolationIndex < 0) ? null : isolationFlags.get(isolationIndex);
        FeatureFlagEntry currentEntry = (currentFlags == null || currentIndex < 0) ? null : currentFlags.get(currentIndex);
        final Map<String, FeatureFlagEntry> uniqueFlags = new LinkedHashMap<String, FeatureFlagEntry>(maxSize);
        while (uniqueFlags.size() < maxSize && (globalEntry != null || isolationEntry != null || currentEntry != null)) {
            FeatureFlagEntry entryToAdd = null;
            ScopeType selectedBuffer = null;
            if (globalEntry != null && (entryToAdd == null || globalEntry.nanos > entryToAdd.nanos)) {
                entryToAdd = globalEntry;
                selectedBuffer = ScopeType.GLOBAL;
            }
            if (isolationEntry != null && (entryToAdd == null || isolationEntry.nanos > entryToAdd.nanos)) {
                entryToAdd = isolationEntry;
                selectedBuffer = ScopeType.ISOLATION;
            }
            if (currentEntry != null && (entryToAdd == null || currentEntry.nanos > entryToAdd.nanos)) {
                entryToAdd = currentEntry;
                selectedBuffer = ScopeType.CURRENT;
            }
            if (entryToAdd == null) {
                break;
            }
            if (!uniqueFlags.containsKey(entryToAdd.flag)) {
                uniqueFlags.put(entryToAdd.flag, entryToAdd);
            }
            if (ScopeType.CURRENT.equals(selectedBuffer)) {
                --currentIndex;
                currentEntry = ((currentFlags != null && currentIndex >= 0) ? currentFlags.get(currentIndex) : null);
            }
            else if (ScopeType.ISOLATION.equals(selectedBuffer)) {
                --isolationIndex;
                isolationEntry = ((isolationFlags != null && isolationIndex >= 0) ? isolationFlags.get(isolationIndex) : null);
            }
            else {
                if (!ScopeType.GLOBAL.equals(selectedBuffer)) {
                    continue;
                }
                --globalIndex;
                globalEntry = ((globalFlags != null && globalIndex >= 0) ? globalFlags.get(globalIndex) : null);
            }
        }
        final List<FeatureFlagEntry> resultList = new ArrayList<FeatureFlagEntry>(uniqueFlags.values());
        Collections.reverse(resultList);
        return new FeatureFlagBuffer(maxSize, new CopyOnWriteArrayList<FeatureFlagEntry>(resultList));
    }
    
    private static class FeatureFlagEntry
    {
        @NotNull
        private final String flag;
        private final boolean result;
        @NotNull
        private final Long nanos;
        
        public FeatureFlagEntry(@NotNull final String flag, final boolean result, @NotNull final Long nanos) {
            this.flag = flag;
            this.result = result;
            this.nanos = nanos;
        }
        
        @NotNull
        public FeatureFlag toFeatureFlag() {
            return new FeatureFlag(this.flag, this.result);
        }
    }
}
