package de.plushnikov.intellij.plugin.processor.handler.singular;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiCodeBlock;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiSubstitutor;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiVariable;
import de.plushnikov.intellij.plugin.processor.field.AccessorsInfo;
import de.plushnikov.intellij.plugin.psi.LombokLightFieldBuilder;
import de.plushnikov.intellij.plugin.psi.LombokLightMethodBuilder;
import de.plushnikov.intellij.plugin.util.PsiAnnotationUtil;
import de.plushnikov.intellij.plugin.util.PsiMethodUtil;
import de.plushnikov.intellij.plugin.util.PsiTypeUtil;
import lombok.core.handlers.Singulars;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public abstract class AbstractSingularHandler implements BuilderElementHandler {
protected final String collectionQualifiedName;
private final boolean shouldGenerateFullBodyBlock;
AbstractSingularHandler(String qualifiedName, boolean shouldGenerateFullBodyBlock) {
this.collectionQualifiedName = qualifiedName;
this.shouldGenerateFullBodyBlock = shouldGenerateFullBodyBlock;
}
@Override
public void addBuilderField(@NotNull List<PsiField> fields, @NotNull PsiVariable psiVariable, @NotNull PsiClass innerClass, @NotNull AccessorsInfo accessorsInfo, @NotNull PsiSubstitutor substitutor) {
final String fieldName = accessorsInfo.removePrefix(psiVariable.getName());
final PsiType fieldType = getBuilderFieldType(substitutor.substitute(psiVariable.getType()), psiVariable.getProject());
final LombokLightFieldBuilder fieldBuilder =
new LombokLightFieldBuilder(psiVariable.getManager(), fieldName, fieldType)
.withModifier(PsiModifier.PRIVATE)
.withNavigationElement(psiVariable)
.withContainingClass(innerClass);
fields.add(fieldBuilder);
}
@NotNull
protected PsiType getBuilderFieldType(@NotNull PsiType psiFieldType, @NotNull Project project) {
final PsiManager psiManager = PsiManager.getInstance(project);
final PsiType elementType = PsiTypeUtil.extractOneElementType(psiFieldType, psiManager);
return PsiTypeUtil.createCollectionType(psiManager, CommonClassNames.JAVA_UTIL_ARRAY_LIST, elementType);
}
@Override
public void addBuilderMethod(@NotNull List<PsiMethod> methods, @NotNull PsiVariable psiVariable, @NotNull String fieldName, @NotNull PsiClass innerClass, boolean fluentBuilder, PsiType returnType, String singularName, PsiSubstitutor builderSubstitutor) {
final PsiType psiFieldType = builderSubstitutor.substitute(psiVariable.getType());
final PsiManager psiManager = psiVariable.getManager();
final LombokLightMethodBuilder oneAddMethod = new LombokLightMethodBuilder(psiManager, singularName)
.withMethodReturnType(returnType)
.withContainingClass(innerClass)
.withNavigationElement(psiVariable)
.withModifier(PsiModifier.PUBLIC);
addOneMethodParameter(oneAddMethod, psiFieldType, singularName);
oneAddMethod.withBody(createOneAddMethodCodeBlock(innerClass, fluentBuilder, singularName, fieldName, psiFieldType));
methods.add(oneAddMethod);
final LombokLightMethodBuilder allAddMethod = new LombokLightMethodBuilder(psiManager, fieldName)
.withMethodReturnType(returnType)
.withContainingClass(innerClass)
.withNavigationElement(psiVariable)
.withModifier(PsiModifier.PUBLIC);
addAllMethodParameter(allAddMethod, psiFieldType, fieldName);
allAddMethod.withBody(createAllAddMethodCodeBlock(innerClass, fluentBuilder, fieldName, psiFieldType));
methods.add(allAddMethod);
final LombokLightMethodBuilder clearMethod = new LombokLightMethodBuilder(psiManager, "clear" + StringUtil.capitalize(fieldName))
.withMethodReturnType(returnType)
.withContainingClass(innerClass)
.withNavigationElement(psiVariable)
.withModifier(PsiModifier.PUBLIC)
.withBody(createClearMethodCodeBlock(innerClass, fluentBuilder, fieldName));
methods.add(clearMethod);
}
@NotNull
private PsiCodeBlock createClearMethodCodeBlock(@NotNull PsiClass innerClass, boolean fluentBuilder, String psiFieldName) {
final String blockText;
if (shouldGenerateFullBodyBlock) {
blockText = getClearMethodBody(psiFieldName, fluentBuilder);
} else {
blockText = fluentBuilder ? "return this;" : "";
}
return PsiMethodUtil.createCodeBlockFromText(blockText, innerClass);
}
protected abstract String getClearMethodBody(String psiFieldName, boolean fluentBuilder);
@NotNull
private PsiCodeBlock createOneAddMethodCodeBlock(@NotNull PsiClass innerClass, boolean fluentBuilder, @NotNull String singularName, @NotNull String psiFieldName, PsiType psiFieldType) {
final String blockText;
if (shouldGenerateFullBodyBlock) {
blockText = getOneMethodBody(singularName, psiFieldName, psiFieldType, innerClass.getManager(), fluentBuilder);
} else {
blockText = fluentBuilder ? "return this;" : "";
}
return PsiMethodUtil.createCodeBlockFromText(blockText, innerClass);
}
@NotNull
private PsiCodeBlock createAllAddMethodCodeBlock(@NotNull PsiClass innerClass, boolean fluentBuilder, @NotNull String psiFieldName, @NotNull PsiType psiFieldType) {
final String blockText;
if (shouldGenerateFullBodyBlock) {
blockText = getAllMethodBody(psiFieldName, psiFieldType, innerClass.getManager(), fluentBuilder);
} else {
blockText = fluentBuilder ? "return this;" : "";
}
return PsiMethodUtil.createCodeBlockFromText(blockText, innerClass);
}
protected abstract void addOneMethodParameter(@NotNull LombokLightMethodBuilder methodBuilder, @NotNull PsiType psiFieldType, @NotNull String singularName);
protected abstract void addAllMethodParameter(@NotNull LombokLightMethodBuilder methodBuilder, @NotNull PsiType psiFieldType, @NotNull String singularName);
protected abstract String getOneMethodBody(@NotNull String singularName, @NotNull String psiFieldName, @NotNull PsiType psiFieldType, PsiManager psiManager, boolean fluentBuilder);
protected abstract String getAllMethodBody(@NotNull String singularName, @NotNull PsiType psiFieldType, PsiManager psiManager, boolean fluentBuilder);
public String createSingularName(PsiAnnotation singularAnnotation, String psiFieldName) {
String singularName = PsiAnnotationUtil.getStringAnnotationValue(singularAnnotation, "value");
if (StringUtil.isEmptyOrSpaces(singularName)) {
singularName = Singulars.autoSingularize(psiFieldName);
if (singularName == null) {
singularName = psiFieldName;
}
}
return singularName;
}
public static boolean validateSingularName(PsiAnnotation singularAnnotation, String psiFieldName) {
String singularName = PsiAnnotationUtil.getStringAnnotationValue(singularAnnotation, "value");
if (StringUtil.isEmptyOrSpaces(singularName)) {
singularName = Singulars.autoSingularize(psiFieldName);
return singularName != null;
}
return true;
}
@Override
public void appendBuildCall(@NotNull StringBuilder buildMethodParameters, @NotNull String fieldName) {
buildMethodParameters.append(fieldName);
}
}