package org.apache.logging.log4j.spi;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.util.PropertiesUtil;

public class DefaultThreadContextMap implements ThreadContextMap {
   public static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
   private final boolean useMap;
   private final ThreadLocal<Map<String, String>> localMap;

   public DefaultThreadContextMap(boolean useMap) {
      this.useMap = useMap;
      this.localMap = createThreadLocalMap(useMap);
   }

   static ThreadLocal<Map<String, String>> createThreadLocalMap(final boolean isMapEnabled) {
      PropertiesUtil managerProps = PropertiesUtil.getProperties();
      boolean inheritable = managerProps.getBooleanProperty("isThreadContextMapInheritable");
      return (ThreadLocal)(inheritable ? new InheritableThreadLocal<Map<String, String>>() {
         protected Map<String, String> childValue(Map<String, String> parentValue) {
            return parentValue != null && isMapEnabled ? Collections.unmodifiableMap(new HashMap(parentValue)) : null;
         }
      } : new ThreadLocal());
   }

   public void put(String key, String value) {
      if (this.useMap) {
         Map<String, String> map = (Map)this.localMap.get();
         Map<String, String> map = map == null ? new HashMap() : new HashMap(map);
         map.put(key, value);
         this.localMap.set(Collections.unmodifiableMap(map));
      }
   }

   public String get(String key) {
      Map<String, String> map = (Map)this.localMap.get();
      return map == null ? null : (String)map.get(key);
   }

   public void remove(String key) {
      Map<String, String> map = (Map)this.localMap.get();
      if (map != null) {
         Map<String, String> copy = new HashMap(map);
         copy.remove(key);
         this.localMap.set(Collections.unmodifiableMap(copy));
      }

   }

   public void clear() {
      this.localMap.remove();
   }

   public boolean containsKey(String key) {
      Map<String, String> map = (Map)this.localMap.get();
      return map != null && map.containsKey(key);
   }

   public Map<String, String> getCopy() {
      Map<String, String> map = (Map)this.localMap.get();
      return map == null ? new HashMap() : new HashMap(map);
   }

   public Map<String, String> getImmutableMapOrNull() {
      return (Map)this.localMap.get();
   }

   public boolean isEmpty() {
      Map<String, String> map = (Map)this.localMap.get();
      return map == null || map.size() == 0;
   }

   public String toString() {
      Map<String, String> map = (Map)this.localMap.get();
      return map == null ? "{}" : map.toString();
   }

   public int hashCode() {
      int prime = true;
      int result = 1;
      Map<String, String> map = (Map)this.localMap.get();
      int result = 31 * result + (map == null ? 0 : map.hashCode());
      result = 31 * result + (this.useMap ? 1231 : 1237);
      return result;
   }

   public boolean equals(Object obj) {
      if (this == obj) {
         return true;
      } else if (obj == null) {
         return false;
      } else {
         if (obj instanceof DefaultThreadContextMap) {
            DefaultThreadContextMap other = (DefaultThreadContextMap)obj;
            if (this.useMap != other.useMap) {
               return false;
            }
         }

         if (!(obj instanceof ThreadContextMap)) {
            return false;
         } else {
            ThreadContextMap other = (ThreadContextMap)obj;
            Map<String, String> map = (Map)this.localMap.get();
            Map<String, String> otherMap = other.getImmutableMapOrNull();
            if (map == null) {
               if (otherMap != null) {
                  return false;
               }
            } else if (!map.equals(otherMap)) {
               return false;
            }

            return true;
         }
      }
   }
}
