package FDA;
import Tools.Console;
import java.util.*;
import java.util.function.Function;
public class State {
private ArrayList> transitions = new ArrayList<>();
private Transition other = null;
private String name = "Node";
private String noTransitionError = "NOT AVAILABLE TRANSITION FOR ELEMENT ";
public State(String name) {
this.name = name;
}
public State() {
}
public String getNoTransitionError() {
return noTransitionError;
}
public void setNoTransitionError(String noTransitionError) {
this.noTransitionError = noTransitionError;
}
public Transition addTransition(T transitionValue, State toTransit, boolean ignoreRead, boolean write) {
checkAddTransition(toTransit, ignoreRead);
Transition transition = new Transition(transitionValue, toTransit, ignoreRead, write);
transitions.add(transition);
return transition;
}
public Transition addTransitionFunction(Function transitionFunction, State toTransit, boolean ignoreRead, boolean write) {
checkAddTransition(toTransit, ignoreRead);
Transition transition = new Transition(transitionFunction, toTransit, ignoreRead, write);
transitions.add(transition);
return transition;
}
public Transition addOtherElementTransitionFunction(State toTransit, boolean ignoreRead, boolean write) {
checkAddTransition(toTransit, ignoreRead);
other = new Transition(this::otherFunction, toTransit, ignoreRead, write);
return other;
}
private void checkAddTransition(State toTransit, boolean ignoreRead) {
if (toTransit == null) {
throw new IllegalArgumentException("Transitioned node must be not null");
}
if (!(toTransit instanceof FinalState) && ignoreRead) {
throw new IllegalArgumentException("Ignore read can only be used in FinalStates");
}
}
private boolean otherFunction(T next) {
for (Transition transition : transitions) {
if (transition.apply(next)) {
return false;
}
}
return true;
}
@Override
public String toString() {
return "State{" +
"transitions=" + transitions +
", name='" + name + '\'' +
'}';
}
protected FDAData feedForward(FDA fda, Transition transition, List sequence, T prev, boolean debug) {
//Check first if current node is final
if (this instanceof FinalState) {
if (prev != null) {
printPath(debug, prev.toString(), true, !transition.isReadNext(), transition.isWrite());
}
fda.printOnFinish(debug, true, prev.toString());
fda.onReadSequence((FinalState) this, sequence);
//end read sequence
return new FDAData(1, transition, this, prev);
}
if (prev != null) {
if (transition != null) {
printPath(debug, prev.toString(), false, false, transition.isWrite());
} else {
printPath(debug, prev.toString(), false, false, false);
}
}else{
printPath(debug, "", false, false, false);
}
//SELECTION OF NEXT CHARACTER
T character;
if (transition == null || transition.isReadNext()) {
if (fda.getIterator().hasNext()) {
character = (T) fda.getIterator().next();//read next character
} else {
FDAException exception = new FDAException(-1, "REACH END OF ITERATOR BUT NOT REACHED FINAL STATE");
boolean notfinish = fda.onError(exception);
int internalCode = notfinish?1:-1;
return new FDAData(internalCode, transition, this, prev);
}
} else {
character = prev;
}
//Check available transition
State nextState = null;
Transition transitionUsed = null;
for (Transition element : transitions) {
if (element.apply(character)) {
nextState = element.getToTransit();
transitionUsed = element;
}
}
if (nextState == null && other != null) {//Other element transition
nextState = other.getToTransit();
transitionUsed = other;
}
if (nextState == null) {//If there is no available transition
FDAException exception = new FDAException(-2, noTransitionError);
boolean notfinish = fda.onError(exception);
int internalCode = notfinish?1:-1;
return new FDAData(internalCode, transition, this, fda.getIterator().getCurrentElement());
}
if (transitionUsed != null) {//If there is transition call semantic actions of transition
if (transitionUsed.isWrite()) {
sequence.add(character);
}
try {
transitionUsed.callActions(character, sequence, fda.getIterator());
} catch (FDAException e) {
boolean notfinish = fda.onError(e);
int internalCode = notfinish?1:-1;
return new FDAData(internalCode, transition, this, fda.getIterator().getCurrentElement());
}
}
// go to next state of transition
return nextState.feedForward(fda, transitionUsed, sequence, character, debug);
}
private void printPath(boolean debug, String prev, boolean isFinal, boolean ignoreRead, boolean write) {
if (!debug) return;
String modifiers = "";
prev = prev.replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
if (ignoreRead) {
modifiers += Console.ANSI_BLUE + "[IGNORE READ]";
}
if (write) {
modifiers += Console.ANSI_GREEN + "[W] ";
}
if (isFinal) {
Console.print(Console.ANSI_CYAN + "(" + prev + ") " + modifiers + Console.ANSI_YELLOW + "<<" + name + ">>" + Console.ANSI_PURPLE + " ==> ");
} else {
Console.print(Console.ANSI_CYAN + "(" + prev + ") " + modifiers + Console.ANSI_YELLOW + name + Console.ANSI_PURPLE + " ==> ");
}
}
}