package tc.oc.pgm.filters.matcher.match;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import com.google.common.collect.Range;
import tc.oc.pgm.features.Feature;
import tc.oc.pgm.features.FeatureDefinition;
import tc.oc.pgm.features.FeatureFactory;
import tc.oc.pgm.filters.Filter;
import tc.oc.pgm.filters.FilterListener;
import tc.oc.pgm.filters.FilterMatchModule;
import tc.oc.pgm.filters.matcher.TypedFilter;
import tc.oc.pgm.filters.matcher.player.ParticipatingFilter;
import tc.oc.pgm.filters.query.IMatchQuery;
import tc.oc.pgm.match.Match;
import tc.oc.pgm.match.MatchPlayer;
public class PlayerCountFilter extends TypedFilter.Impl<IMatchQuery> implements FeatureFactory<PlayerCountFilter.Reactor> {
private final @Inspect Range<Integer> range;
private final @Inspect Filter filter;
public PlayerCountFilter(Filter filter, Range<Integer> range, boolean participants, boolean observers) {
this.range = range;
if(!observers) {
filter = ParticipatingFilter.PARTICIPATING.and(filter);
}
if(!participants) {
filter = ParticipatingFilter.OBSERVING.and(filter);
}
this.filter = filter;
}
@Override
public Stream<? extends FeatureDefinition> dependencies() {
return Stream.of(filter);
}
@Override
public boolean isDynamic() {
return true;
}
@Override
public boolean matches(IMatchQuery query) {
return query.feature(this).response();
}
@Override
public Reactor createFeature(Match match) {
return new Reactor(match);
}
@Override
public void load(Match match) {
match.features().get(this);
}
class Reactor implements Feature<PlayerCountFilter>, FilterListener<MatchPlayer> {
private final FilterMatchModule fmm;
private final Set<MatchPlayer> players = new HashSet<>();
Reactor(Match match) {
this.fmm = match.needMatchModule(FilterMatchModule.class);
fmm.onChange(MatchPlayer.class, filter, this);
}
@Override
public PlayerCountFilter getDefinition() {
return PlayerCountFilter.this;
}
boolean response() {
return range.contains(players.size());
}
@Override
public void filterQueryChanged(MatchPlayer filterable, boolean response) {
final boolean before = response();
if(response) {
players.add(filterable);
} else {
players.remove(filterable);
}
if(before != response()) {
fmm.invalidate(filterable.getMatch());
}
}
}
}