content: package dev.alangomes.springspigot.picocli;
  
  import dev.alangomes.springspigot.picocli.conversion.PicocliConversorInjector;
  import lombok.Getter;
  import lombok.SneakyThrows;
  import org.springframework.aop.framework.Advised;
  import org.springframework.aop.support.AopUtils;
  import org.springframework.beans.factory.BeanFactory;
  import picocli.CommandLine;
  import picocli.CommandLine.IHelpSectionRenderer;
  
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Set;
  import java.util.function.Function;
  import java.util.stream.Collectors;
  
  @Getter
  public class CommandLineDefinition {
  
      private final String beanName;
      private final Object instance;
      private final CommandLine.IFactory commandFactory;
  
      private final HashMap<String, CommandLineDefinition> subcommands = new HashMap<>();
  
      CommandLineDefinition(Object instance, CommandLine.IFactory factory) {
          this.beanName = instance instanceof String ? (String) instance : null;
          this.instance = !(instance instanceof String) ? instance : null;
          this.commandFactory = factory;
      }
  
      void addSubcommand(String name, Object commandLine) {
          if (commandLine instanceof CommandLineDefinition) {
              subcommands.put(name, (CommandLineDefinition) commandLine);
          } else {
              subcommands.put(name, new CommandLineDefinition(commandLine, commandFactory));
          }
      }
  
      public CommandLine build(BeanFactory factory) {
          CommandLine commandLine = doBuild(factory);
  
          overrideHelpRenderers(commandLine);
          overrideConverters(factory, commandLine);
          return commandLine;
      }
  
      private CommandLine doBuild(BeanFactory factory) {
          CommandLine commandLine = new CommandLine(beanName != null ? getBean(factory, beanName) : instance, commandFactory);
  
          subcommands.forEach((key, value) -> commandLine.addSubcommand(key, value.doBuild(factory)));
          return commandLine;
      }
  
      @SneakyThrows
      private Object getBean(BeanFactory factory, String name) {
          Object bean = factory.getBean(name);
          if (AopUtils.isAopProxy(bean)) {
              return ((Advised) bean).getTargetSource().getTarget();
          }
          return bean;
      }
  
      public Set<String> getCommandNames() {
          return Collections.unmodifiableSet(subcommands.keySet());
      }
  
      private void overrideConverters(BeanFactory beanFactory, CommandLine commandLine) {
          PicocliConversorInjector picocliConversorInjector = beanFactory.getBean(PicocliConversorInjector.class);
          picocliConversorInjector.injectConversor(commandLine);
      }
  
      private void overrideHelpRenderers(CommandLine commandLine) {
          Map<String, IHelpSectionRenderer> renderers = commandLine.getHelpSectionMap().keySet()
                  .stream()
                  .collect(Collectors.toMap(Function.identity(), (k) -> overrideRenderer(commandLine.getHelpSectionMap().get(k))));
          commandLine.setHelpSectionMap(renderers);
      }
  
      private IHelpSectionRenderer overrideRenderer(IHelpSectionRenderer renderer) {
          // strip carriage returns when running inside a windows server
          return (h) -> renderer.render(h).replaceAll("\\r", "");
      }
  
  }
  