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

package com.google.common.flogger.context;

import java.util.Set;
import java.util.Collection;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Iterator;
import com.google.common.flogger.util.Checks;
import java.util.Map;
import java.util.Collections;
import java.util.logging.Level;

public final class LogLevelMap
{
    private final SegmentTrie<Level> trie;
    
    public static Builder builder() {
        return new Builder();
    }
    
    public static LogLevelMap create(final Level level) {
        return create(Collections.emptyMap(), level);
    }
    
    public static LogLevelMap create(final Map<String, ? extends Level> map) {
        return create(map, Level.OFF);
    }
    
    public static LogLevelMap create(final Map<String, ? extends Level> map, final Level defaultLevel) {
        Checks.checkNotNull(defaultLevel, "default log level must not be null");
        for (final Map.Entry<String, ? extends Level> e : map.entrySet()) {
            final String name = e.getKey();
            if (name.startsWith(".") || name.endsWith(".") || name.contains("..")) {
                throw new IllegalArgumentException("invalid logger name: " + name);
            }
            if (e.getValue() == null) {
                throw new IllegalArgumentException("log levels must not be null; logger=" + name);
            }
        }
        return new LogLevelMap(map, defaultLevel);
    }
    
    private LogLevelMap(final Map<String, ? extends Level> map, final Level defaultLevel) {
        this.trie = SegmentTrie.create(map, '.', defaultLevel);
    }
    
    public Level getLevel(final String loggerName) {
        return this.trie.find(loggerName);
    }
    
    public LogLevelMap merge(final LogLevelMap other) {
        final Map<String, Level> thisMap = this.trie.getEntryMap();
        final Map<String, Level> otherMap = other.trie.getEntryMap();
        final Map<String, Level> mergedMap = new HashMap<String, Level>();
        final Set<String> allKeys = new HashSet<String>(thisMap.keySet());
        allKeys.addAll(otherMap.keySet());
        for (final String key : allKeys) {
            if (!otherMap.containsKey(key)) {
                mergedMap.put(key, thisMap.get(key));
            }
            else if (!thisMap.containsKey(key)) {
                mergedMap.put(key, otherMap.get(key));
            }
            else {
                mergedMap.put(key, min(thisMap.get(key), otherMap.get(key)));
            }
        }
        final Level defaultLevel = min(this.trie.getDefaultValue(), other.trie.getDefaultValue());
        return create(mergedMap, defaultLevel);
    }
    
    private static Level min(final Level a, final Level b) {
        return (a.intValue() <= b.intValue()) ? a : b;
    }
    
    public static final class Builder
    {
        private final Map<String, Level> map;
        private Level defaultLevel;
        
        private Builder() {
            this.map = new HashMap<String, Level>();
            this.defaultLevel = Level.OFF;
        }
        
        private void put(final String name, final Level level) {
            if (this.map.put(name, level) != null) {
                throw new IllegalArgumentException("duplicate entry for class/package: " + name);
            }
        }
        
        public Builder add(final Level level, final Class<?>... classes) {
            for (final Class<?> cls : classes) {
                this.put(cls.getName(), level);
            }
            return this;
        }
        
        public Builder add(final Level level, final Package... packages) {
            for (final Package pkg : packages) {
                this.put(pkg.getName(), level);
            }
            return this;
        }
        
        public Builder setDefault(final Level level) {
            Checks.checkNotNull(this.defaultLevel, "default log level must not be null");
            this.defaultLevel = level;
            return this;
        }
        
        public LogLevelMap build() {
            return LogLevelMap.create(this.map, this.defaultLevel);
        }
    }
}
