/*
 * 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_DOT_ALGORITHM
#define ASTL_DOT_ALGORITHM

#include <iostream>
#include <string>
#include <ccopy.h>

#ifdef WIN32
using namespace std;
#endif

class DFA_dot
{
public:
  ostream &out;
  typedef unsigned long State;
  unsigned long Q, null_state, _state_fontsize, _edge_fontsize;
  float _ratio, _ranksep;
  string _rankdir, _states_label;
  bool _initial, _concentrate;

  DFA_dot(ostream &output)
    : out(output), Q(0), null_state(0), _state_fontsize(14),
      _edge_fontsize(14),
      _ratio(.75), _ranksep(.75), _rankdir("LR"), _initial(true), 
      _concentrate(false)
  { }
  
  void graph_attributes() {
    out << "ratio=" << _ratio << ";" << endl;
    out << "concentrate=" << (_concentrate ? "TRUE" : "FALSE") << ";" << endl;
    out << "rankdir=" << _rankdir << ";" << endl;
    out << "ranksep=" << _ranksep << ";" << endl;
  }

  DFA_dot& ratio(float x) {
    _ratio = x;
    return *this;
  }

  DFA_dot& states_label(const string &x) {
    _states_label = x;
    return *this;
  }

  DFA_dot& state_fontsize(unsigned long x) {
    _state_fontsize = x;
    return *this;
  }

  DFA_dot& edge_fontsize(unsigned long x) {
    _edge_fontsize = x;
    return *this;
  }

  DFA_dot& concentrate(bool b) {
    _concentrate = b;
    return *this;
  }

  DFA_dot& rankdir(const string &s) {
    _rankdir = s;
    return *this;
  }

  DFA_dot& initial(bool b) {
    _initial = b;
    return *this;
  }

  DFA_dot& ranksep(float f) {
    _ranksep = f;
    return *this;
  }

  bool initial() const {
    return _initial;
  }

  unsigned long new_state() {
    return ++Q;
  }
  
  template <class Alphabet>
  void set_trans(State q, const Alphabet &a, State p) {
    out << q << " -> " << p << " [label=\"" << a <<
      "\",fontsize=" << _edge_fontsize << "];" << endl;
  }

  struct bool_reference
  {
    State q;
    DFA_dot &dfa;

    bool_reference(State p, DFA_dot &a)
      : q(p), dfa(a)
    { }

    bool_reference& operator= (bool b) {
      dfa.out << q << " [shape=circle";
      if (b == true) dfa.out << ",style=bold";
      dfa.out << ",fontsize=" << dfa._state_fontsize;
      if (dfa._states_label.size() > 0)
				dfa.out << ",label=\"" << dfa._states_label << "\"";
      dfa.out << "];" << endl;
      return *this;
    }
  };

  bool_reference final(State q) {
    return bool_reference(q, *this);
  }
};

// This function seems to confuse g++ 2.96, temporarily removed
// Output the graph with default configuration:
// template <class DFirstCursor>
// void dot(ostream &out, DFirstCursor x, DFirstCursor y = DFirstCursor())
// {
//  DFA_dot output_stream(out);
//  dot(out, x, y);
// }

// Customized output representation through the DFA_dot object: 
template <class DFirstCursor>
void dot(DFA_dot &output_stream, DFirstCursor x, DFirstCursor y = DFirstCursor())
{
  output_stream.out << "digraph G {" << endl;
  output_stream.graph_attributes();
  DFA_dot::State i = clone(output_stream, x, y);
  if (output_stream.initial() && i != output_stream.null_state)
    output_stream.out << i << " [shape=doublecircle];" << endl;
  output_stream.out << "}" << endl;
}
    
#endif // ASTL_DOT_ALGORITHM



