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

package com.google.common.flogger.backend;

import com.google.common.flogger.util.Checks;
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import com.google.common.flogger.MetadataKey;

public abstract class MetadataHandler<C>
{
    protected abstract <T> void handle(final MetadataKey<T> p0, final T p1, final C p2);
    
    protected <T> void handleRepeated(final MetadataKey<T> key, final Iterator<T> values, final C context) {
        while (values.hasNext()) {
            this.handle(key, values.next(), context);
        }
    }
    
    public static <C> Builder<C> builder(final ValueHandler<Object, C> defaultHandler) {
        return new Builder<C>((ValueHandler)defaultHandler);
    }
    
    public static final class Builder<C>
    {
        private static final ValueHandler<Object, Object> IGNORE_VALUE;
        private static final RepeatedValueHandler<Object, Object> IGNORE_REPEATED_VALUE;
        private final Map<MetadataKey<?>, ValueHandler<?, ? super C>> singleValueHandlers;
        private final Map<MetadataKey<?>, RepeatedValueHandler<?, ? super C>> repeatedValueHandlers;
        private final ValueHandler<Object, ? super C> defaultHandler;
        private RepeatedValueHandler<Object, ? super C> defaultRepeatedHandler;
        
        private Builder(final ValueHandler<Object, ? super C> defaultHandler) {
            this.singleValueHandlers = new HashMap<MetadataKey<?>, ValueHandler<?, ? super C>>();
            this.repeatedValueHandlers = new HashMap<MetadataKey<?>, RepeatedValueHandler<?, ? super C>>();
            this.defaultRepeatedHandler = null;
            this.defaultHandler = Checks.checkNotNull(defaultHandler, "default handler");
        }
        
        public Builder<C> setDefaultRepeatedHandler(final RepeatedValueHandler<Object, ? super C> defaultHandler) {
            this.defaultRepeatedHandler = Checks.checkNotNull(defaultHandler, "handler");
            return this;
        }
        
        public <T> Builder<C> addHandler(final MetadataKey<T> key, final ValueHandler<? super T, ? super C> handler) {
            Checks.checkNotNull(key, "key");
            Checks.checkNotNull(handler, "handler");
            this.repeatedValueHandlers.remove(key);
            this.singleValueHandlers.put(key, handler);
            return this;
        }
        
        public <T> Builder<C> addRepeatedHandler(final MetadataKey<? extends T> key, final RepeatedValueHandler<T, ? super C> handler) {
            Checks.checkNotNull(key, "key");
            Checks.checkNotNull(handler, "handler");
            Checks.checkArgument(key.canRepeat(), "key must be repeating");
            this.singleValueHandlers.remove(key);
            this.repeatedValueHandlers.put(key, handler);
            return this;
        }
        
        public Builder<C> ignoring(final MetadataKey<?> key, final MetadataKey<?>... rest) {
            this.checkAndIgnore(key);
            for (final MetadataKey<?> k : rest) {
                this.checkAndIgnore(k);
            }
            return this;
        }
        
        public Builder<C> ignoring(final Iterable<MetadataKey<?>> keys) {
            for (final MetadataKey<?> k : keys) {
                this.checkAndIgnore(k);
            }
            return this;
        }
        
         <T> void checkAndIgnore(final MetadataKey<T> key) {
            Checks.checkNotNull(key, "key");
            if (key.canRepeat()) {
                this.addRepeatedHandler(key, Builder.IGNORE_REPEATED_VALUE);
            }
            else {
                this.addHandler(key, Builder.IGNORE_VALUE);
            }
        }
        
        public Builder<C> removeHandlers(final MetadataKey<?> key, final MetadataKey<?>... rest) {
            this.checkAndRemove(key);
            for (final MetadataKey<?> k : rest) {
                this.checkAndRemove(k);
            }
            return this;
        }
        
        void checkAndRemove(final MetadataKey<?> key) {
            Checks.checkNotNull(key, "key");
            this.singleValueHandlers.remove(key);
            this.repeatedValueHandlers.remove(key);
        }
        
        public MetadataHandler<C> build() {
            return new MapBasedhandler<C>(this);
        }
        
        static {
            IGNORE_VALUE = new ValueHandler<Object, Object>() {
                @Override
                public void handle(final MetadataKey<Object> key, final Object value, final Object context) {
                }
            };
            IGNORE_REPEATED_VALUE = new RepeatedValueHandler<Object, Object>() {
                @Override
                public void handle(final MetadataKey<Object> key, final Iterator<Object> value, final Object context) {
                }
            };
        }
    }
    
    private static final class MapBasedhandler<C> extends MetadataHandler<C>
    {
        private final Map<MetadataKey<?>, ValueHandler<?, ? super C>> singleValueHandlers;
        private final Map<MetadataKey<?>, RepeatedValueHandler<?, ? super C>> repeatedValueHandlers;
        private final ValueHandler<Object, ? super C> defaultHandler;
        private final RepeatedValueHandler<Object, ? super C> defaultRepeatedHandler;
        
        private MapBasedhandler(final Builder<C> builder) {
            this.singleValueHandlers = new HashMap<MetadataKey<?>, ValueHandler<?, ? super C>>();
            this.repeatedValueHandlers = new HashMap<MetadataKey<?>, RepeatedValueHandler<?, ? super C>>();
            this.singleValueHandlers.putAll(((Builder<Object>)builder).singleValueHandlers);
            this.repeatedValueHandlers.putAll(((Builder<Object>)builder).repeatedValueHandlers);
            this.defaultHandler = ((Builder<Object>)builder).defaultHandler;
            this.defaultRepeatedHandler = ((Builder<Object>)builder).defaultRepeatedHandler;
        }
        
        @Override
        protected <T> void handle(final MetadataKey<T> key, final T value, final C context) {
            final ValueHandler<T, ? super C> handler = (ValueHandler<T, ? super C>)this.singleValueHandlers.get(key);
            if (handler != null) {
                handler.handle(key, value, context);
            }
            else {
                this.defaultHandler.handle((MetadataKey<Object>)key, value, context);
            }
        }
        
        @Override
        protected <T> void handleRepeated(final MetadataKey<T> key, final Iterator<T> values, final C context) {
            final RepeatedValueHandler<T, ? super C> handler = (RepeatedValueHandler<T, ? super C>)this.repeatedValueHandlers.get(key);
            if (handler != null) {
                handler.handle(key, values, context);
            }
            else if (this.defaultRepeatedHandler != null && !this.singleValueHandlers.containsKey(key)) {
                this.defaultRepeatedHandler.handle((MetadataKey<Object>)key, (Iterator<Object>)values, context);
            }
            else {
                super.handleRepeated(key, values, context);
            }
        }
    }
    
    public interface ValueHandler<T, C>
    {
        void handle(final MetadataKey<T> p0, final T p1, final C p2);
    }
    
    public interface RepeatedValueHandler<T, C>
    {
        void handle(final MetadataKey<T> p0, final Iterator<T> p1, final C p2);
    }
}
