package er.rest.util;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import com.webobjects.eoaccess.EOAttribute;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EOEntityClassDescription;
import com.webobjects.eocontrol.EOClassDescription;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSLog;
import com.webobjects.foundation.NSMutableDictionary;
import er.extensions.eof.ERXKey;
import er.extensions.eof.ERXKeyFilter;
import er.rest.ERXRestClassDescriptionFactory;
public class ERXRestSchema {
public static NSDictionary<String, Object> schemaForEntityNamed(String entityName, ERXKeyFilter filter) {
NSMutableDictionary<String, Object> schema = new NSMutableDictionary<>();
schema.setObjectForKey(entityName, "name");
NSDictionary<String, Object> properties = ERXRestSchema.schemaPropertiesForEntityNamed(entityName, filter, new HashSet<>());
schema.setObjectForKey(properties, "properties");
return schema;
}
protected static NSDictionary<String, Object> schemaPropertiesForEntityNamed(String entityName, ERXKeyFilter filter, Set<String> entities) {
if (entities.contains(entityName)) {
return null;
}
entities.add(entityName);
NSMutableDictionary<String, Object> properties = new NSMutableDictionary<>();
EOClassDescription classDescription = ERXRestClassDescriptionFactory.classDescriptionForEntityName(entityName);
EOEntity entity = null;
if (classDescription instanceof EOEntityClassDescription) {
entity = ((EOEntityClassDescription) classDescription).entity();
}
for (String attributeName : classDescription.attributeKeys()) {
ERXKey<Object> key = new ERXKey<>(attributeName);
if (filter.matches(key, ERXKey.Type.Attribute)) {
EOAttribute attribute = null;
if (entity != null) {
attribute = entity.attributeNamed(key.key());
}
NSMutableDictionary<String, Object> property = new NSMutableDictionary<>();
boolean optional = attribute != null && attribute.allowsNull();
property.setObjectForKey(optional, "optional");
Class<?> attributeClass = classDescription.classForAttributeKey(key.key());
if (String.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("string", "type");
if (attribute != null) {
int width = attribute.width();
if (width > 0) {
if (!optional) {
property.setObjectForKey(1, "minLength");
}
property.setObjectForKey(width, "maxLength");
}
}
}
else if (Date.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("string", "type");
property.setObjectForKey("date-time", "format");
}
else if (LocalDate.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("string", "type");
property.setObjectForKey("date", "format");
}
else if (LocalDateTime.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("string", "type");
property.setObjectForKey("date-time", "format");
}
else if (LocalTime.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("string", "type");
property.setObjectForKey("time", "format");
}
else if (OffsetDateTime.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("string", "type");
property.setObjectForKey("date-time", "format");
}
else if (Integer.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("integer", "type");
}
else if (BigDecimal.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("number", "type");
}
else if (Number.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("number", "type");
}
else if (Boolean.class.isAssignableFrom(attributeClass)) {
property.setObjectForKey("boolean", "type");
}
else {
NSLog.out.appendln("Unknown schema type '" + attributeClass.getName() + "' for entity '" + entityName + "'");
property.setObjectForKey("any", "type");
}
properties.setObjectForKey(property, key.key());
}
}
for (String toOneRelationshipName : classDescription.toOneRelationshipKeys()) {
ERXKey<Object> key = new ERXKey<>(toOneRelationshipName);
if (filter.matches(key, ERXKey.Type.ToOneRelationship)) {
EOClassDescription destinationClassDescription = classDescription.classDescriptionForDestinationKey(key.key());
ERXKeyFilter destinationFilter = filter._filterForKey(key);
NSDictionary<String, Object> destinationSchema = ERXRestSchema.schemaPropertiesForEntityNamed(destinationClassDescription.entityName(), destinationFilter, entities);
if (destinationSchema != null) {
properties.setObjectForKey(destinationSchema, key.key());
}
else {
// MS: Recursive reference to an entity .... wtf do we do.
}
/*
* HashMap property = new HashMap(); property.put("$ref", relationship.destinationEntity().name());
* properties.put(relationship.name(), property);
*/
}
}
for (String toManyRelationshipName : classDescription.toManyRelationshipKeys()) {
ERXKey<Object> key = new ERXKey<>(toManyRelationshipName);
if (filter.matches(key, ERXKey.Type.ToManyRelationship)) {
EOClassDescription destinationClassDescription = classDescription.classDescriptionForDestinationKey(key.key());
ERXKeyFilter destinationFilter = filter._filterForKey(key);
NSDictionary<String, Object> destinationSchema = ERXRestSchema.schemaPropertiesForEntityNamed(destinationClassDescription.entityName(), destinationFilter, entities);
if (destinationSchema != null) {
properties.setObjectForKey(destinationSchema, key.key());
}
else {
// MS: Recursive reference to an entity .... wtf do we do.
}
}
}
entities.remove(entityName);
return properties;
}
}