package org.apache.logging.log4j.core.config.plugins.visitors;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;

public class PluginElementVisitor extends AbstractPluginVisitor<PluginElement> {
   public PluginElementVisitor() {
      super(PluginElement.class);
   }

   public Object visit(Configuration configuration, Node node, LogEvent event, StringBuilder log) {
      String name = ((PluginElement)this.annotation).value();
      if (!this.conversionType.isArray()) {
         Node namedNode = this.findNamedNode(name, node.getChildren());
         if (namedNode == null) {
            log.append("null");
            return null;
         } else {
            log.append(namedNode.getName()).append('(').append(namedNode.toString()).append(')');
            node.getChildren().remove(namedNode);
            return namedNode.getObject();
         }
      } else {
         this.setConversionType(this.conversionType.getComponentType());
         List<Object> values = new ArrayList();
         Collection<Node> used = new ArrayList();
         log.append("={");
         boolean first = true;
         Iterator i$ = node.getChildren().iterator();

         while(true) {
            Node child;
            PluginType childType;
            do {
               if (!i$.hasNext()) {
                  log.append('}');
                  if (!values.isEmpty() && !this.conversionType.isAssignableFrom(values.get(0).getClass())) {
                     LOGGER.error("Attempted to assign attribute {} to list of type {} which is incompatible with {}.", name, values.get(0).getClass(), this.conversionType);
                     return null;
                  }

                  node.getChildren().removeAll(used);
                  Object[] array = (Object[])((Object[])Array.newInstance(this.conversionType, values.size()));

                  for(int i = 0; i < array.length; ++i) {
                     array[i] = values.get(i);
                  }

                  return array;
               }

               child = (Node)i$.next();
               childType = child.getType();
            } while(!name.equalsIgnoreCase(childType.getElementName()) && !this.conversionType.isAssignableFrom(childType.getPluginClass()));

            if (!first) {
               log.append(", ");
            }

            first = false;
            used.add(child);
            Object childObject = child.getObject();
            if (childObject == null) {
               LOGGER.error("Null object returned for {} in {}.", child.getName(), node.getName());
            } else {
               if (childObject.getClass().isArray()) {
                  log.append(Arrays.toString((Object[])((Object[])childObject))).append('}');
                  return childObject;
               }

               log.append(child.toString());
               values.add(childObject);
            }
         }
      }
   }

   private Node findNamedNode(String name, Iterable<Node> children) {
      Iterator i$ = children.iterator();

      Node child;
      PluginType childType;
      do {
         if (!i$.hasNext()) {
            return null;
         }

         child = (Node)i$.next();
         childType = child.getType();
      } while(!name.equalsIgnoreCase(childType.getElementName()) && !this.conversionType.isAssignableFrom(childType.getPluginClass()));

      return child;
   }
}
