package com.cardshifter.modapi.phase;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.function.Predicate;
import com.cardshifter.modapi.base.Component;
import com.cardshifter.modapi.base.Entity;
public class PhaseController extends Component {
private final LinkedList<Phase> upcomingPhases = new LinkedList<>();
private final LinkedList<Phase> permanentPhases = new LinkedList<>();
private int phaseNumber;
private int recreateCount;
public PhaseController() {
}
public PhaseController addPhase(Phase phase) {
permanentPhases.add(phase);
upcomingPhases.add(phase);
return this;
}
public void insertTemporaryPhaseNext(Phase phase) {
upcomingPhases.add(1, phase);
}
public boolean insertTemporaryPhaseBefore(Phase phase, Predicate<Phase> beforePhase) {
ListIterator<Phase> it = navigateToRecreate(beforePhase);
if (it != null) {
if (it.previousIndex() >= 0) {
it.previous();
}
it.add(phase);
}
return it != null;
}
private ListIterator<Phase> navigateToRecreate(Predicate<Phase> after) {
ListIterator<Phase> it = navigateTo(upcomingPhases.listIterator(), after);
if (it == null) {
int size = upcomingPhases.size();
upcomingPhases.addAll(permanentPhases);
it = navigateTo(upcomingPhases.listIterator(size), after);
if (it == null) {
return null;
}
}
return it;
}
private static <T> ListIterator<T> navigateTo(ListIterator<T> iterator, Predicate<T> navigateAfter) {
ListIterator<T> it = iterator;
while (it.hasNext()) {
T next = it.next();
if (navigateAfter.test(next)) {
return it;
}
}
return null;
}
public boolean insertTemporaryPhaseAfter(Phase phase, Predicate<Phase> afterPhase) {
ListIterator<Phase> it = navigateToRecreate(afterPhase);
if (it != null) {
it.add(phase);
}
return it != null;
}
public Phase getCurrentPhase() {
refillPhases();
return upcomingPhases.getFirst();
}
private void refillPhases() {
if (upcomingPhases.isEmpty()) {
upcomingPhases.addAll(permanentPhases);
}
}
public Phase nextPhase() {
Phase oldPhase = getCurrentPhase();
executeEvent(new PhaseEndEvent(this, getEntity().getGame(), oldPhase));
phaseNumber++;
upcomingPhases.removeFirst();
Phase currentPhase = getCurrentPhase();
if (currentPhase == permanentPhases.peekFirst()) {
recreateCount++;
}
executeEvent(new PhaseStartEvent(this, getEntity().getGame(), oldPhase, currentPhase));
return currentPhase;
}
public Entity getCurrentEntity() {
return getCurrentPhase().getOwner();
}
/**
* Get the individual phase number. Increased with each call to {@link #nextPhase()}
* @return The phase number of the current phase
*/
public int getPhaseNumber() {
return phaseNumber;
}
/**
* Return the number of loops that has been made. Increased whenever {@link #nextPhase()} starts on the first permanent phase.
* @return Number of times the upcomingPhases has been recreated from the list of permanentPhases
*/
public int getRecreateCount() {
return recreateCount;
}
public void insertTemporaryPhaseBeforeCurrent(Phase phase) {
this.upcomingPhases.addFirst(phase);
}
}