/*
 * ASTL - the Automaton Standard Template Library.
 * C++ generic components for Finite State Machine handling.
 * Copyright (C) 2000 Vincent Le Maout (vlemaout@lexiquest.fr).
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


#ifndef ASTL_STREAM_ALGORITHMS
#define ASTL_STREAM_ALGORITHMS

#include <iostream>
#include <astl.h>
#include <cursor.h>
#include <set>

class DFA_stream
{
public:
  typedef int State;
  struct bool_reference;
  friend bool_reference;

protected:
  ostream &out;
  set<State> F;
  State count;

public:
  State null_state;

  DFA_stream(ostream &output)
    : out(output), count(0), null_state(0)
  { }

  State new_state() { 
    return ++count;
  }

  struct bool_reference
  {
    State q;
    DFA_stream &dfa;

    bool_reference(State p, DFA_stream &a)
      : q(p), dfa(a)
    { }

    bool_reference& operator= (bool b) {
      if (b == true) dfa.F.insert(q);
      return *this;
    }
  };

  bool_reference final(State q) {
    return bool_reference(q, *this);
  }

  template <class Alphabet>
  void set_trans(State q, const Alphabet &a, State p) {
    out << (F.find(q) != F.end() ? -q : q) << " " 
	<< a << " " << (F.find(p) != F.end() ? -p : p) << endl;
  }
};

//TODO: ce curseur ne respecte pas les spécifications
//il faut y ajouter une pile pour pouvoir appeler directement language(cout,
// istream_cursor(cin)); par exemple
// sujet à changement, ne pas utiliser
class istream_cursor : public dfirst_cursor_concept
{
public:
  typedef int State;

protected:
  istream &in;
  State q, p;
  int a;
  bool has_poped;
  int depth;

public:
  typedef istream_cursor self;

  istream_cursor()               // end of range
    : in(cin), q(0), depth(0)
  { }

  istream_cursor(istream &input) // start of range
    : in(input), q(0), has_poped(false), depth(0) {
    forward();
    has_poped = false;
  }

  State src() const {
    return (q > 0 ? q : -q);
  }

  State aim() const {
    return (p > 0 ? p : -p);
  }

  bool operator== (const self &x) const { // we only need this operator to test for the end of range
    return q == x.q;   
  }

#ifdef WIN32
  bool operator!= (const self &x) const {
    return !(*this == x);
  }
#endif

  bool src_final() const {
    return q < 0;
  }

  bool aim_final() const {
    return p < 0;
  }

  int letter() const {
    return a;
  }

  bool forward() 
  {
    if (has_poped) 
      has_poped = false;
    else {
      State tmp_q;
      char tmp_a;
      in >> tmp_q;
      if (in.eof()) {
	q = 0;
	has_poped = true;
      }
      else {
	in >> tmp_a >> p;
	has_poped = (tmp_q != p);
	q = tmp_q;
	a = tmp_a;
      }
    }
    return !has_poped;
  }
};

#endif // ASTL_STREAM_ALGORITHMS

