package org.apache.logging.log4j.core.config.json;

import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.logging.log4j.core.config.AbstractConfiguration;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.FileConfigurationMonitor;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.Reconfigurable;
import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;
import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
import org.apache.logging.log4j.core.config.status.StatusConfiguration;
import org.apache.logging.log4j.core.util.Patterns;

public class JsonConfiguration extends AbstractConfiguration implements Reconfigurable {
   private static final String[] VERBOSE_CLASSES = new String[]{ResolverUtil.class.getName()};
   private final List<JsonConfiguration.Status> status = new ArrayList();
   private JsonNode root;

   public JsonConfiguration(ConfigurationSource configSource) {
      super(configSource);
      File configFile = configSource.getFile();

      try {
         InputStream configStream = configSource.getInputStream();

         byte[] buffer;
         try {
            buffer = toByteArray(configStream);
         } finally {
            configStream.close();
         }

         ByteArrayInputStream is = new ByteArrayInputStream(buffer);
         this.root = this.getObjectMapper().readTree(is);
         JsonNode node;
         if (this.root.size() == 1) {
            for(Iterator i$ = this.root.iterator(); i$.hasNext(); this.root = node) {
               node = (JsonNode)i$.next();
            }
         }

         this.processAttributes(this.rootNode, this.root);
         StatusConfiguration statusConfig = (new StatusConfiguration()).withVerboseClasses(VERBOSE_CLASSES).withStatus(this.getDefaultStatus());
         Iterator i$ = this.rootNode.getAttributes().entrySet().iterator();

         while(true) {
            while(i$.hasNext()) {
               Entry<String, String> entry = (Entry)i$.next();
               String key = (String)entry.getKey();
               String value = this.getStrSubstitutor().replace((String)entry.getValue());
               if ("status".equalsIgnoreCase(key)) {
                  statusConfig.withStatus(value);
               } else if ("dest".equalsIgnoreCase(key)) {
                  statusConfig.withDestination(value);
               } else if ("shutdownHook".equalsIgnoreCase(key)) {
                  this.isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
               } else if ("verbose".equalsIgnoreCase((String)entry.getKey())) {
                  statusConfig.withVerbosity(value);
               } else if ("packages".equalsIgnoreCase(key)) {
                  String[] packages = value.split(Patterns.COMMA_SEPARATOR);
                  String[] arr$ = packages;
                  int len$ = packages.length;

                  for(int i$ = 0; i$ < len$; ++i$) {
                     String p = arr$[i$];
                     PluginManager.addPackage(p);
                  }
               } else if ("name".equalsIgnoreCase(key)) {
                  this.setName(value);
               } else if ("monitorInterval".equalsIgnoreCase(key)) {
                  int interval = Integer.parseInt(value);
                  if (interval > 0 && configFile != null) {
                     this.monitor = new FileConfigurationMonitor(this, configFile, this.listeners, interval);
                  }
               } else if ("advertiser".equalsIgnoreCase(key)) {
                  this.createAdvertiser(value, configSource, buffer, "application/json");
               }
            }

            statusConfig.initialize();
            if (this.getName() == null) {
               this.setName(configSource.getLocation());
            }
            break;
         }
      } catch (Exception var19) {
         LOGGER.error("Error parsing {}", configSource.getLocation(), var19);
      }

   }

   protected ObjectMapper getObjectMapper() {
      return (new ObjectMapper()).configure(Feature.ALLOW_COMMENTS, true);
   }

   public void setup() {
      Iterator<Entry<String, JsonNode>> iter = this.root.fields();
      List children = this.rootNode.getChildren();

      while(iter.hasNext()) {
         Entry<String, JsonNode> entry = (Entry)iter.next();
         JsonNode n = (JsonNode)entry.getValue();
         if (n.isObject()) {
            LOGGER.debug("Processing node for object {}", entry.getKey());
            children.add(this.constructNode((String)entry.getKey(), this.rootNode, n));
         } else if (n.isArray()) {
            LOGGER.error("Arrays are not supported at the root configuration.");
         }
      }

      LOGGER.debug("Completed parsing configuration");
      if (this.status.size() > 0) {
         Iterator i$ = this.status.iterator();

         while(i$.hasNext()) {
            JsonConfiguration.Status s = (JsonConfiguration.Status)i$.next();
            LOGGER.error("Error processing element " + s.name + ": " + s.errorType);
         }
      }

   }

   public Configuration reconfigure() {
      try {
         ConfigurationSource source = this.getConfigurationSource().resetInputStream();
         return source == null ? null : new JsonConfiguration(source);
      } catch (IOException var2) {
         LOGGER.error("Cannot locate file {}", this.getConfigurationSource(), var2);
         return null;
      }
   }

