/*
 * Copyright 2002-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aot.generate;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.javapoet.ClassName;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
 * Generates unique class names that can be used in ahead-of-time generated
 * source code. This class is stateful so the same instance should be used for
 * all name generation. Most commonly the class name generator is obtained via a
 * {@link GenerationContext}.
 *
 * @author Phillip Webb
 * @since 6.0
 */
public final class ClassNameGenerator {

	private static final String SEPARATOR = "__";

	private static final String AOT_PACKAGE = "__.";

	private static final String AOT_FEATURE = "Aot";

	private final Map<String, AtomicInteger> sequenceGenerator = new ConcurrentHashMap<>();


	/**
	 * Generate a new class name for the given {@code target} /
	 * {@code featureName} combination.
	 * @param target the target of the newly generated class or {@code null} if
	 * there is not target.
	 * @param featureName the name of the feature that the generated class
	 * supports
	 * @return a unique generated class name
	 */
	public ClassName generateClassName(@Nullable Class<?> target, String featureName) {
		Assert.hasLength(featureName, "'featureName' must not be empty");
		featureName = clean(featureName);
		if(target != null) {
			return generateSequencedClassName(target.getName().replace("$", "_") + SEPARATOR + StringUtils.capitalize(featureName));
		}
		return generateSequencedClassName(AOT_PACKAGE+ featureName);
	}

	private String clean(String name) {
		StringBuilder clean = new StringBuilder();
		boolean lastNotLetter = true;
		for (char ch : name.toCharArray()) {
			if (!Character.isLetter(ch)) {
				lastNotLetter = true;
				continue;
			}
			clean.append(lastNotLetter ? Character.toUpperCase(ch) : ch);
			lastNotLetter = false;
		}
		return (!clean.isEmpty()) ? clean.toString() : AOT_FEATURE;
	}

	private ClassName generateSequencedClassName(String name) {
		name = addSequence(name);
		return ClassName.get(ClassUtils.getPackageName(name),
				ClassUtils.getShortName(name));
	}

	private String addSequence(String name) {
		int sequence = this.sequenceGenerator
				.computeIfAbsent(name, key -> new AtomicInteger()).getAndIncrement();
		return (sequence > 0) ? name + sequence : name;
	}

}

@@ -1013,17 +1013,16 @@
 Generate
-s
  unique 
@@ -1037,65 +1037,70 @@
 mes 
-that can be u
+ba
 sed 
-in ahead-of-time generated%0A * so
+on an optional target %7B@link Class%7D and%0A * a feat
 ur
-c
 e 
-cod
+nam
 e. T
@@ -1160,15 +1160,15 @@
 used
+%0A *
  for
-%0A *
  all
@@ -1239,17 +1239,17 @@
 ined
+%0A *
  via a
-%0A *
  %7B@l
@@ -1299,16 +1299,43 @@
 ip Webb%0A
+ * @author Stephane Nicoll%0A
  * @sinc
@@ -1650,72 +1650,292 @@
 e a 
-new class name for the given %7B@code target%7D /%0A%09 * %7B@code
+unique %7B@link ClassName%7D based on the specified %7B@code target%7D%0A%09 * class and %7B@code featureName%7D. If a %7B@code target%7D is specified, the%0A%09 * generated class name is a suffixed version of it.%0A%09 * %3Cp%3EFor instance, a %7B@code com.example.Demo%7D target with an%0A%09 * %7B@code Initializer%7D
  feature
 Name
@@ -1934,58 +1934,352 @@
 ture
-Name%7D combination.%0A%09 * @param target the target of
+ name leads to a%0A%09 * %7B@code com.example.Demo__Initializer%7D generated class name. If such a%0A%09 * feature was already requested for this target, a counter is used to%0A%09 * ensure uniqueness.%0A%09 * %3Cp%3EIf there is no target, the %7B@code featureName%7D is used to generate the%0A%09 * class name in the %7B@value #AOT_PACKAGE%7D package.%0A%09 * @param target the class
  the
@@ -2301,18 +2301,34 @@
 d class 
-o
 r
+elates to, or%0A%09 *
  %7B@code 
@@ -2335,20 +2335,16 @@
 null%7D if
-%0A%09 *
  there i
@@ -2355,17 +2355,16 @@
 t target
-.
 %0A%09 * @pa
@@ -2681,16 +2681,17 @@
 e);%0A%09%09if
+ 
 (target 
@@ -2772,17 +2772,22 @@
 $%22, %22_%22)
- 
+%0A%09%09%09%09%09
 + SEPARA
@@ -2881,16 +2881,17 @@
 _PACKAGE
+ 
 + featur

Clarify the scope of target in ClassNameGenerator