import org.jmonde.state.State;
import org.jmonde.state.StateMachine;
import org.jmonde.state.StateUtil;

public class StateExample1 {

    private final State myStateIdle = new State();
    private final State myStateActive = new State();
    private final State myStateManual = new State(myStateActive);
    private final State myStateAuto = new State(myStateActive);
    private final StateMachine myMachine = new StateMachine(myStateIdle);
    private boolean myIsAutoPilotEngaged = true;

    public StateExample1() {
        initializeFSM();
        myMachine.enter();
    }

    private void initializeFSM() {
        myStateManual.makeAutoChild();

        StateUtil.addActionEnter(myStateIdle,
                                 new Runnable() {
                                     public void run() {
                                         dreamOfGlory();
                                     }});
        StateUtil.addActionLeave(myStateIdle,
                                 new Runnable() {
                                     public void run() {
                                         wakeup();
                                     }});

        StateUtil.addActionEnter(myStateActive,
                                 new Runnable() {
                                     public void run() {
                                         fastenHarness();
                                     }});
        StateUtil.addActionLeave(myStateActive,
                                 new Runnable() {
                                     public void run() {
                                         removeHarness();
                                     }});

        StateUtil.addActionEnter(myStateAuto,
                                 new Runnable() {
                                     public void run() {
                                         engageAutoPilot();
                                     }});
        StateUtil.addActionLeave(myStateAuto,
                                 new Runnable() {
                                     public void run() {
                                         disengageAutoPilot();
                                     }});
        StateUtil.addActionCurrent(myStateAuto,
                                   new Runnable() {
                                       public void run() {
                                           if (isAutoPilotError()) {
                                               transitionTo(myStateManual);
                                           }
                                       }});

        StateUtil.addActionEnter(myStateManual,
                                 new Runnable() {
                                     public void run() {
                                         donScarfAndGoggles();
                                     }});
        StateUtil.addActionLeave(myStateManual,
                                 new Runnable() {
                                     public void run() {
                                         doffScarfAndGoggles();
                                     }});
    }

    public void activate() {
        if (myStateIdle.isActive()) {
            transitionTo(myStateActive);
        }
    }

    public void auto() {
        if (myStateManual.isActive()) {
            myMachine.leaveFor(myStateAuto);
            // transition actions can go here, if needed
            myMachine.enter();
        }
    }

    public void deactivate() {
        if (myStateActive.isActive()) {
            transitionTo(myStateIdle);
        }
    }

    public void manual() {
        if (myStateAuto.isActive()) {
            transitionTo(myStateManual);
        }
    }

    private void disengageAutoPilot() {
        System.out.println("disengageAutoPilot");
    }

    private void doffScarfAndGoggles() {
        System.out.println("doffScarfAndGoggles");
    }

    private void donScarfAndGoggles() {
        System.out.println("donScarfAndGoggles");
    }

    private void engageAutoPilot() {
        System.out.println("engageAutoPilot");
    }

    private void fastenHarness() {
        System.out.println("fastenHarness");
    }

    private void dreamOfGlory() {
        System.out.println("dreamOfGlory");
    }

    private boolean isAutoPilotError() {
        return ! myIsAutoPilotEngaged;
    }

    private void removeHarness() {
        System.out.println("removeHarness");
    }

    private void wakeup() {
        System.out.println("wakeup");
    }

    /*
     * A simple transition without support for transition actions.
     */
    private void transitionTo(State nextState) {
        myMachine.leaveFor(nextState);
        myMachine.enter();
    }

    public static void main(String[] args) {
        StateExample1 d = new StateExample1();
        d.activate();
        d.auto();
        d.manual();
        d.activate(); // should be ignored, we're already active
        d.deactivate();
        d.myIsAutoPilotEngaged = false;
        d.activate();
        d.auto();
        d.myIsAutoPilotEngaged = true;
        d.deactivate();
        d.activate();
    }
}
