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

package com.google.common.flogger.context;

import java.util.Arrays;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import java.util.ArrayList;
import java.util.List;
import com.google.common.flogger.util.Checks;
import com.google.common.flogger.MetadataKey;
import com.google.common.flogger.backend.Metadata;

public abstract class ScopeMetadata extends Metadata
{
    public static Builder builder() {
        return new Builder();
    }
    
    public static <T> ScopeMetadata singleton(final MetadataKey<T> key, final T value) {
        return new SingletonMetadata((MetadataKey<T>)key, (T)value);
    }
    
    public static ScopeMetadata none() {
        return EmptyMetadata.INSTANCE;
    }
    
    private ScopeMetadata() {
    }
    
    public abstract ScopeMetadata concatenate(final ScopeMetadata p0);
    
    abstract Entry<?> get(final int p0);
    
    @Override
    public MetadataKey<?> getKey(final int n) {
        return this.get(n).key;
    }
    
    @Override
    public Object getValue(final int n) {
        return this.get(n).value;
    }
    
    private static final class Entry<T>
    {
        final MetadataKey<T> key;
        final T value;
        
        Entry(final MetadataKey<T> key, final T value) {
            this.key = Checks.checkNotNull(key, "key");
            this.value = Checks.checkNotNull(value, "value");
        }
    }
    
    public static final class Builder
    {
        private static final Entry<?>[] EMPTY_ARRAY;
        private final List<Entry<?>> entries;
        
        private Builder() {
            this.entries = new ArrayList<Entry<?>>(2);
        }
        
        public <T> Builder add(final MetadataKey<T> key, final T value) {
            this.entries.add(new Entry<Object>((MetadataKey<Object>)key, value));
            return this;
        }
        
        public ScopeMetadata build() {
            return new ImmutableScopeMetadata(this.entries.toArray(Builder.EMPTY_ARRAY));
        }
        
        static {
            EMPTY_ARRAY = new Entry[0];
        }
    }
    
    private static final class ImmutableScopeMetadata extends ScopeMetadata
    {
        private final Entry<?>[] entries;
        
        ImmutableScopeMetadata(final Entry<?>[] entries) {
            super(null);
            this.entries = entries;
        }
        
        @Override
        public int size() {
            return this.entries.length;
        }
        
        @Override
        Entry<?> get(final int n) {
            return this.entries[n];
        }
        
        @NullableDecl
        @Override
        public <T> T findValue(final MetadataKey<T> key) {
            Checks.checkArgument(!key.canRepeat(), "metadata key must be single valued");
            for (int n = this.entries.length - 1; n >= 0; --n) {
                final Entry<?> e = this.entries[n];
                if (e.key.equals(key)) {
                    return (T)e.value;
                }
            }
            return null;
        }
        
        @Override
        public ScopeMetadata concatenate(final ScopeMetadata metadata) {
            final int extraSize = metadata.size();
            if (extraSize == 0) {
                return this;
            }
            if (this.entries.length == 0) {
                return metadata;
            }
            final Entry<?>[] merged = Arrays.copyOf(this.entries, this.entries.length + extraSize);
            for (int i = 0; i < extraSize; ++i) {
                merged[i + this.entries.length] = metadata.get(i);
            }
            return new ImmutableScopeMetadata(merged);
        }
    }
    
    private static final class SingletonMetadata extends ScopeMetadata
    {
        private final Entry<?> entry;
        
         <T> SingletonMetadata(final MetadataKey<T> key, final T value) {
            super(null);
            this.entry = new Entry<Object>(key, value);
        }
        
        @Override
        public int size() {
            return 1;
        }
        
        @Override
        Entry<?> get(final int n) {
            if (n == 0) {
                return this.entry;
            }
            throw new IndexOutOfBoundsException();
        }
        
        @NullableDecl
        @Override
        public <R> R findValue(final MetadataKey<R> key) {
            Checks.checkArgument(!key.canRepeat(), "metadata key must be single valued");
            return (R)(this.entry.key.equals(key) ? this.entry.value : null);
        }
        
        @Override
        public ScopeMetadata concatenate(final ScopeMetadata metadata) {
            final int extraSize = metadata.size();
            if (extraSize == 0) {
                return this;
            }
            final Entry<?>[] merged = new Entry[extraSize + 1];
            merged[0] = this.entry;
            for (int i = 0; i < extraSize; ++i) {
                merged[i + 1] = metadata.get(i);
            }
            return new ImmutableScopeMetadata(merged);
        }
    }
    
    private static final class EmptyMetadata extends ScopeMetadata
    {
        static final ScopeMetadata INSTANCE;
        
        private EmptyMetadata() {
            super(null);
        }
        
        @Override
        public int size() {
            return 0;
        }
        
        @Override
        Entry<?> get(final int n) {
            throw new IndexOutOfBoundsException();
        }
        
        @NullableDecl
        @Override
        public <T> T findValue(final MetadataKey<T> key) {
            Checks.checkArgument(!key.canRepeat(), "metadata key must be single valued");
            return null;
        }
        
        @Override
        public ScopeMetadata concatenate(final ScopeMetadata metadata) {
            return metadata;
        }
        
        static {
            INSTANCE = new EmptyMetadata();
        }
    }
}
