#ifndef __fsm_Gate_h__
#define __fsm_Gate_h__

namespace Gate {

class FSM;

class Context {
public:
  virtual void error(const char* state_name, const char* event_name) =0;
  virtual void Alarm(FSM* fsm) =0;
  virtual void EnterLocked(FSM* fsm) =0;
  virtual void EnterUnlocked(FSM* fsm) =0;
  virtual void ExitLocked(FSM* fsm) =0;
  virtual void ExitUnlocked(FSM* fsm) =0;
  virtual void Lock(FSM* fsm) =0;
  virtual void ThankYou(FSM* fsm) =0;
  virtual void Unlock(FSM* fsm) =0;
};

class State {
public:
  virtual const char* getName() const =0;
  virtual void enter(FSM* fsm);
  virtual void exit(FSM* fsm);
  virtual void Coin(FSM* fsm);
  virtual void Pass(FSM* fsm);
};

class LockedState : public State {
public:
  virtual const char* getName() const;
  virtual void enter(FSM* fsm);
  virtual void exit(FSM* fsm);
  virtual void Coin(FSM* fsm);
  virtual void Pass(FSM* fsm);
};

class UnlockedState : public State {
public:
  virtual const char* getName() const;
  virtual void enter(FSM* fsm);
  virtual void exit(FSM* fsm);
  virtual void Coin(FSM* fsm);
  virtual void Pass(FSM* fsm);
};

class FSM  {
  Context* context_;
  State*   state_;
  State*   newstate_;
  State*   terminal_;
  static LockedState Locked_;
  static UnlockedState Unlocked_;
public:
  FSM() { state_ = &Locked_; terminal_ = 0; }
  bool isTerminated() const { return state_ == terminal_; }

  void setContext(Context* context) { context_ = context; }
  Context* getContext() const { return context_; }

  void setNewState(State* state) { newstate_ = state; }
  State* getNewState() { return newstate_; }

  void setState(State* state) { state_ = state; }
  void setState() { state_ = newstate_; }
  State* getState() { return state_; }

  static State* Locked() { return &Locked_; }
  static State* Unlocked() { return &Unlocked_; }

  void Coin() { state_->Coin(this); }
  void Pass() { state_->Pass(this); }
};

}

#endif

