package com.cardshifter.modapi.actions;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import com.cardshifter.modapi.base.Entity;
public class ECSAction {
private final Entity owner;
private final String name;
private final Predicate<ECSAction> allowed;
private final Consumer<ECSAction> perform;
private final List<TargetSet> targetSets = new ArrayList<>();
public ECSAction(Entity owner, String name, Predicate<ECSAction> allowed, Consumer<ECSAction> perform) {
this.owner = owner;
this.name = name;
this.allowed = allowed;
this.perform = perform;
}
public String getName() {
return name;
}
public Entity getOwner() {
return owner;
}
public ECSAction copy() {
return copy(owner);
}
public ECSAction copy(Entity copyTo) {
ECSAction action = new ECSAction(copyTo, this.name, this.allowed, this.perform);
for (TargetSet set : targetSets) {
action.addTargetSet(set.getMin(), set.getMax());
TargetSet lastSet = action.getTargetSets().get(action.getTargetSets().size() - 1);
set.getChosenTargets().forEach(target -> lastSet.addTarget(target));
}
return action;
}
public boolean perform(Entity performer) {
synchronized (performer.getGame()) {
if (!this.isAllowed(performer)) {
return false;
}
if (!this.targetSets.stream().allMatch(targets -> targets.hasEnoughTargets())) {
return false;
}
try {
this.owner.getGame().executeEvent(new ActionPerformEvent(owner, this, performer), () -> this.perform.accept(this));
} catch (RuntimeException ex) {
throw new RuntimeException("Error performing action " + this, ex);
}
this.targetSets.forEach(TargetSet::clearTargets);
return true;
}
}
public boolean isAllowed(Entity performer) {
synchronized (performer.getGame()) {
ActionAllowedCheckEvent event = new ActionAllowedCheckEvent(owner, this, performer);
if (!owner.getGame().getEvents().executePostEvent(event).isAllowed()) {
return false;
}
return this.allowed.test(this);
}
}
public List<TargetSet> getTargetSets() {
return new ArrayList<>(targetSets);
}
public ECSAction addTargetSet(int min, int max) {
// TODO: Consider using an ECSAction builder and put `addTargetSet` there
this.targetSets.add(new TargetSet(this, min, max));
return this;
}
@Override
public String toString() {
return name + " for entity " + owner;
}
public Stream<Entity> getAllTargets() {
return targetSets.stream().flatMap(e -> e.getChosenTargets().stream());
}
}