
import Interaction from "./Interaction";
import InteractionFactory from "./InteractionFactory";
import StepNFA from "./StepNFA";
import StepState, { transitionType } from "./StepState";

export default class Step {

    public expression: string;
    public stepDFA: StepNFA;

    constructor(expression: string, dfa: StepNFA) {
        this.expression = expression;
        this.stepDFA = dfa;
    }

    get enteringInteractionList(): Interaction[] {
        return Array.from(this.stepDFA.transitions.get(this.stepDFA.startState).keys())
                    .map((label) => InteractionFactory.parseInteraction(label));
    }

    public followSequence(sequence: Interaction[]): { state: StepState, interactionsNotConsumed: Interaction[]} {
        let state = this.stepDFA.startState;
        const interactionsNotConsumed = sequence.slice();
        while (interactionsNotConsumed.length > 0 && !this.isEnteringInteraction(interactionsNotConsumed[0])) {
            interactionsNotConsumed.shift();
        }
        while (interactionsNotConsumed.length > 0) {
            const interaction = interactionsNotConsumed.shift();
            state = this.followInteraction(state, interaction);
            if (state === null) {
                return {
                    state: null,
                    interactionsNotConsumed,
                };
            }
        }
        return {
            state,
            interactionsNotConsumed,
        };
    }

    private isEnteringInteraction(interaction: Interaction): boolean {
        return this.enteringInteractionList.some((enteringInteraction) => enteringInteraction.toString() === interaction.toString());
    }

    private followInteraction(currentState: StepState, interaction: Interaction): StepState {
        if (this.stepDFA.transitions.has(currentState)) {
            const transition = this.stepDFA.transitions.get(currentState);
            if (transition.has(interaction.getLabel())) {
                return transition.get(interaction.getLabel())[0];
            } else if (transition.has(interaction.toString())) {
                return transition.get(interaction.toString())[0];
            } else if (transition.has(transitionType.star)) {
                return transition.get(transitionType.star)[0];
            }
        } else {
            return null;
        }
    }

}
