package org.whole.lang.pojo.visitors;
import static org.whole.lang.pojo.reflect.PojoEntityDescriptorEnum.ArrayType_ord;
import static org.whole.lang.pojo.reflect.PojoEntityDescriptorEnum.CollectionType_ord;
import static org.whole.lang.pojo.reflect.PojoEntityDescriptorEnum.MapType_ord;
import static org.whole.lang.pojo.reflect.PojoEntityDescriptorEnum.PrimitiveType_ord;
import static org.whole.lang.pojo.reflect.PojoEntityDescriptorEnum.ReferenceType_ord;
import org.whole.lang.bindings.BindingManagerFactory;
import org.whole.lang.bindings.IBindingManager;
import org.whole.lang.matchers.Matcher;
import org.whole.lang.pojo.factories.PojoEntityFactory;
import org.whole.lang.pojo.model.ArrayType;
import org.whole.lang.pojo.model.CollectionType;
import org.whole.lang.pojo.model.Declaration;
import org.whole.lang.pojo.model.IPojoEntity;
import org.whole.lang.pojo.model.Library;
import org.whole.lang.pojo.model.MapType;
import org.whole.lang.pojo.model.ModifierEnum;
import org.whole.lang.pojo.model.Name;
import org.whole.lang.pojo.model.Parameter;
import org.whole.lang.pojo.model.PojoDeclaration;
import org.whole.lang.pojo.model.PrimitiveType;
import org.whole.lang.pojo.model.ProductDeclaration;
import org.whole.lang.pojo.model.Property;
import org.whole.lang.pojo.model.ReferenceType;
import org.whole.lang.pojo.model.Template;
import org.whole.lang.pojo.model.Type;
import org.whole.lang.pojo.reflect.PojoEntityDescriptorEnum;
import org.whole.lang.pojo.templates.PojoTemplateManager;
import org.whole.lang.pojo.util.PojoUtils;
import org.whole.lang.queries.model.Path;
import org.whole.lang.util.BehaviorUtils;
import org.whole.lang.util.EntityUtils;
import org.whole.lang.util.FreshNameGenerator;
import org.whole.lang.util.StringUtils;
public class PojoNormalizerVisitor extends PojoIdentityDefaultVisitor {
public PojoNormalizerVisitor() {
}
@Override
public void visit(IPojoEntity entity) {
Library p = Matcher.findAncestor(PojoEntityDescriptorEnum.Library, entity);
if (p != null)
visit(p);
}
@Override
public void visit(Library entity) {
IBindingManager bindings = BindingManagerFactory.instance.createBindingManager();
FreshNameGenerator entityNameGenerator = new FreshNameGenerator();
resolveTemplateNameCollisionsInDeclarations(entity, bindings, entityNameGenerator);
createDefaultTemplateInDeclarations(entity, bindings, entityNameGenerator);
createDefaultTemplateInProperties(entity, bindings);
createDefaultTypeInParameters(entity, bindings);
createDefaultTemplateInParameters(entity, bindings);
addMappingDataTypes(entity, bindings, entityNameGenerator);
}
public static void resolveTemplateNameCollisionsInDeclarations(Library entity, IBindingManager bindings, FreshNameGenerator entityNameGenerator) {
Path findAllProductDeclarationsWithTemplateName = (Path) PojoTemplateManager.instance().create("findAllProductDeclarationsWithTemplateName");
bindings.wEnterScope();
for (ProductDeclaration declaration : BehaviorUtils.<ProductDeclaration>compileAndLazyEvaluate(findAllProductDeclarationsWithTemplateName, entity, bindings)) {
Template template = declaration.getTemplate();
template.wSetValue(entityNameGenerator.nextFreshName(StringUtils.toSimpleName(template.wStringValue())));
}
bindings.wExitScope();
}
public static void createDefaultTemplateInDeclarations(Library entity, IBindingManager bindings, FreshNameGenerator entityNameGenerator) {
PojoEntityFactory pef = PojoEntityFactory.instance;
Path findAllProductDeclarationsWithEmptyTemplate = (Path) PojoTemplateManager.instance().create("findAllProductDeclarationsWithEmptyTemplate");
bindings.wEnterScope();
for (ProductDeclaration declaration : BehaviorUtils.<ProductDeclaration>compileAndLazyEvaluate(findAllProductDeclarationsWithEmptyTemplate, entity, bindings)) {
String name = StringUtils.toSimpleName(bindings.wStringValue("name"));
declaration.setTemplate(pef.createName(entityNameGenerator.nextFreshName(name)));
}
bindings.wExitScope();
}
public static void createDefaultTemplateInProperties(Library entity, IBindingManager bindings) {
Path findAllPropertiesWithoutTemplate = (Path) PojoTemplateManager.instance().create("findAllPropertiesWithoutTemplate");
bindings.wEnterScope();
for (Property property : BehaviorUtils.<Property>compileAndLazyEvaluate(findAllPropertiesWithoutTemplate, entity, bindings))
property.setTemplate((Name) EntityUtils.clone(bindings.wGet("name")));
bindings.wExitScope();
}
public static void createDefaultTypeInParameters(Library entity, IBindingManager bindings) {
Path findAllParametersWithoutType = (Path) PojoTemplateManager.instance().create("findAllParametersWithoutType");
Path findParameterType = (Path) PojoTemplateManager.instance().create("findPropertyType");
bindings.wEnterScope();
for (Parameter parameter : BehaviorUtils.<Parameter>compileAndLazyEvaluate(findAllParametersWithoutType, entity, bindings)) {
PojoDeclaration pojo = (PojoDeclaration) bindings.wGet("pojo");
Type type = BehaviorUtils.<Type>evaluateFirstResult(findParameterType, pojo, bindings);
if (type != null)
parameter.setType(EntityUtils.clone(type));
else
throw new IllegalArgumentException("Missing " + bindings.wStringValue("name") +
" property in " + pojo.getName().wStringValue() + " pojo declaration");
}
bindings.wExitScope();
}
public static void createDefaultTemplateInParameters(Library entity, IBindingManager bindings) {
Path findAllParametersWithoutTemlate = (Path) PojoTemplateManager.instance().create("findAllParametersWithoutTemlate");
Path findParameterTemplate = (Path) PojoTemplateManager.instance().create("findPropertyTemplate");
bindings.wEnterScope();
for (Parameter parameter : BehaviorUtils.<Parameter>compileAndLazyEvaluate(findAllParametersWithoutTemlate, entity, bindings)) {
PojoDeclaration pojo = (PojoDeclaration) bindings.wGet("pojo");
Name name = BehaviorUtils.<Name>evaluateFirstResult(findParameterTemplate, pojo, bindings);
if (name != null)
parameter.setTemplate(EntityUtils.clone(name));
}
bindings.wExitScope();
}
public static void addMappingDataTypes(Library entity, IBindingManager bindings, FreshNameGenerator entityNameGenerator) {
Path findNonPrimitiveTypes = (Path) PojoTemplateManager.instance().create("findAllPropertyTypes");
bindings.wEnterScope();
for (Type type : BehaviorUtils.<Type>compileAndLazyEvaluate(findNonPrimitiveTypes, entity, bindings))
addMappingDataType(type, entity, bindings, entityNameGenerator);
bindings.wExitScope();
}
public static void addMappingDataType(Type type, Library entity, IBindingManager bindings, FreshNameGenerator entityNameGenerator) {
bindings.wEnterScope();
switch (type.wGetEntityDescriptor().getOrdinal()) {
case PrimitiveType_ord:
addPrimitiveTypeMappingDataType((PrimitiveType) type, entity, bindings, entityNameGenerator);
break;
case ReferenceType_ord:
addReferenceTypeMappingDataType((ReferenceType) type, entity, bindings, entityNameGenerator);
break;
case ArrayType_ord:
addArrayTypeMappingDataType((ArrayType) type, entity, bindings, entityNameGenerator);
break;
case CollectionType_ord:
addCollectionTypeMappingDataType((CollectionType) type, entity, bindings, entityNameGenerator);
break;
case MapType_ord:
addMapTypeMappingDataType((MapType) type, entity, bindings, entityNameGenerator);
break;
}
bindings.wExitScope();
}
public static void addMissingDataTypeDeclaration(Type type, Library entity, FreshNameGenerator entityNameGenerator) {
if (PojoUtils.findProductDeclaration(type, entity) == null)
PojoUtils.addDataTypeDeclaration(type, entityNameGenerator.nextFreshName(PojoUtils.calculateTypeName(type)), entity);
}
public static void addPrimitiveTypeMappingDataType(PrimitiveType type, Library entity, IBindingManager bindings, FreshNameGenerator entityNameGenerator) {
addMissingDataTypeDeclaration(type, entity, entityNameGenerator);
}
public static void addReferenceTypeMappingDataType(ReferenceType type, Library entity, IBindingManager bindings, FreshNameGenerator entityNameGenerator) {
Property property = (Property) bindings.wGet("property");
Declaration declaration = PojoUtils.findProductDeclaration(type, entity);
boolean hasDataTypeModifier = property.getAnnotations().wContainsValue(ModifierEnum.DATATYPE);
boolean needsDeclaration = declaration == null;
boolean needsModifier = property.equals(type.wGetParent()) &&
!hasDataTypeModifier &&
(needsDeclaration || Matcher.matchImpl(PojoEntityDescriptorEnum.DataTypeDeclaration, declaration));
if (needsModifier)
property.getAnnotations().wAdd(PojoEntityFactory.instance.createModifier(ModifierEnum.DATATYPE));
if (needsDeclaration)
PojoUtils.addDataTypeDeclaration(type, entityNameGenerator.nextFreshName(PojoUtils.calculateTypeName(type)), entity);
}
public static void addArrayTypeMappingDataType(ArrayType type, Library entity, IBindingManager bindings, FreshNameGenerator entityNameGenerator) {
addMappingDataType(type.getElementType(), entity, bindings, entityNameGenerator);
addMissingDataTypeDeclaration(type, entity, entityNameGenerator);
}
public static void addCollectionTypeMappingDataType(CollectionType type, Library entity, IBindingManager bindings, FreshNameGenerator entityNameGenerator) {
addMappingDataType(type.getElementType(), entity, bindings, entityNameGenerator);
addMissingDataTypeDeclaration(type, entity, entityNameGenerator);
}
public static void addMapTypeMappingDataType(MapType type, Library entity, IBindingManager bindings, FreshNameGenerator entityNameGenerator) {
addMappingDataType(type.getKeyType(), entity, bindings, entityNameGenerator);
addMappingDataType(type.getValueType(), entity, bindings, entityNameGenerator);
addMissingDataTypeDeclaration(type, entity, entityNameGenerator);
}
}