package com.lyndir.omicron.api;
import com.google.common.collect.*;
import com.lyndir.lhunath.opal.system.util.*;
import com.lyndir.omicron.api.error.NotAuthenticatedException;
import com.lyndir.omicron.api.error.NotObservableException;
import java.util.Optional;
import com.lyndir.omicron.api.util.Maybool;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* <i>10 15, 2012</i>
*
* @author lhunath
*/
public interface IGameObject extends GameObserver, GameObservable {
/**
* @return The unique identifier of this unit in the game.
*/
long getObjectID();
/**
* @return The game that hosts this object.
*/
IGame getGame();
/**
* @return The type that defines the behavior of this unit.
*/
IUnitType getType();
/**
* @return The modules that implement the behavior of this unit mapped by module type.
*/
ImmutableMultimap<PublicModuleType<?>, ? extends IModule> getModulesByType();
/**
* Get this object's module of the given type at the given index.
*
* @param moduleType The type of module to get.
* @param index The index of the module.
* @param <M> The type of the module.
*
* @return The module of the given type at the given index.
*/
default <M extends IModule> Optional<M> getModule(final PublicModuleType<M> moduleType, final int index) {
return Optional.ofNullable( Iterables.get( getModules( moduleType ), index, null ) );
}
/**
* Get this object's module of the given type at the given index.
*
* @param moduleType The type of module to get.
* @param predicate Return the first module of the given type for which the predicate holds true.
* @param <M> The type of the module.
*
* @return The module of the given type at the given index.
*/
default <M extends IModule> Optional<M> getModule(final PublicModuleType<M> moduleType, final Predicate<M> predicate) {
return getModules( moduleType ).stream().filter( predicate ).findFirst();
}
/**
* Get this object's modules of the given type.
*
* @param moduleType The type of module to get.
* @param <M> The type of the module.
*
* @return A list of modules of the given type or an empty list if there are none.
*/
@SuppressWarnings("unchecked")
default <M extends IModule> List<M> getModules(final PublicModuleType<M> moduleType) {
// Checked by Module's constructor.
return (List<M>) getModulesByType().get( moduleType );
}
/**
* Run a method on a module but return {@code elseValue} if this object doesn't have such a module.
*
* @param moduleType The type of the module to run a method on.
* @param index The index of the module to run a method on.
* @param elseValue The value to return if this object doesn't have a module of the given type at the given index.
* @param <M> The type of the module to run a method on.
*
* @return A proxy object that you can run your method on.
*/
default <M extends IModule, T> T onModuleElse(final PublicModuleType<M> moduleType, final int index, final T elseValue, final NNFunctionNN<M, T> operation)
throws NotAuthenticatedException, NotObservableException {
Optional<M> module = getModule( moduleType, index );
return module.isPresent()? operation.apply( module.get() ): elseValue;
}
/**
* Run a method on a module but return {@code elseValue} if this object doesn't have such a module.
*
* @param moduleType The type of the module to run a method on.
* @param predicate Run the method on the first module for which this predicate holds true.
* @param elseValue The value to return if this object doesn't have a module of the given type.
* @param <M> The type of the module to run a method on.
*
* @return A proxy object that you can run your method on.
*/
default <M extends IModule, T> T onModuleElse(final PublicModuleType<M> moduleType, final Predicate<M> predicate,
final T elseValue, final NNFunctionNN<M, T> operation)
throws NotAuthenticatedException, NotObservableException {
Optional<M> module = getModule( moduleType, predicate );
return module.isPresent()? operation.apply( module.get() ): elseValue;
}
/**
* Run a method on a module or do nothing if this object doesn't have such a module
* (in this case, if the method has a return value, it will return {@code null}).
*
* @param moduleType The type of the module to run a method on.
* @param index The index of the module to run a method on.
* @param <M> The type of the module to run a method on.
*
* @return A proxy object that you can run your method on.
*/
@Nullable
default <M extends IModule, T> T onModule(final PublicModuleType<M> moduleType, final int index, final NFunctionNN<M, T> operation)
throws NotAuthenticatedException, NotObservableException {
Optional<M> module = getModule( moduleType, index );
return module.isPresent()? operation.apply( module.get() ): null;
}
/**
* Run a method on a module or do nothing if this object doesn't have such a module
* (in this case, if the method has a return value, it will return {@code null}).
*
* @param moduleType The type of the module to run a method on.
* @param predicate Run the method on the first module for which this predicate holds true.
* @param <M> The type of the module to run a method on.
*
* @return A proxy object that you can run your method on.
*/
@Nullable
default <M extends IModule, T> T onModule(final PublicModuleType<M> moduleType, final Predicate<M> predicate, final NFunctionNN<M, T> operation)
throws NotAuthenticatedException, NotObservableException {
Optional<M> module = getModule( moduleType, predicate );
return module.isPresent()? operation.apply( module.get() ): null;
}
/**
* @return The modules that implement the behavior of this unit.
*/
default ImmutableCollection<? extends IModule> getModules(){
return getModulesByType().values();
}
@Nonnull
IGameObjectController<? extends IGameObject> getController();
@Override
default Maybool canObserve(@Nonnull final GameObservable observable) {
return onModuleElse( PublicModuleType.BASE, 0, Maybool.no(), module -> module.getController().canObserve( observable ) );
}
@Nonnull
@Override
default Stream<? extends ITile> observableTiles() {
return onModuleElse( PublicModuleType.BASE, 0, Stream.empty(), module -> module.getController().observableTiles() );
}
/**
* @return {@code true} if this object is owned by the currently authenticated player.
*/
default boolean isOwnedByCurrentPlayer() {
Optional<? extends IPlayer> owner = getOwner();
return owner.isPresent() && owner.get().isCurrentPlayer();
}
}