
import IInteraction from "./InteractionFactory";
import StepNFA from "./StepNFA";
import { STEP_OPERATOR } from "./StepOperator";
import StepState, { transitionType } from "./StepState";
export default class StepAST {

    public label: STEP_OPERATOR | IInteraction;
    public left: StepAST;
    public right: StepAST;
    public parameter: string;

    constructor(label, left, right, parameter) {
        this.left = left;
        this.right = right;
        this.label = label;
        this.parameter = parameter;
    }

    public buildNFA(): Promise<StepNFA> {
        if (this.label === STEP_OPERATOR.and) {
            return this.buildAnd();
        } else if (this.label === STEP_OPERATOR.or) {
            return this.buildOr();
        } else if (this.label === STEP_OPERATOR.arrow) {
            return this.buildArrow();
        } else if (this.label === STEP_OPERATOR.seq) {
            return this.buildSeq();
        } else if (this.label === STEP_OPERATOR.if) {
            return this.buildIf();
        } else if (this.label === STEP_OPERATOR.if_else) {
            return this.buildIfElse();
        } else {
            return this.buildInteraction();
        }
    }

    /// TODO
    private buildAnd(): Promise<StepNFA> {

        let leftNFA: StepNFA;
        let rightNFA: StepNFA;

        let arrowLeft: StepNFA;
        let arrowRight: StepNFA;

        return Promise.all([this.left.buildNFA(), this.right.buildNFA()])
            .then(([left, right]) => {
                leftNFA = left;
                rightNFA = right;
                return left.arrow(right);
            }).then((left) => {
                arrowLeft = left;
                return rightNFA.arrow(leftNFA);
            }).then((right) => {
                arrowRight = right;
                return arrowLeft.or(arrowRight);
            });
    }

    private buildOr(): Promise<StepNFA> {
        return  Promise.all([this.left.buildNFA(), this.right.buildNFA()])
        .then(([leftNFA, rightNFA]) => {
            return leftNFA.or(rightNFA);
        });
    }

    private buildArrow(): Promise<StepNFA> {
        return  Promise.all([this.left.buildNFA(), this.right.buildNFA()])
        .then(([leftNFA, rightNFA]) => {
            return leftNFA.arrow(rightNFA);
        });
    }

    private buildSeq(): Promise < StepNFA > {
        return  Promise.all([this.left.buildNFA(), this.right.buildNFA()])
        .then(([leftNFA, rightNFA]) => {
            return leftNFA.sequence(rightNFA);
        });
    }

    private buildInteraction(): Promise < StepNFA > {
        const start = new StepState();
        const end = new StepState();
        const interaction = this.label as IInteraction;
        const nfa = new StepNFA(start, [end], [start, end ], new Map());
        nfa.addTransition(start, end, interaction.toString());

        return Promise.resolve(nfa);
    }

    private buildIf(): Promise<StepNFA> {
        return this.left.buildNFA().then((step) => {
            return step.if(this.parameter);
        });
    }

    private buildIfElse(): Promise<StepNFA> {
        return  Promise.all([this.left.buildNFA(), this.right.buildNFA()])
        .then(([ifNFA, elseNFA]) => {
            return ifNFA.ifElse(elseNFA, this.parameter);
        });
    }
}
