package generators;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import code.ast.TypeDeclaration;
import models.algebra.Type;
import models.dataConstraintModel.DataConstraintModel;
import models.dataConstraintModel.ListType;
import models.dataConstraintModel.MapType;
import models.dataConstraintModel.ResourceHierarchy;
import models.dataFlowModel.DataTransferChannel;
public class CodeGenerationContext {
protected HashMap<String, HashMap<ResourceHierarchy, String>> componentNames = new HashMap<>();
protected Map<ResourceHierarchy, TypeDeclaration> resourceHierarchyToComponent;
protected Map<String, Type> componentNameToType;
protected Map<ResourceHierarchy, Map<ResourceHierarchy, Map<DataTransferChannel, String>>> updateMethods;
protected ILanguageSpecific langSpec = null;
protected IPlatformSpecific platformSpec = null;
public CodeGenerationContext(ILanguageSpecific langSpec, IPlatformSpecific platformSpec) {
this.resourceHierarchyToComponent = new HashMap<>();
this.componentNameToType = new HashMap<>();
this.updateMethods = new HashMap<>();
this.langSpec = langSpec;
this.platformSpec = platformSpec;
}
public String getComponentName(ResourceHierarchy res, ILanguageSpecific langSpec) {
String name = res.getResourceName();
if (res.getNumParameters() > 0) {
if (name.length() > 3 && name.endsWith("ies")) {
name = name.substring(0, name.length() - 3) + "y";
} else if (name.length() > 1 && name.endsWith("s")) {
name = name.substring(0, name.length() - 1);
} else {
name += "Element";
}
}
String componentName = langSpec.toComponentName(name);
if (!generatesComponent(res)) return componentName;
// To avoid generating multiple components with the same name.
HashMap<ResourceHierarchy, String> resToName = componentNames.get(componentName);
if (resToName == null) {
resToName = new HashMap<>();
resToName.put(res, componentName);
componentNames.put(componentName, resToName);
return componentName;
}
if (resToName.get(res) == null) {
componentName += resToName.size();
resToName.put(res, componentName);
return componentName;
}
return resToName.get(res);
}
public Type getOrCreateComponentType(ResourceHierarchy res) {
return getOrCreateComponentType(getComponentName(res, langSpec));
}
public Type getOrCreateComponentType(String componentName) {
Type componentType = componentNameToType.get(componentName);
if (componentType != null) return componentType;
componentType = new Type(componentName, new code.ast.SimpleType(componentName));
componentNameToType.put(componentName, componentType);
return componentType;
}
public Type getImplStateType(ResourceHierarchy res, ILanguageSpecific langSpec) {
Set<ResourceHierarchy> children = res.getChildren();
if (children == null || children.size() == 0) {
// leaf resource.
return res.getResourceStateType();
} else {
ResourceHierarchy child = children.iterator().next();
if (children.size() == 1 && child.getNumParameters() > 0) {
// map or list.
if (DataConstraintModel.typeList.isAncestorOf(res.getResourceStateType()) || res.getResourceStateType() instanceof ListType) {
// list.
if (generatesComponent(child)) {
return langSpec.newListType(getOrCreateComponentType(child));
} else {
return langSpec.newListType(getImplStateType(child, langSpec));
}
} else if (DataConstraintModel.typeMap.isAncestorOf(res.getResourceStateType()) || res.getResourceStateType() instanceof MapType) {
// map.
if (generatesComponent(child)) {
return langSpec.newMapType(DataConstraintModel.typeString, getOrCreateComponentType(child).getInterfaceTypeName());
} else {
return langSpec.newMapType(DataConstraintModel.typeString, getImplStateType(child, langSpec).getInterfaceTypeName());
}
}
return null;
} else {
// class
return res.getResourceStateType();
}
}
}
public boolean generatesComponent(ResourceHierarchy res) {
if (res.getParent() == null) return true;
if (res.getChildren() == null || res.getChildren().size() == 0) return false;
if (res.getNumParameters() > 0 && res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0) return false;
if (res.getChildren().size() == 1 && res.getChildren().iterator().next().getNumParameters() > 0
&& (res.getChildren().iterator().next().getChildren() == null || res.getChildren().iterator().next().getChildren().size() == 0)) return false;
return true;
// return res.getParent() == null || !(res.getChildren() == null || res.getChildren().size() == 0);
}
public void putComponent(ResourceHierarchy res, TypeDeclaration component) {
resourceHierarchyToComponent.put(res, component);
}
public TypeDeclaration getComponent(ResourceHierarchy res) {
return resourceHierarchyToComponent.get(res);
}
public String getOrPutUpdateMethodName(ResourceHierarchy srcRes, DataTransferChannel ch, ResourceHierarchy dstRes) {
Map<ResourceHierarchy, Map<DataTransferChannel, String>> dstResUpdatesMethods = updateMethods.getOrDefault(dstRes, new HashMap<>());
updateMethods.put(dstRes, dstResUpdatesMethods);
Map<DataTransferChannel, String> dstResFromSrcResUpdatesMethods = dstResUpdatesMethods.getOrDefault(srcRes, new HashMap<>());
dstResUpdatesMethods.put(srcRes, dstResFromSrcResUpdatesMethods);
String updateMethodName = dstResFromSrcResUpdatesMethods.get(ch);
if (updateMethodName == null) {
String srcResComponentName = getComponentName(srcRes, langSpec);
String dstResComponentName = getComponentName(dstRes, langSpec);
if (generatesComponent(dstRes)) {
updateMethodName = CodeGenerator.updateMethodPrefix + CodeGenerator.from + srcResComponentName;
} else if (dstRes.getParent() != null) {
updateMethodName = CodeGenerator.updateMethodPrefix + dstResComponentName + CodeGenerator.from + srcResComponentName;
}
if (dstResFromSrcResUpdatesMethods.size() > 0) {
updateMethodName += dstResFromSrcResUpdatesMethods.size() + 1; // To avoid declaring the method multiply.
}
dstResFromSrcResUpdatesMethods.put(ch, updateMethodName);
}
return updateMethodName;
}
}