package jalse.entities;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jalse.actions.ActionScheduler;
import jalse.attributes.AttributeContainer;
import jalse.attributes.AttributeListener;
import jalse.attributes.AttributeType;
import jalse.misc.Identifiable;
import jalse.misc.ListenerSet;
import jalse.tags.Taggable;
/**
* Entity plays the greatest role in the overall data model. An entity is representative of a single
* entity or group of entities with a defined identities. Entities have {@link AttributeType} as
* well as {@link AttributeListener} for trigger code upon add, removal or change of those
* attributes. Entities can create and kill other entities (tree-like structure) these events can be
* accessed by adding {@link EntityListener}. <br>
* <br>
* Entities can be wrapped and marked as specific entity types as long as the inheriting interface
* follows what is outlined in {@link Entities}. Entity have can have a number of types (subclasses
* of {@link Entity}) which can be used to identify a collection of entities with similar state or
* function.<br>
* <br>
* An example of how the type marking works:
*
* <pre>
* <code>
* public interface Animal extends Entity {}
* public interface FlyingAnimal extends Animal {}
*
* Entity e; // Previously created entity.
* e.markAsType(FlyingAnimal.class);
*
* assert e.isMarkedAsType(Animal.class);
* </code>
* </pre>
*
* NOTE: Taking an entity {@link #asType(Class)} is similar to casting but does not mark as the
* entity with the type.
*
*
* @author Elliot Ford
*
* @see EntityContainer
* @see DefaultEntityContainer
* @see EntityListener
* @see EntityFactory
* @see Entities#asType(Entity, Class)
*
*/
public interface Entity extends EntityContainer, Identifiable, AttributeContainer, Taggable, ActionScheduler<Entity> {
/**
* Adds a listener for the entity.
*
* @param listener
* Listener to add.
*
* @return {@code true} if container did not already contain this listener.
* @throws NullPointerException
* if listener is null.
*
* @see ListenerSet#add(Object)
*
*/
boolean addEntityTypeListener(EntityTypeListener listener);
/**
* Convenience method for wrapping the entity to a different type.
*
* @param type
* Entity type to wrap to.
* @return The wrapped entity.
*
* @see Entities#asType(Entity, Class)
*/
default <T extends Entity> T asType(final Class<T> type) {
return Entities.asType(this, type);
}
/**
* Gets the parent container.
*
* @return The parent container or null if not found.
*/
EntityContainer getContainer();
/**
* Gets all the entity listeners.
*
* @return All the entity listeners.
*/
Set<? extends EntityTypeListener> getEntityTypeListeners();
/**
* Gets the types this entity has been marked as.
*
* @return Marked types.
*
* @see #streamMarkedAsTypes()
*/
default Set<Class<? extends Entity>> getMarkedAsTypes() {
return streamMarkedAsTypes().collect(Collectors.toSet());
}
/**
* This is a convenience method for getting the container (optional).
*
* @return Optional containing the container or else empty optional if the entity is not alive.
*/
default Optional<EntityContainer> getOptContainer() {
return Optional.ofNullable(getContainer());
}
/**
* Checks whether there is an associated container.
*
* @return Whether there was a container.
*/
default boolean hasContainer() {
return getContainer() != null;
}
/**
* Checks whether the container contains a particular listener.
*
* @param listener
* The EntityListener to check for.
* @return Whether the container contains the given EntityListener.
*/
default boolean hasEntityTypeListener(final EntityTypeListener listener) {
return getEntityTypeListeners().contains(listener);
}
/**
* Checks if the entity is alive.
*
* @return Whether the entity is alive.
*/
boolean isAlive();
/**
* Checks whether the entity has the associated type.
*
* @param type
* Entity type to check.
* @return Whether the entity was previously associated to the type.
*/
boolean isMarkedAsType(Class<? extends Entity> type);
/**
* Kills the entity.
*
* @return Whether the entity was alive.
*/
boolean kill();
/**
* Adds the specified type to the entity. If any of the ancestry of this type are not associated
* to this entity they will also be added.
*
* @param type
* Entity type to add.
* @return Whether the type was not associated to the entity.
*/
boolean markAsType(Class<? extends Entity> type);
/**
* Removes a entity listener.
*
* @param listener
* Listener to remove.
*
* @return {@code true} if the listener was removed.
* @throws NullPointerException
* if listener is null.
*
* @see ListenerSet#remove(Object)
*
*/
boolean removeEntityTypeListener(EntityTypeListener listener);
/**
* Removes all listeners for entities.
*/
void removeEntityTypeListeners();
/**
* Streams the types this entity has been marked as.
*
* @return Stream of marked types.
*
*/
Stream<Class<? extends Entity>> streamMarkedAsTypes();
/**
* Transfers this entity to the specified destination container.
*
* @param destination
* Target container.
* @return Whether the entity was transferred.
*
*/
boolean transfer(EntityContainer destination);
/**
* Removes all the types from the entity.
*/
void unmarkAsAllTypes();
/**
* Removes the specified type from the entity. If this type is the ancestor of any other types
* associated to the entity they will be removed.
*
* @param type
* Entity type to remove.
* @return Whether the entity was previously associated to the type (or its any of its
* children).
*/
boolean unmarkAsType(Class<? extends Entity> type);
}