/*******************************************************************\

Module: AND-Inverter Graph

Author: Daniel Kroening, kroening@cs.cmu.edu

\*******************************************************************/

#ifndef CPROVER_PROPDEC_AND_GRAPH_H
#define CPROVER_PROPDEC_AND_GRAPH_H

#include <vector>
#include <set>
#include <map>

#include "propdec/prop.h"

class and_graph_nodet
{
public:
  bool is_and;
  literalt a, b;
  
  and_graph_nodet():is_and(false)
  {
    a.clear();
    b.clear();
  }
  
  void make_and(literalt _a, literalt _b)
  {
    is_and=true;
    a=_a;
    b=_b;
  }
};

class and_grapht
{
public:
  and_grapht()
  {
    clear();
  }
  
  virtual ~and_grapht()
  {
  }
  
  void clear()
  {
    _const_0.set(0);
    _const_1.set(1);
    nodes.resize(1);
  }

  typedef std::set<unsigned> terminal_sett;
  typedef std::map<unsigned, terminal_sett> terminalst;

  void get_terminals(terminalst &terminals) const;

  void print(std::ostream& out, literalt a) const;
  
  const and_graph_nodet &get_node(literalt l) const
  {
    return nodes[l.var_no()];
  }
  
  const and_graph_nodet &get_node(unsigned v) const
  {
    return nodes[v];
  }
  
  and_graph_nodet &get_node(literalt l)
  {
    return nodes[l.var_no()];
  }
  
  and_graph_nodet &get_node(unsigned v)
  {
    return nodes[v];
  }
  
  unsigned number_of_nodes() const
  {
    return nodes.size();
  }
  
  void print(std::ostream &out) const;
  
  void swap(and_grapht &g)
  {
    _const_0.swap(g._const_0);
    _const_1.swap(g._const_1);
    nodes.swap(g.nodes);
  }
  
  literalt new_node()
  {
    nodes.push_back(and_graph_nodet());
    literalt l;
    l.set(nodes.size()-1, false);
    return l;
  }
  
  virtual void output_dot_node(std::ostream &out, unsigned v) const;
  virtual std::string dot_node_label(unsigned v) const;
  virtual void output_dot(std::ostream &out) const;
  
protected:  
  typedef std::vector<and_graph_nodet> nodest;
  nodest nodes;

  literalt _const_0, _const_1;

  const std::set<unsigned> &get_terminals_rec(
    unsigned n,
    terminalst &terminals) const;
};

std::ostream &operator << (std::ostream &, const and_grapht &);

#endif