   private Node constructNode(String name, Node parent, JsonNode jsonNode) {
      PluginType<?> type = this.pluginManager.getPluginType(name);
      Node node = new Node(parent, name, type);
      this.processAttributes(node, jsonNode);
      Iterator<Entry<String, JsonNode>> iter = jsonNode.fields();
      List children = node.getChildren();

      while(true) {
         while(iter.hasNext()) {
            Entry<String, JsonNode> entry = (Entry)iter.next();
            JsonNode n = (JsonNode)entry.getValue();
            if (!n.isArray() && !n.isObject()) {
               LOGGER.debug("Node {} is of type {}", entry.getKey(), n.getNodeType());
            } else {
               if (type == null) {
                  this.status.add(new JsonConfiguration.Status(name, n, JsonConfiguration.ErrorType.CLASS_NOT_FOUND));
               }

               if (!n.isArray()) {
                  LOGGER.debug("Processing node for object {}", entry.getKey());
                  children.add(this.constructNode((String)entry.getKey(), node, n));
               } else {
                  LOGGER.debug("Processing node for array {}", entry.getKey());

                  for(int i = 0; i < n.size(); ++i) {
                     String pluginType = this.getType(n.get(i), (String)entry.getKey());
                     PluginType<?> entryType = this.pluginManager.getPluginType(pluginType);
                     Node item = new Node(node, (String)entry.getKey(), entryType);
                     this.processAttributes(item, n.get(i));
                     if (pluginType.equals(entry.getKey())) {
                        LOGGER.debug("Processing {}[{}]", entry.getKey(), i);
                     } else {
                        LOGGER.debug("Processing {} {}[{}]", pluginType, entry.getKey(), i);
                     }

                     Iterator<Entry<String, JsonNode>> itemIter = n.get(i).fields();
                     List itemChildren = item.getChildren();

                     while(true) {
                        while(itemIter.hasNext()) {
                           Entry<String, JsonNode> itemEntry = (Entry)itemIter.next();
                           if (((JsonNode)itemEntry.getValue()).isObject()) {
                              LOGGER.debug("Processing node for object {}", itemEntry.getKey());
                              itemChildren.add(this.constructNode((String)itemEntry.getKey(), item, (JsonNode)itemEntry.getValue()));
                           } else if (((JsonNode)itemEntry.getValue()).isArray()) {
                              JsonNode array = (JsonNode)itemEntry.getValue();
                              String entryName = (String)itemEntry.getKey();
                              LOGGER.debug("Processing array for object {}", entryName);

                              for(int j = 0; j < array.size(); ++j) {
                                 itemChildren.add(this.constructNode(entryName, item, array.get(j)));
                              }
                           }
                        }

                        children.add(item);
                        break;
                     }
                  }
               }
            }
         }

         String t;
         if (type == null) {
            t = "null";
         } else {
            t = type.getElementName() + ':' + type.getPluginClass();
         }

         String p = node.getParent() == null ? "null" : (node.getParent().getName() == null ? "root" : node.getParent().getName());
         LOGGER.debug("Returning {} with parent {} of type {}", node.getName(), p, t);
         return node;
      }
   }

   private String getType(JsonNode node, String name) {
      Iterator iter = node.fields();

      while(iter.hasNext()) {
         Entry<String, JsonNode> entry = (Entry)iter.next();
         if (((String)entry.getKey()).equalsIgnoreCase("type")) {
            JsonNode n = (JsonNode)entry.getValue();
            if (n.isValueNode()) {
               return n.asText();
            }
         }
      }

      return name;
   }

   private void processAttributes(Node parent, JsonNode node) {
      Map<String, String> attrs = parent.getAttributes();
      Iterator iter = node.fields();

      while(iter.hasNext()) {
         Entry<String, JsonNode> entry = (Entry)iter.next();
         if (!((String)entry.getKey()).equalsIgnoreCase("type")) {
            JsonNode n = (JsonNode)entry.getValue();
            if (n.isValueNode()) {
               attrs.put(entry.getKey(), n.asText());
            }
         }
      }

   }

   public String toString() {
      return this.getClass().getSimpleName() + "[location=" + this.getConfigurationSource() + "]";
   }

   private static class Status {
      private final JsonNode node;
      private final String name;
      private final JsonConfiguration.ErrorType errorType;

      public Status(String name, JsonNode node, JsonConfiguration.ErrorType errorType) {
         this.name = name;
         this.node = node;
         this.errorType = errorType;
      }
   }

   private static enum ErrorType {
      CLASS_NOT_FOUND;
   }
}
