#ifndef __Node_h__
#define __Node_h__


#include <list>
#include <map>
#include <hash_map>
#include <iostream>
using namespace std;

class Node;
struct hashF;
struct eqPofN;

const int TERM_VAR_ID = -1;


/******************************************************************************/
/* --- pomocná struktura pro Mapa_apply --- */
/* --- obsahuje dvijice uzlù --- */
class pair_of_nodes{
  public:
  Node * u1;
  Node * u2;
  pair_of_nodes(Node * first,Node * second): u1(first),u2(second){}

 };

/******************************************************************************/
/* --- pomocná funkce pro hashovaci funkce --- */
/* --- bezkolizni funkce --- */

  unsigned int pairF(unsigned int i, unsigned int j)
{
  return (((i+j)*(i+j+1))/2)+i  ;

}
/******************************************************************************/


// definice typu pro zretezeny seznam ukazatelu na uzel
typedef list<Node*> NodeList;
// definice typu pro tabulku pri kopirovani BDD
typedef map<Node*,Node*> Mapa_uzlu;
// definice typu pro tabulku pri funkci apply na BDD
typedef hash_map<const pair_of_nodes, Node *, hashF,eqPofN> Mapa_apply;



class Node {
friend class BDD;
friend class PLAtab;


protected:
   static unsigned int idCount;
   Node * Low;
   Node * High;
   unsigned int varId;
   unsigned int nodeId;
   NodeList parentList;

public:
         Node();
         Node(int vid, Node * l=NULL, Node * h=NULL);

  void bypass(Node * child, Node * newNode);
  unsigned int getId(){ return nodeId; } // vraci nodeId uzlu

  virtual int getValue(){ return -1; }   // vraci -1 u neterminalu, a value u terminalu
  virtual bool isTerminal(){ return false; }
  virtual ostream& printInfo(ostream & out)const;

  ostream& recurs_print(ostream & out);

 friend Node * applyOp(Node * first, Node * second, BDD & diagram,Mapa_apply * map,int (*func_op)(Node *,Node *));
 friend Node * rec_copy(Node * src,BDD * diagram, Mapa_uzlu * mapa);
 friend ostream& operator<<(ostream & out,const Node & n);
};


/******************************************************************************/
/* --- funkce pro porovnani dvou pair_of_nodes --- */
/* --- porovnava jejich nodeId --- */

struct eqPofN
{
  bool operator()(const pair_of_nodes p1, const pair_of_nodes p2) const
  {
    return (p1.u1->getId() == p2.u1->getId()) && (p1.u2->getId() == p2.u2->getId()) ;
  }
};
/******************************************************************************/
/* --- hashovaci funkce pro hashovaci tabulku Mapa_apply --- */

struct hashF {
unsigned int operator()(const pair_of_nodes & first)
{
  return pairF(first.u1->getId(),first.u2->getId()) % 15485863;
}
};




#endif
