package jalse.entities.functions;
import static jalse.entities.Entities.isEntityOrSubtype;
import static jalse.entities.functions.Functions.checkHasReturnType;
import static jalse.entities.functions.Functions.checkNoParams;
import static jalse.entities.functions.Functions.checkNotDefault;
import static jalse.entities.functions.Functions.firstGenericTypeArg;
import static jalse.entities.functions.Functions.getIDSuppliers;
import static jalse.entities.functions.Functions.returnTypeIs;
import static jalse.entities.functions.Functions.toClass;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;
import jalse.entities.DefaultEntityProxyFactory;
import jalse.entities.Entity;
import jalse.entities.EntityContainer;
import jalse.entities.annotations.EntityID;
import jalse.entities.annotations.GetEntities;
import jalse.entities.methods.GetEntitiesMethod;
/**
* This is a method function for {@link GetEntities} annotation. It will resolve an
* {@link GetEntitiesMethod} to be used by the entity typing system. This differs from the usual
* getting of {@link Entity} as it also lets gain a subset of {@link Entity} using {@link EntityID}
* (so adding to any method will cause it to filter).<br>
* <br>
* The next example signature will resolve to {@link EntityContainer#getEntities()}.
*
* <pre>
* <code>
* {@code @GetEntities}
* {@code Set<Entity>} getGhosts();
* </code>
* </pre>
*
* The next example signature will resolve to {@link EntityContainer#getEntitiesOfType(Class)}.
*
* <pre>
* <code>
* {@code @GetEntities}
* {@code Set<Ghost>} getGhosts();
* </code>
* </pre>
*
* The next example signature will resolve to {@link EntityContainer#getEntitiesAsType(Class)}.
*
* <pre>
* <code>
* {@code @GetEntities(ofType = false)}
* {@code Set<Ghost>} getGhosts();
* </code>
* </pre>
*
* The next example signature will show how to use one of the above examples with a subset.
*
* <pre>
* <code>
* {@code @EntityID(mostSigBits = 0, leastSigBits = 1)}
* {@code @EntityID(mostSigBits = 0, leastSigBits = 2)}
* {@code @EntityID(mostSigBits = 0, leastSigBits = 3)}
* {@code @EntityID(mostSigBits = 0, leastSigBits = 4)}
* {@code @EntityID(mostSigBits = 0, leastSigBits = 5)}
* {@code @GetEntities}
* {@code Stream<Ghost>} getGhosts();
* </code>
* </pre>
*
* NOTE: This function will throw exceptions if {@link GetEntities} is present but the method
* signature is invalid.
*
* @author Elliot Ford
*
* @see DefaultEntityProxyFactory
*
*/
public class GetEntitiesFunction implements EntityMethodFunction {
@SuppressWarnings("unchecked")
@Override
public GetEntitiesMethod apply(final Method m) {
// Check for annotation
final GetEntities annonation = m.getAnnotation(GetEntities.class);
if (annonation == null) {
return null;
}
// Basic check method signature
checkHasReturnType(m);
checkNoParams(m);
checkNotDefault(m);
// Create ID suppliers
final Set<Supplier<UUID>> idSuppliers = getIDSuppliers(m);
// Check stream
if (!returnTypeIs(m, Set.class)) {
throw new IllegalArgumentException("Must have Set return type");
}
// Get entity type
final Type entityType = firstGenericTypeArg(m.getGenericReturnType());
// Check entity
if (!isEntityOrSubtype(toClass(entityType))) {
throw new IllegalArgumentException("Entity must be obtainable from return type");
}
// Create stream entities method
return new GetEntitiesMethod((Class<? extends Entity>) entityType, idSuppliers, annonation.ofType());
}
}