#ifndef ASTL_CLASS_DFA_DEFAULT
#define ASTL_CLASS_DFA_DEFAULT

#include <astl.h> // DFA_base

template <class DFA>
class DFA_default : public DFA_base
{
protected :
  DFA      dfa;

public:
  typedef typename DFA::Sigma          Sigma;
  typedef typename DFA::Alphabet       Alphabet;
  typedef typename DFA::State          State;
  typedef typename DFA::Tag            Tag;
  //  typedef typename DFA::Edges          Edges;
  typedef typename DFA::const_iterator const_iterator;
  
  State&   null_state;
  Alphabet default_letter;   

  DFA_default(const Alphabet &def_letter, unsigned long n = 0)
    : dfa(n), null_state(dfa.null_state), default_letter(def_letter)
  { }

  // For edges class, one has to redefine method find to take in account the
  // default transition (brute force):
  class Edges : public DFA::Edges
  {
  protected:
    Alphabet default_letter;
  public:
    typedef typename DFA::Edges super;

    Edges(const typename DFA::Edges &x, const Alphabet &def_letter)
      : super(x), default_letter(def_letter)
      { }

    typename DFA::Edges::const_iterator find(const Alphabet &x) {
      typename DFA::Edges::const_iterator tmp = super::find(x);
      if (tmp == super::end())
	return super::find(default_letter);
      return tmp;
    }
  };

  State new_state() {
    return (dfa.new_state());
  }

  template <class OutputIterator>
  OutputIterator new_state(unsigned long how_many, OutputIterator x) {
    return (dfa.new_state(how_many, x));
  }

  void del_state(State s) {
    dfa.del_state(s);
  }

  void set_trans(State from, const Alphabet &a, State to) {
    ///   cout << "dfa_default::set_trans(" << from << ", " << a << ", " << to << ")" << endl;
    dfa.set_trans(from, a, to);
  }

  void del_trans(State s, const Alphabet &a) {
    dfa.del_trans(s, a);
  }

  void change_trans(State s, const Alphabet &a, State new_aim) {
    dfa.change_trans(s, a, new_aim);
  }

  void copy_state(State from, State to) {
    dfa.copy_state(from, to);
  }

  State duplicate_state(State s) {
    return (dfa.duplicate_state(s));
  }

  Tag&           tag(State s) {
    return (dfa.tag(s));
  }

  const Tag& tag(State s) const {
    return (dfa.tag(s));
  }

  State delta1(State s, const Alphabet &a) const {
    State aim;
    return (((aim = dfa.delta1(s, a)) == null_state) ? 
	    dfa.delta1(s, default_letter) : aim);
  }

  // No use of default transitions:
  State delta0(State s, const Alphabet &a) const {
    return (dfa.delta1(s, a));
  }

  Edges delta2(State s) const {
    return (Edges(dfa.delta2(s), default_letter));
  }

  State initial() const {
    return (dfa.initial());
  }
  
  void initial(State s) {
    dfa.initial(s);
  }

  unsigned long  state_count() const {
    return (dfa.state_count());
  }

  unsigned long  trans_count() const {
    return (dfa.trans_count());
  }

  const_iterator begin() const {
    return (dfa.begin());
  }

  const_iterator end() const {
    return (dfa.end());
  }

  class bool_reference
  {
    DFA &dfa;
    State s;

  public:
    bool_reference(DFA &_dfa, State q)
      : dfa(_dfa), s(q)
    { }
    
    operator bool() const {
      return (dfa.final(s));
    }

    template <class T>
    bool_reference operator = (T t) {
      dfa.final(s) = t;
      return (*this);
    }

    template <class T>
    bool operator == (T t) const { 
      return (dfa.final(s) == t);
    }
  };
		   
  bool final(State s) const {
    return (dfa.final(s));
  }

  bool_reference final(State s) {
    return (bool_reference(dfa, s));
  }

};  

#endif // ASTL_CLASS_DFA_DEFAULT



