package at.oefai.aaa.agent.jam;

import at.oefai.aaa.agent.jam.types.Binding;

/**
 * Represents the runtime state of branch constructs.
 * @author Marc Huber
 * @author Jaeho Lee
 */
class PlanRuntimeBranchState implements PlanRuntimeState {

    private PlanBranchConstruct thisConstruct = null;
    private PlanRuntimeState substate = null;

    private int activeBranchNum; // index (0 based) to current branch

    /**  */
    PlanRuntimeBranchState(final PlanBranchConstruct be) {
        this.thisConstruct = be;
        this.substate = be.getBranch(0).newRuntimeState();
        this.activeBranchNum = 0;
    }

    // Member functions

    int getActiveBranchNum() { return this.activeBranchNum; }

    /** Execute something in one of the branches. */
    public State execute(final Binding b, final Goal thisGoal) {
        PlanConstruct currentConstruct;
        PlanBranchConstruct.BranchType branchType;
        branchType = this.thisConstruct.getBranchType();
        currentConstruct = this.thisConstruct.getBranch(this.activeBranchNum);

        if (this.substate == null) {
            this.substate = currentConstruct.newRuntimeState();
        }
        State returnVal = this.substate.execute(b, thisGoal);

        //
        // FAILED!
        //
        // Something in the branch failed so this construct may fail
        if (returnVal == State.CONSTRUCT_FAILED) {
            // If this is an AND branch, or if we've gone through all branches of an OR,
            // then the construct has failed.
            if (branchType == PlanBranchConstruct.BranchType.AND_BRANCH
                || this.activeBranchNum == this.thisConstruct.getNumBranches() - 1) {
                    return State.CONSTRUCT_FAILED;
            }
            this.substate = this.thisConstruct.getBranch(++this.activeBranchNum).newRuntimeState();
            return State.CONSTRUCT_INCOMP;
        } else if (returnVal == State.CONSTRUCT_INCOMP) { // INCOMPLETE Nothing's been determined at this point
            return State.CONSTRUCT_INCOMP;
        } else { // COMPLETE!
            // If this is an OR branch, or if we've gone through all branches of an AND,
            // then the construct has succeeded.
            if (branchType == PlanBranchConstruct.BranchType.OR_BRANCH
                || (this.activeBranchNum == this.thisConstruct.getNumBranches() - 1)) {
                    return State.CONSTRUCT_COMPLETE;
            }
            // More branches, so need to keep executing
            this.substate = this.thisConstruct.getBranch(++this.activeBranchNum).newRuntimeState();
            return State.CONSTRUCT_INCOMP;
        }
    }

    /**  */
    void setActiveBranchNum(final int n) {
        if (n >= 0 && n < this.thisConstruct.getNumBranches()) {
            this.activeBranchNum = n;
        } else {
            this.activeBranchNum = -1;
        }
    }

}

