#include <global.hpp>

#include <cairo/cairo.h>
#include <cairo-ps.h>
#include <pango/pangocairo.h>
#include <glib.h>
#include <cairo_t_singleton.hpp>


#include <interfacce.hpp>
#include <legame.hpp>
#include <etichetta.hpp>
#include <atomo.hpp>
#include <procedura.hpp>
#include <multiline_label.hpp>
#include <multifont_label.hpp>
#include <paragraph_text.hpp>
#include <gruppo.hpp>

#include <substructure_search.hpp>


using namespace substructure_search;

residual_DFS::residual_DFS(){
  clean_to_start();
}

residual_DFS::residual_DFS(gruppo& ref)
  :_molecule(ref)

{
  clean_to_start();

}


bool residual_DFS::is_black(atomo* a){
  int res=0;
  if(a!=NULL){
    if(_blacks.count(a)>0){
      res=1;
    }
  }

  return res;
}

bool residual_DFS::is_gray(atomo* a){
  int res=0;

  if(a!=NULL){
    if(_grays.count(a)>0){
      res=1;
    }
  }

  return res;
}


residual_DFS::~residual_DFS(){

}

void residual_DFS::clean_to_start(){
  while(!_stack_atoms.empty()){
    _stack_atoms.pop();
  }
  
  while(!_parents.empty()){
    _parents.pop();
  }
   
  while(!_history.empty()){
      _history.pop();
  }

  while(!_bond_type.empty()){
      _bond_type.pop();
  }

  while(!_no_children.empty()){
    _no_children.pop();
  }


  while(!_curr_action.empty()){
    _curr_action.pop();
  }

  _grays.clear();

  _blacks.clear();

}





bool residual_DFS::DFS_find_descend_forced(atomo* parent, atomo* child){
  node_status nw;
  bool is_cycle=false;
  bool had_children_not_black=false;
  bool found=false;

  nw._parent_node=parent;
  if(is_gray(parent)){
    nw._lastcolor=GRAY;
  }else if(is_black(parent)){
    nw._lastcolor=BLACK;
  }else{
    nw._lastcolor=WHITE;
  }

  vector<legame>::iterator sub_first=parent->primo_leg();
  vector<legame>::iterator sub_last=parent->ultimo_leg();
  atomo* child_found=0;
  while(sub_first!=sub_last){
    child_found=_molecule.find_atomo_id((*sub_first).id_atomo());  

    if(child_found==child){
      found=true;
    }
    if( found &&
        (_blacks.count(child)==0) ){

      if(is_gray(child)){
        is_cycle=true;
      }
        
      had_children_not_black=true;
      _grays[child]=true;
      _stack_atoms.push(child);
      _bond_type.push((*sub_first).tipo_legame());
      _no_children.push(child->bond_number());
      _parents.push(parent);
      if(is_cycle){
        _curr_action.push(DESCEND_NORMAL_CYCLE);
        nw._action=DESCEND_NORMAL_CYCLE;
        nw._node=child;
      }else{
        _curr_action.push(DESCEND_NORMAL);
        nw._action=DESCEND_NORMAL;
        nw._node=child;
      }
      break;
    }	
    sub_first++;
  }

  if(found && (_blacks.count(child)==0)){
    
    DFS_manage_node_no_white_nodes(had_children_not_black,
                                   is_cycle,
                                   parent, 
                                   child , 
                                   nw);

      
    _history.push(nw);
  }
  //nw._node=child;
  return found && (_blacks.count(child)==0);
}

void residual_DFS::DFS_find_and_descend(atomo* parent, node_status& nw){
  bool is_cycle=false;
  bool had_children_not_black=false;
  
  vector<legame>::iterator sub_first=parent->primo_leg();
  vector<legame>::iterator sub_last=parent->ultimo_leg();
  atomo* child=0;
  while(sub_first!=sub_last){
    child=_molecule.find_atomo_id((*sub_first).id_atomo());  
    if( (_blacks.count(child)==0) && 
        (_parents.size()==0 || _parents.top()->id()!=child->id())){
      if(is_gray(child)){
        is_cycle=true;
      }

      had_children_not_black=true;
      _grays[child]=true;
      _stack_atoms.push(child);
      _bond_type.push((*sub_first).tipo_legame());
      _no_children.push(child->bond_number());
      _parents.push(parent);
      if(is_cycle){
        _curr_action.push(DESCEND_NORMAL_CYCLE);
        nw._action=DESCEND_NORMAL_CYCLE;
      }else{
        _curr_action.push(DESCEND_NORMAL);
        nw._action=DESCEND_NORMAL;
      }
      break;
    }	
    sub_first++;
  }


  DFS_manage_node_no_white_nodes(had_children_not_black,
                                 is_cycle, 
                                 parent, child, nw);

}




void residual_DFS::DFS_manage_node_no_white_nodes(bool had_children_not_black,
                                                  bool is_cycle,
                                                  atomo* parent, 
                                                  atomo* child , 
                                                  node_status& nw){

  vector<legame>::iterator sub_first=parent->primo_leg();
  vector<legame>::iterator sub_last=parent->ultimo_leg();
  
  bool all_black_or_gray=true;
  while(sub_first!=sub_last){
    atomo* c2=_molecule.find_atomo_id((*sub_first).id_atomo());
    if(!is_gray(c2) && !is_black(c2)){
      all_black_or_gray=false;
    }
    sub_first++;
  }


  if(all_black_or_gray){
    /*
      std::cerr << "tutti i figli sono grigi o neri setto" 
      << curr->id() << " black ";
    */
    _grays.erase(parent);
    _blacks[parent]=true;
    nw._currcolor=BLACK;
    if(had_children_not_black){
      if(is_cycle){
        _curr_action.push(DESCEND_SET_BLACK_PARENT_CYCLE);
        nw._action=DESCEND_SET_BLACK_PARENT_CYCLE;
      }else{
        _curr_action.push(DESCEND_SET_BLACK_PARENT);
        nw._action=DESCEND_SET_BLACK_PARENT;
      }
      nw._node=child;
    }else{
      if(is_cycle){
        _curr_action.push(SET_BLACK_CURR_CYCLE);
        nw._action=SET_BLACK_CURR_CYCLE; //will never happens isn'it?
        nw._parent_node=child;
        nw._node=parent;
      }else{
        _curr_action.push(SET_BLACK_CURR);
        nw._action=SET_BLACK_CURR;
        nw._parent_node=child;
        nw._node=parent;
      }
    }
  }else{
    nw._node=child;
    nw._currcolor=nw._lastcolor;
  }
}



bool residual_DFS::DFS_simulate_shift_descendant(atomo** res){
  dump_history();
  dump();
  bool found=false;
  atomo* parent=parent_atom();
  atomo* old_child=curr_atom();

  
  //std::cerr << "############################################" << std::endl;
  DFS_pop_current_atom(false,false);
  atomo* gran_parent=parent_atom();
  //dump_history();
  //dump();
  /*   gparent ---- parent ---- child */
  //std::cerr << "@@@@@@@@@@@@@@@@@@@@"<< std::endl;
  if( (gran_parent!=NULL && parent!=NULL)){

    found=DFS_simulate_shift_descendant_w_gparent(res,gran_parent,
                                                  parent, old_child);
    DFS_find_descend_forced(parent,old_child);
  }else if(gran_parent==NULL && parent!=NULL){ 

    found=DFS_simulate_shift_descendant_no_gparent(res,parent, 
                                                   old_child);
    DFS_find_descend_forced(parent,old_child);
  }else if(gran_parent==NULL && parent==NULL){  //we are at the starting point!
    int start=old_child->id();
    DFS_step(&start);
  }

  return found;
}


bool residual_DFS::DFS_simulate_shift_descendant_w_gparent(atomo** res, atomo* gparent,
                                                           atomo* parent, atomo* old_child){
  

  /*   gparent ----> parent ----> child */
  bool found=false;
  atomo* nw_child=NULL;
  vector<legame>::iterator sub_first=parent->primo_leg();
  vector<legame>::iterator sub_last=parent->ultimo_leg();
  while(sub_first!=sub_last){  
    nw_child=_molecule.find_atomo_id((*sub_first).id_atomo());
    if(nw_child->id()!=old_child->id() &&
       (_blacks.count(nw_child)==0) && 
       (gparent->id()!=nw_child->id()) ){
      found=true;
      *res=nw_child;
      break;
    }
    sub_first++;
  }
  

  return found; 
}


bool residual_DFS::DFS_simulate_shift_descendant_no_gparent(atomo** res, atomo* parent, 
                                                            atomo* old_child){



  /*   gparent ----> parent ----> child */
  bool found=false;
  atomo* nw_child=NULL;
  vector<legame>::iterator sub_first=parent->primo_leg();
  vector<legame>::iterator sub_last=parent->ultimo_leg();
  while(sub_first!=sub_last){  
    nw_child=_molecule.find_atomo_id((*sub_first).id_atomo());
    if(nw_child->id()!=old_child->id() &&
       (_blacks.count(nw_child)==0)){
      found=true;
      *res=nw_child;
      break;
    }
    sub_first++;
  }
  

  return found; 
}


bool residual_DFS::DFS_shift_descendant(bool leave_black){
  bool found=false;
  // std:: cerr << "]]]]]]]]]" << std::endl;
  //   dump();
  
  //   std:: cerr << "]]]]]]]]]" << std::endl;

  atomo* curr_child=curr_atom();
  DFS_pop_current_atom(leave_black,false);

  //   std:: cerr << "[[[[[[[[[[[[[[" << std::endl;
  //   dump();
  //   std:: cerr << "[[[[[[[[[[[[[[" << std::endl;
  //   std::cerr << __FUNCTION__ << " genitore " <<curr_atom()->id()
  //             << endl;

  atomo* nw_child=NULL;
  vector<legame>::iterator sub_first=curr_atom()->primo_leg();
  vector<legame>::iterator sub_last=curr_atom()->ultimo_leg();
  while(sub_first!=sub_last){  
    nw_child=_molecule.find_atomo_id((*sub_first).id_atomo());
    if(nw_child->id()!=curr_child->id() &&
       (_blacks.count(nw_child)==0) && 
       (_parents.size()==0 || _parents.top()->id()!=nw_child->id()) ){
      found=true;
      break;
    }
    sub_first++;
  }
  
  //  std::cerr << __FUNCTION__ << " nuovo figlio " << nw_child->id()
  //          << endl;

  DFS_find_descend_forced(curr_atom(),nw_child);

  return found;
}

void residual_DFS::DFS_delete_terminal(atomo* at,node_status& nw,bool keep_in_history){
  _stack_atoms.pop();
  _bond_type.pop();
  _no_children.pop();
  _parents.pop();
  
  _curr_action.push(DELETE_TERMINAL);
  nw._action=DELETE_TERMINAL;
  nw._currcolor=BLACK;
  nw._parent_node=at;
  nw._node=at;

  if(keep_in_history){
    _history.push(nw);
  }

}

void residual_DFS::DFS_step(int* start){
  if(start!=NULL){
    clean_to_start();
    _stack_atoms.push(_molecule.find_atomo_id(*start));
    _curr_action.push(NONE);
    _grays[_molecule.find_atomo_id(*start)]=true;
    node_status nw;
    nw._parent_node=_molecule.find_atomo_id(*start);
    nw._node=_molecule.find_atomo_id(*start);
    nw._lastcolor=WHITE;
    nw._currcolor=GRAY;
    _history.push(nw);
  }else{
    if(!_stack_atoms.empty()){
      atomo* curr=_stack_atoms.top();
      //std::cerr << "top " << curr->id() << " \n" ;
      node_status nw;
      nw._parent_node=curr;
      if(is_gray(curr)){
        nw._lastcolor=GRAY;
      }else if(is_black(curr)){
        nw._lastcolor=BLACK;
      }else{
        nw._lastcolor=WHITE;
      }
      if(_blacks.count(curr)==0){
        DFS_find_and_descend(curr,nw);                

      }else{
        DFS_delete_terminal(_stack_atoms.top(), nw,false);
      }
      _history.push(nw);
    }
  }

}

bool residual_DFS::DFS_set_black_current(atomo* candidate){
  vector<legame>::iterator sub_first=candidate->primo_leg();
  vector<legame>::iterator sub_last=candidate->ultimo_leg();
  atomo* child=0;
  bool had_children_not_black=false;
  while(sub_first!=sub_last){
    //dump_blacks();
    child=_molecule.find_atomo_id((*sub_first).id_atomo());  
    if( ! ( is_gray(child) || is_black(child) ) ){ 
      //std::cerr << "attenzione!!!! " <<  child->id() << " " << child << std::endl;
      had_children_not_black=true;
      break;
    }
    sub_first++;
  }

  if(!had_children_not_black){
    _grays.erase(candidate);
    _blacks[candidate]=true;
  }

  return !had_children_not_black;

}

void residual_DFS::DFS_force_black_current(bool keep_track){
  node_status nw;
  nw._node=curr_atom();
  nw._parent_node=parent_atom();  
  nw._lastcolor=BLACK;
  nw._currcolor=BLACK;
  nw._action=FORCE_BLACK_CURRENT;
  _blacks[curr_atom()]=true;
  _grays.erase(curr_atom());
  //std::cerr << "setto black " << curr_atom()->id() << std::endl;
  _curr_action.push(FORCE_BLACK_CURRENT);
  if(keep_track){
    _history.push(nw);
  }
}



void residual_DFS::DFS_force_black_parent(bool keep_track){
  node_status nw;
  nw._node=curr_atom();
  nw._parent_node=parent_atom();  
  nw._lastcolor=get_color(parent_atom());
  nw._currcolor=BLACK;
  nw._action=FORCE_BLACK_PARENT;
  _blacks[parent_atom()]=true;
  _grays.erase(parent_atom());
  //std::cerr << "setto black " << curr_atom()->id() << std::endl;
  _curr_action.push(FORCE_BLACK_PARENT);
  if(keep_track){
    _history.push(nw);
  }
}


colornode residual_DFS::get_color(atomo* atm){
  colornode res=WHITE;
  if(is_black(atm)){
    res=BLACK;
  }else if(is_gray(atm)){
    res=GRAY;
  }
  return res;
}

bool residual_DFS::DFS_pop_current_atom(bool leave_it_black, bool keep_in_history){
  node_status nw;
  bool has_more=false;
  if(!_stack_atoms.empty()){
    has_more=true;
    atomo* last=curr_atom();
    std::stack<node_status> last_st;
    last_st.push(_history.back());
    nw._node=curr_atom();
    nw._parent_node=parent_atom();
    if(last_st.top()._action==SET_BLACK_CURR_CYCLE ||
       last_st.top()._action==SET_BLACK_CURR){
      std::queue<node_status> q_saved=_history;
      while(q_saved.size()>2){
        q_saved.pop();
      }

      last_st.push(q_saved.front());
      backstep();
      backstep();
 
    }else{
      has_more=backstep();

    }

    if(has_more){

      if(leave_it_black){
        //std::cerr << __FUNCTION__ << " setto black " << last->id() << std::endl;
        _blacks[last]=true;
        _grays.erase(last);
        nw._action=POP_CURRENT_ATOM_LEAVE_BLACK;
        _curr_action.push(POP_CURRENT_ATOM_LEAVE_BLACK);
      }else{
        nw._action=POP_CURRENT_ATOM;
        _curr_action.push(POP_CURRENT_ATOM);
      }

      if(keep_in_history){      
        while(!last_st.empty()){
          _history.push(last_st.top());
          last_st.pop();
        }
        _history.push(nw);
      }
    }
  }

  return has_more;
}

action residual_DFS::curr_action(){
  return _curr_action.top();
}

int residual_DFS::bond_type(){
  return _bond_type.top();
}

int residual_DFS::no_children(){
  return _no_children.top();
}

atomo* residual_DFS::curr_atom(){
  if(_stack_atoms.empty()){
    return NULL;
  }else{
    return _stack_atoms.top();
  }
}

atomo* residual_DFS::parent_atom(){
  atomo* res=NULL;
  if(_stack_atoms.size()>1){
    std::stack<atomo*> saved=_stack_atoms;
    _stack_atoms.pop();
    
    res= _stack_atoms.top();
    _stack_atoms=saved;
  }
  return res;
}


bool residual_DFS::DFS_is_finished(){
  std::stack<atomo*> tmp=_stack_atoms;
  bool res=true;
  while(!tmp.empty()){
    if( !is_black(tmp.top())){
      res=false;
      break;
    }
    tmp.pop();
  }

  return res;
}


bool residual_DFS::backstep(){
  //std::cerr << "********************** indietro! "
  //          << _history.size()  << " ***************" << std::endl;
  bool has_more=false;
  if(!_history.empty()){
    has_more=true;
    int count=_history.size()-1;
    if(count==0){
      count=1;
      has_more=false;
    }
    std::queue<node_status> copy_hist=_history;
    atomo* start=NULL;

    while(!_stack_atoms.empty()){
      start=_stack_atoms.top();
      _stack_atoms.pop();
    }

    int id_start=start->id();
    DFS_step(&id_start);

    for(int i=0;i<count;i++){
      node_status st=copy_hist.front();
      copy_hist.pop();
      switch (st._action){
      case NONE:
        {
          int start=st._node->id();
          DFS_step(&start);        
        }
        break;
      case FORCE_BLACK_PARENT:
        assert(st._parent_node==parent_atom());
        DFS_force_black_parent();
        break;
      case FORCE_BLACK_CURRENT:
        assert(st._node==curr_atom());
        DFS_force_black_current();
        break;
      case POP_CURRENT_ATOM_LEAVE_BLACK:
        DFS_pop_current_atom(true);
        break;
      case POP_CURRENT_ATOM:
        DFS_pop_current_atom(false);
        break;
      case DELETE_TERMINAL:
        //std::cerr << "cancellerei " << st._node->id() << std::endl;
        //dump_blacks();
        assert(_stack_atoms.top() == st._node);
        assert(is_black(st._node));
        
        DFS_delete_terminal(_stack_atoms.top() , st,true);
        break;
      case SET_BLACK_CURR:
        DFS_set_black_current(st._node);
        _history.push(st);
        break;
      case DESCEND_FORCE_SET_BLACK_PARENT:
        DFS_descend_force_set_black_parent(st._parent_node,
                                           st._node,
                                           true);
        break;
      case DESCEND_FORCE_SET_BLACK_PARENT_CYCLE:
        assert(is_gray(st._node));
        DFS_descend_force_set_black_parent_cycle(st._parent_node,
                                                 st._node,
                                                 true);
        break;
      case DESCEND_SET_BLACK_PARENT:
        //std::cerr << "\t\tDESCEND_SET_BLACK_PARENT prima" << std::endl;
        // dump_blacks();
        //         std::cerr << "crtitico da: " <<  st._parent_node->id() 
        //                   << " " << st._node->id() << std::endl;

        DFS_find_descend_forced(st._parent_node, st._node);
//         std::cerr << "\t\tDESCEND_SET_BLACK_PARENT dopo" << std::endl;
//         dump_blacks();
        break;
      case DESCEND_SET_BLACK_PARENT_CYCLE:
        assert(is_gray(st._node));
        DFS_find_descend_forced(st._parent_node, st._node);
        break;
      default:
        DFS_find_descend_forced(st._parent_node, st._node);
        break;
      }

      /*      
      action ca=curr_action();

      if(ca==DESCEND_NORMAL){
        std::cerr << "\tDESCEND_NORMAL" << std::endl;
        std::cerr << "partendo da : " << parent_atom()->id() 
                  << " scenderei in " << curr_atom()->id() 
                  << " proveniente da un legame " 
                  << bond_type()
                  << " e " << no_children() << " figli " 
                  << std::endl;
      }else if(ca==DESCEND_TERMINAL){
        std::cerr << "\tDESCEND_TERMINAL" << std::endl;
        std::cerr << "partendo da : " << parent_atom()->id() 
                  << " scenderei in " << curr_atom()->id()  
                  << " proveniente da un legame " 
                  << bond_type()
                  << " e " << no_children() << " figli " 
                  << " questo verra' eliminato "
                  << std::endl;
      }else if(ca==DELETE_TERMINAL){
        std::cerr << "\t DELETE_TERMINAL" << std::endl;
        std::cerr << " eliminato precedente " << std::endl;
      }else if(ca==DESCEND_NORMAL_CYCLE){
        std::cerr << "\t DESCEND_NORMAL_CYCLE" << std::endl;
        std::cerr << "ciclo!! partendo da : " << parent_atom()->id() 
                  << " scenderei in " << curr_atom()->id() 
                  << " proveniente da un legame " 
                  << bond_type()
                  << " e " << no_children() << " figli " 
                  << std::endl;
        
        std::cerr << "\tformano un ciclo" << std::endl;
           
      }else if(ca==SET_BLACK_CURR_CYCLE){
        std::cerr << "\t SET_BLACK_CURR_CYCLE" << std::endl;
        std::cerr << curr_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
        std::cerr << "\te chiude un ciclo" << std::endl;
        
      }else  if(ca==SET_BLACK_CURR){
        std::cerr << "\t SET_BLACK_CURR" << std::endl;
        std::cerr << curr_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
      }else  if(ca==DESCEND_SET_BLACK_PARENT_CYCLE){
        std::cerr << "\t DESCEND_SET_BLACK_PARENT_CYCLE" << std::endl;
        std::cerr << "partendo da : " << parent_atom()->id() 
                  << " scenderei in " << curr_atom()->id() 
                  << " proveniente da un legame " 
                  << bond_type()
                  << " e " << no_children() << " figli " 
                  << std::endl;
        std::cerr << parent_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
        std::cerr << "\te chiude un ciclo" << std::endl;
        
      }else  if(ca==DESCEND_SET_BLACK_PARENT){
        std::cerr << "\t DESCEND_SET_BLACK_PARENT" << std::endl;
        std::cerr << "partendo da : " << parent_atom()->id() 
                  << " scenderei in " << curr_atom()->id() 
                  << " proveniente da un legame " 
                  << bond_type()
                  << " e " << no_children() << " figli " 
                  << std::endl;
        std::cerr << parent_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
      
      }else if(ca==FORCE_BLACK_CURRENT){
        std::cerr << "\tFORCE_BLACK_CURRENT" << std::endl;
        std::cerr << "forzo " << curr_atom()->id() 
                  << " black" << std::endl;
      }
      */
    }
   
  }
  return has_more;
}



void residual_DFS::DFS_descend_force_set_black_parent_cycle(atomo* parent, 
                                                            atomo* child,
                                                            bool keep_track){
  
  node_status nw;
  bool found_not_black=DFS_find_descend_forced(parent, child);
  if(found_not_black && 
     pop_back_history(nw) && 
     is_gray(curr_atom())){
    DFS_force_black_parent(false);
    if(keep_track){
      nw._action=DESCEND_FORCE_SET_BLACK_PARENT_CYCLE;
      _history.push(nw);
    }
  }


}

void residual_DFS::DFS_descend_force_set_black_parent(atomo* parent,
                                                      atomo* child,
                                                      bool keep_track){
  
  node_status nw;
  DFS_find_descend_forced(parent, child);
  if(pop_back_history(nw)){
    DFS_force_black_parent(false);
    if(keep_track){
      nw._action=DESCEND_FORCE_SET_BLACK_PARENT;
      _history.push(nw);
    }
  }

}

bool residual_DFS::pop_back_history(node_status& popped){
  std::queue<node_status> nw;
  bool res=false;

  while(!_history.empty() && _history.size()>1){
    res=true;
    nw.push(_history.front());
    _history.pop();
  }
  
  if(res){
    popped=_history.front();
    _history=nw;
  }

  return res;

}

void residual_DFS::dump(){
  std::stack<atomo*> tmp=_stack_atoms;
  while(!tmp.empty()){
    std::cerr << tmp.top() << " id= "
              << tmp.top()->id();

    if(is_black(tmp.top())){
      std::cerr << " BLACK ";
    }else     if(is_gray(tmp.top())){
      std::cerr << " gray ";
    }else{
      std::cerr << " white ";
    }
    std::cerr << std::endl;
    tmp.pop();
  }

}

void residual_DFS::dump_history(){
  dump_any_history(_history);
}


void residual_DFS::dump_any_history(std::queue<node_status> tmp){
  while(!tmp.empty()){
    std::cerr << "node: " << tmp.front()._node->id() << " "
              << "parentnode: " << tmp.front()._parent_node->id() << " "
              << "curcolor: " << colornode2string(tmp.front()._currcolor) << " "
              << "lastcolor: " << colornode2string(tmp.front()._lastcolor) << " "
              << "act: " << action2string(tmp.front()._action) 
              << std::endl;
    tmp.pop();
  }

  
}


void residual_DFS::dump_blacks(){
  std::map<atomo*,bool>::iterator iter;   
  for( iter = _blacks.begin(); iter != _blacks.end(); iter++ ) {
    std::cerr << "id: " << iter->first->id() << " address=" 
              << iter->first << " value:"
              << iter->second << endl;
  }

}


atomo* residual_DFS::get_starting_point(){
  atomo* res=NULL;
  if(!_stack_atoms.empty()){
    std::stack<atomo*> saved=_stack_atoms;
    while(_stack_atoms.size()>1){
      _stack_atoms.pop();
    }
    
    assert(_stack_atoms.size()==1);
    res=_stack_atoms.top();
    
    _stack_atoms=saved;
  }
  return res;

}

bool residual_DFS::is_starting_point(atomo* chkd){
  return get_starting_point()==chkd;
}


std::vector<atomo*> residual_DFS::dump_atoms_from_molecule(){
  std::vector<atomo*> res;
  vector<atomo>::iterator first=_molecule.iniz_atom();
  vector<atomo>::iterator last=_molecule.fin_atom();

  while(first!=last){
    atomo* a=_molecule.find_atomo_id((*first).id());
    res.push_back(a);
    first++;
  }

  return res;
}

std::string residual_DFS::colornode2string(colornode c){
  std::string res="";

  if(c==WHITE){
    res="white";
  }else if(c==GRAY){
    res="gray";
  }else if(c==BLACK){
    res="BLACK";
  }
              
  return res;
}


std::string residual_DFS::action2string(action a){
  std::string res="";
  if(a == NONE){ 
    res="NONE";
  }else if(a == DESCEND_NORMAL){ 
    res="DESCEND_NORMAL";
  }else if(a == DESCEND_TERMINAL){
    res="DESCEND_TERMINAL";
  }else if(a == DESCEND_NORMAL_CYCLE){
    res="DESCEND_NORMAL_CYCLE";
  }else if(a==  DESCEND_TERMINAL_CYCLE){
    res="DESCEND_TERMINAL_CYCLE";
  }else if(a==  SET_BLACK_CURR_CYCLE){
    res="SET_BLACK_CURR_CYCLE";
  }else if(a==  SET_BLACK_CURR){
    res="SET_BLACK_CURR";
  }else if(a==  DESCEND_SET_BLACK_PARENT_CYCLE){
    res="DESCEND_SET_BLACK_PARENT_CYCLE";
  }else if(a==  DESCEND_SET_BLACK_PARENT){
    res="DESCEND_SET_BLACK_PARENT";
  }else if(a==  DELETE_TERMINAL){
    res="DELETE_TERMINAL";
  }else if(a== FORCE_BLACK_CURRENT){
    res="FORCE_BLACK_CURRENT";
  }else if(a== FORCE_BLACK_PARENT){
    res="FORCE_BLACK_PARENT";
  }else if(a== FORCE_SHIFT_CHILD){
    res="FORCE_SHIFT_CHILD";
  }else if(a==POP_CURRENT_ATOM){
    res="POP_CURRENT_ATOM";
  }else if(a==POP_CURRENT_ATOM_LEAVE_BLACK){
    res="POP_CURRENT_ATOM_LEAVE_BLACK";
  }else if(a==DESCEND_FORCE_SET_BLACK_PARENT_CYCLE){
    res="DESCEND_FORCE_SET_BLACK_PARENT_CYCLE";
  }else if(a==DESCEND_FORCE_SET_BLACK_PARENT){
    res="DESCEND_FORCE_SET_BLACK_PARENT";
  }



              
  return res;
}


gruppo residual_DFS::get_copy_gruppo(){
  return _molecule;
}


gruppo* residual_DFS::get_pointer_gruppo(){
  return &_molecule;
}


/*************************************************/



molecule_matching::molecule_matching(gruppo& mol, gruppo& sub)
  :_sub(sub),
   _mol(mol)
{
  
}

molecule_matching::~molecule_matching(){

}


void molecule_matching::clean(){
  _sub.clean_to_start();
  _mol.clean_to_start();
}


bool molecule_matching::match(){
  //return TEST_DFS_forced();
  bool result=false;
  std::vector<atomo*> starting_points_sub=_sub.dump_atoms_from_molecule();
  std::vector<atomo*> starting_points_mol=_mol.dump_atoms_from_molecule();
  /*
  for(unsigned int i=0;i<starting_points_sub.size();i++){
    std::cerr << starting_points_sub[i] << " " << i << ",";
  }
  
  std::cerr  << std::endl;

  for(unsigned int i2=0;i2<starting_points_mol.size();i2++){
    std::cerr << starting_points_mol[i2] << " " << i2 << "," ;
  }
  
  std::cerr  << std::endl;
  */
  //at least on atome for each groups
  if(starting_points_sub.size()>0 && 
     starting_points_mol.size()>0 ){
    //for each atom in searched substructure
    for(unsigned int ct_st_points_sub=0;
        ct_st_points_sub<starting_points_sub.size();
        ct_st_points_sub++){
      clean();
      int starting=static_cast<int>(starting_points_sub[ct_st_points_sub]->id());
      //initialize DFS for substructure
      _sub.DFS_step(&starting);
      //for each starting point
      for(unsigned int ct_st_points_mol=0;
          ct_st_points_mol<starting_points_mol.size();
          ct_st_points_mol++){
        starting=static_cast<int>(starting_points_mol[ct_st_points_mol]->id());
        //initialize DFS for molecule
        _mol.DFS_step(&starting);
        //check if the starting point has equal (i.e. same label)
          if(good_starting_point(_sub.curr_atom(),_mol.curr_atom())){
            //start DFS
            bool break_main=false;
            while(!_sub.DFS_is_finished()){
              std::cerr << "\t\tSTART ITERATION" << std::endl;
              _sub.DFS_step();

              std::cerr << "------------ SUB ---------------" << std::endl;
              debug_print_DFS(_sub);
              _sub.dump();
              _sub.dump_history();
              std::cerr << "------------ FINE SUB ---------------\n" << std::endl;
              if(!main_descend(false)){
                break_main=true;
                break;
              }
              
            }
            //std::cerr << "OOOOKKK" << std::endl;
            if(!break_main){
              return true;
            }
            
          }
      } // end for(unsigned int ct_st_points_mol=0;
     
    } // end for(unsigned int ct_st_points_sub=0;
    return false; 
  }

  return result;
}



bool molecule_matching::main_descend(bool use_reds){
  bool res=false;
  action curr_action=_sub.curr_action();
  std::cerr << "------------ MOL ---------------" << std::endl;
  std::cerr << " \t\taction wished " << residual_DFS::action2string(curr_action) << std::endl;
  switch(curr_action){
  case DESCEND_NORMAL:
    if(find_normal_candidate(use_reds)){
      res=true;
    }else{
      if(find_alternative_path()){
        std::cerr << "\t\tsearch alternative OK!" << std::endl;
        res=true;
      }else{
        std::cerr << "\t\tsearch alternative failed" << std::endl;
        res=false;
      }
    }
    debug_print_all(_mol);

    break;
  case DESCEND_TERMINAL:
    break;
  case DELETE_TERMINAL:
    {
      node_status st;
      assert(_mol.is_black(_mol.curr_atom()));
      _mol.DFS_delete_terminal(_mol.curr_atom(), st, true);
      _mol_reds.clear();
      res=true;

      debug_print_all(_mol);
      

    }
    break;
  case DESCEND_NORMAL_CYCLE:
    break;
  case SET_BLACK_CURR_CYCLE:
    break;
  case SET_BLACK_CURR:
    _mol.DFS_force_black_current();
    res=true;

    debug_print_all(_mol);
    break;
  case DESCEND_SET_BLACK_PARENT_CYCLE:

    if(find_set_black_parent_cycle_candidate(use_reds)){
      res=true;
      debug_print_all(_mol);
      _mol.dump_blacks();
      
    }else{
      if(find_alternative_path()){
        std::cerr << "\t\tsearch alternative OK!" << std::endl;
        res=true;
        debug_print_all(_mol);
        _mol.dump_blacks();
      }else{
        std::cerr << "\t\tsearch alternative failed" << std::endl;
        res=false;
        debug_print_all(_mol);
        _mol.dump_blacks();
      }
    }

    break;
  case DESCEND_SET_BLACK_PARENT:
    std::cerr << "\t\tDESCEND_SET_BLACK_PARENT STARTTTT!"  << std::endl;
    //debug_print_all(_mol);
    //std::cerr << "¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹" << std::endl;

    if(find_set_black_parent_candidate(use_reds)){
      res=true;
      debug_print_all(_mol);
      _mol.dump_blacks();
      
    }else{
       std::cerr << "DESCEND_SET_BLACK_PARENT no candidate!" 
                 << std::endl;
       std::cerr << "search alternative\n\t\tstart dump" << std::endl;
//       debug_print_all(_mol);
//       std::cerr << "°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°" << std::endl;

      if(find_alternative_path()){
        std::cerr << "\t\tsearch alternative OK!" << std::endl;
        res=true;
        debug_print_all(_mol);
        _mol.dump_blacks();
      }else{
        std::cerr << "\t\tsearch alternative failed" << std::endl;
        res=false;
        debug_print_all(_mol);
        _mol.dump_blacks();
      }
    }
    break;
  default:
    assert(false);
    break;
                
  }

  return res;

}


bool molecule_matching::find_alternative_path(){

  block_path(_mol.curr_atom());
  bool mol_res=go_back_to_parent(_mol);


  
//   std::cerr << "################## MOL ################################" << std::endl;
//   std::cerr << "# ";
//   _mol.dump_history();
  
//   _mol.dump();
//   std::cerr << "                                                 #" << std::endl;
//   std::cerr << "##################################################" << std::endl;
  

  bool sub_res=go_back_to_parent(_sub);
  
//   std::cerr << "################### SUB ###############################" << std::endl;
//   std::cerr << "# ";
//   _sub.dump_history();
  
//   _sub.dump();
//   std::cerr << "                                                 #" << std::endl;
//   std::cerr << "##################################################" << std::endl;
  
  bool res=false;

  if(mol_res && sub_res){
    res=main_descend(true);
  }

  return res;
}




bool molecule_matching::go_back_to_parent(residual_DFS& molecule){
  bool res=false;
  atomo* pin=molecule.curr_atom();

  
  if(!_mol.is_starting_point(pin)){

    std::vector<action> allowed;
    allowed.push_back(DESCEND_NORMAL);
    
    allowed.push_back(DESCEND_NORMAL_CYCLE);
    allowed.push_back(DESCEND_TERMINAL);
    allowed.push_back(DESCEND_TERMINAL_CYCLE);
    allowed.push_back(DESCEND_SET_BLACK_PARENT_CYCLE);
    allowed.push_back(DESCEND_SET_BLACK_PARENT);

    //DEBUG_TO_CERR(pin->id());
    /*
    molecule.dump_history();
  
    molecule.dump();
    */
    bool available=false;

    if(pin!=NULL){
      while(molecule.curr_atom()==pin &&
            find(allowed.begin(), allowed.end(), molecule.curr_action())!=allowed.end()){
        available=molecule.backstep();
        std::cerr << __FUNCTION__ << "backstep\n";
      }
    }

    res=available;
  }
  return res;
}


bool molecule_matching::block_path(atomo* atm){
  bool res=false;
  if(atm==NULL){
    atomo* at=_mol.curr_atom();
    if(at!=NULL){
      _mol_reds.insert(at);
      res=true;
    }
  }else{
    _mol_reds.insert(atm);
    res=true;
  }

  return res;
}


bool molecule_matching::find_set_black_parent_cycle_candidate(bool use_reds){
  bool res=false;
  std::vector<action> allowed;

  allowed.push_back(DESCEND_NORMAL_CYCLE);
  allowed.push_back(DESCEND_TERMINAL_CYCLE);
  allowed.push_back(DESCEND_SET_BLACK_PARENT_CYCLE);

  bool (molecule_matching::*condition)(residual_DFS*, 
                                       atomo* , atomo* ,
                                       residual_DFS* , 
                                       atomo* , atomo* ) = &molecule_matching::check_black_parent_cycle_candidate;
  
  bool found=find_generic_candidate(allowed,condition,use_reds);

  if(found){
    if(_mol.curr_action()!=DESCEND_SET_BLACK_PARENT_CYCLE){
      //qui si deve forzare black per il genitore
      //          DA FAREEEEE!!!
      atomo* parent=_mol.parent_atom();
      atomo* curr=_mol.curr_atom();
      _mol.backstep();
      _mol.DFS_descend_force_set_black_parent_cycle(parent,curr,true);
    }
    res=true;
  }else{
    
  }

  return res;
  
}

bool molecule_matching::find_set_black_parent_candidate(bool use_reds){
  bool res=false;
  std::vector<action> allowed;
  allowed.push_back(DESCEND_NORMAL);
  allowed.push_back(DESCEND_SET_BLACK_PARENT);

  bool (molecule_matching::*condition)(residual_DFS*, 
                                       atomo* , atomo* ,
                                       residual_DFS* , 
                                       atomo* , atomo* ) = &molecule_matching::check_normal_candidates_atom;
  
  bool found=find_generic_candidate(allowed,condition,use_reds);

  if(found){
    if(_mol.curr_action()!=DESCEND_SET_BLACK_PARENT){
      //std::cerr << "AAAAAAAAAAAAAAA" << std::endl;

      atomo* parent=_mol.parent_atom();
      atomo* curr=_mol.curr_atom();
      _mol.backstep();
      _mol.DFS_descend_force_set_black_parent(parent,curr,true);

      
      
    }
    res=true;
  }else{
    
  }

  return res;

}


bool molecule_matching::find_normal_candidate(bool use_reds){

  std::vector<action> allowed;
  allowed.push_back(DESCEND_NORMAL);

  bool (molecule_matching::*condition)(residual_DFS*, 
                                       atomo* , atomo* ,
                                       residual_DFS* , 
                                       atomo* , atomo* ) = &molecule_matching::check_normal_candidates_atom;
  
  return find_generic_candidate(allowed,condition,use_reds);


}



bool molecule_matching::find_generic_candidate(std::vector<action> allowed,
                                               bool (molecule_matching::*cond)(residual_DFS*,
                                                                               atomo*,atomo*,
                                                                               residual_DFS*,
                                                                               atomo*,atomo*),
                                               
                                               bool use_reds
                                               ){

  bool result=false;
  atomo* sub_p=_sub.parent_atom();
  atomo* sub_atom=_sub.curr_atom();
  atomo* mol_p=_mol.parent_atom();
  atomo* mol_atom=_mol.curr_atom();
  gruppo* grp=_mol.get_pointer_gruppo();

  vector<legame>::iterator mol_first=mol_atom->primo_leg();
  vector<legame>::iterator mol_last=mol_atom->ultimo_leg();
  atomo* child=0;
  while(mol_first!=mol_last){
    child=grp->find_atomo_id((*mol_first).id_atomo());  
    if(mol_p==NULL || child->id()!= mol_p->id()){ 
      //std::cerr << "check " << mol_atom->id() << " " << child->id() << std::endl;
      bool found_and_not_black=_mol.DFS_find_descend_forced(mol_atom,child);
      action curr_action=_mol.curr_action();
      if(found_and_not_black){
        if(find(allowed.begin(), allowed.end(), curr_action)!=allowed.end() &&
           (((*this).*cond)(&_mol,
                            _mol.curr_atom(), 
                            _mol.parent_atom(),
                            &_sub,
                            sub_atom, 
                            sub_p))){
          //std::cerr << "AOOOOOOOOOOOOOOOOOOO"<< std::endl;
      
          if(use_reds){
            if(_mol_reds.count(_mol.curr_atom())==0){
              result=true;
              break;
            }else{
              result=false;
              _mol.backstep();
            }
          }else{
            result=true;
            break;
          }
          
        }else{
          _mol.backstep();
        }
      }
    }
    mol_first++;
  }

  return result;
}



bool molecule_matching::check_black_parent_cycle_candidate(residual_DFS* dfs_mol, 
                                                           atomo* mol, atomo* parmol,
                                                           residual_DFS* dfs_ref, 
                                                           atomo* sub, atomo* parsub){


 bool res=false;

  gruppo* molecule=dfs_mol->get_pointer_gruppo();
  gruppo* ref=dfs_ref->get_pointer_gruppo();

  if(equal_bond_type(molecule, mol, parmol, 
                     ref, sub, parsub) &&
     equal_no_children(mol, sub) &&
     equal_raw_string (mol, sub) &&
     dfs_mol->is_gray(mol)
     ){
    
    res=true;
  }

  return res;


}

bool molecule_matching::check_normal_candidates_atom(residual_DFS* dfs_mol, 
                                                     atomo* mol, atomo* parmol,
                                                     residual_DFS* dfs_ref, 
                                                     atomo* sub, atomo* parsub){
  bool res=false;

  gruppo* molecule=dfs_mol->get_pointer_gruppo();
  gruppo* ref=dfs_ref->get_pointer_gruppo();

  if(equal_bond_type(molecule, mol, parmol, 
                     ref, sub, parsub) &&
     equal_no_children(mol, sub) &&
     equal_raw_string (mol, sub)
     ){
    
    res=true;
  }

  return res;
}

bool molecule_matching::good_starting_point(atomo* ref, atomo* start){
  bool found=false;

  if(equal_raw_string(ref,start)){
    found=true;
  }

  return found;
}



bool molecule_matching::equal_bond_type(gruppo* molecule_mol, atomo* mol, atomo* parmol, 
                                        gruppo* molecule_ref, atomo* ref, atomo* parref){
  bool res=false;
  legame mol_bond(0,0,0,0,0,0);
  legame ref_bond(0,0,0,0,0,0);;
  if(is_direct_children(molecule_mol, mol, parmol, mol_bond) &&
     is_direct_children(molecule_ref, ref, parref, ref_bond)){
    if(mol_bond.tipo_legame()==ref_bond.tipo_legame()){
      res=true;
    }
  }else{

  }
  return res;
}



bool molecule_matching::is_direct_children(gruppo* mol,
                                           atomo* child, atomo* parent, 
                                           legame& res){

  bool found=false;

  vector<legame>::iterator mol_first=parent->primo_leg();
  vector<legame>::iterator mol_last=parent->ultimo_leg();
  while(mol_first!=mol_last){  
    atomo* nw_child=mol->find_atomo_id((*mol_first).id_atomo()); 
    if(nw_child->id() == child->id() && 
       nw_child==child){
      found=true;
      res=*mol_first;
      break;
    }
    mol_first++;
  }


  return found;

}




bool molecule_matching::equal_no_children(atomo* mol, atomo* ref){
  bool res=false;
  if(mol->bond_number() >= ref->bond_number()){
    res=true;
  }
  return res;
}


bool molecule_matching::equal_raw_string(atomo* mol, atomo* ref){
  bool res=false;
  if((mol->etich()).to_raw_string() == (ref->etich()).to_raw_string()){
    res=true;
  }

  return res;

}


void molecule_matching::debug_print_all(residual_DFS s){
    debug_print_DFS(s);
    s.dump();
    s.dump_history();
}


void molecule_matching::debug_print_DFS(residual_DFS s){
  action ca=s.curr_action();
  if(ca==DESCEND_NORMAL){
    std::cerr << "\tDESCEND_NORMAL" << std::endl;
    std::cerr << "partendo da : " << s.parent_atom()->id() 
              << " scenderei in " << s.curr_atom()->id() 
              << " proveniente da un legame " 
              << s.bond_type()
              << " e " << s.no_children() << " figli " 
              << std::endl;
  }else if(ca==DESCEND_TERMINAL){
    std::cerr << "\tDESCEND_TERMINAL" << std::endl;
    std::cerr << "partendo da : " << s.parent_atom()->id() 
              << " scenderei in " << s.curr_atom()->id()  
              << " proveniente da un legame " 
              << s.bond_type()
              << " e " << s.no_children() << " figli " 
              << " questo verra' eliminato "
              << std::endl;
  }else if(ca==DELETE_TERMINAL){
    std::cerr << "\t DELETE_TERMINAL" << std::endl;
    std::cerr << " eliminato precedente " << std::endl;
  }else if(ca==DESCEND_NORMAL_CYCLE){
    std::cerr << "\t DESCEND_NORMAL_CYCLE" << std::endl;
    std::cerr << "ciclo!! partendo da : " << s.parent_atom()->id() 
              << " scenderei in " << s.curr_atom()->id() 
              << " proveniente da un legame " 
              << s.bond_type()
              << " e " << s.no_children() << " figli " 
              << std::endl;

    std::cerr << "\tformano un ciclo" << std::endl;

  }else if(ca==SET_BLACK_CURR_CYCLE){
    std::cerr << "\t SET_BLACK_CURR_CYCLE" << std::endl;
    std::cerr << s.curr_atom()->id() 
              <<  " diventa black "
              << std::endl;
    std::cerr << "\te chiude un ciclo" << std::endl;

  }else  if(ca==SET_BLACK_CURR){
    std::cerr << "\t SET_BLACK_CURR" << std::endl;
    std::cerr << s.curr_atom()->id() 
              <<  " diventa black "
              << std::endl;
  }else  if(ca==DESCEND_SET_BLACK_PARENT_CYCLE){
    std::cerr << "\t DESCEND_SET_BLACK_PARENT_CYCLE" << std::endl;
    std::cerr << "partendo da : " << s.parent_atom()->id() 
              << " scenderei in " << s.curr_atom()->id() 
              << " proveniente da un legame " 
              << s.bond_type()
              << " e " << s.no_children() << " figli " 
              << std::endl;
    std::cerr << s.parent_atom()->id() 
              <<  " diventa black "
              << std::endl;
    std::cerr << "\te chiude un ciclo" << std::endl;

  }else  if(ca==DESCEND_SET_BLACK_PARENT){
    std::cerr << "\t DESCEND_SET_BLACK_PARENT" << std::endl;
    std::cerr << "partendo da : " << s.parent_atom()->id() 
              << " scenderei in " << s.curr_atom()->id() 
              << " proveniente da un legame " 
              << s.bond_type()
              << " e " << s.no_children() << " figli " 
              << std::endl;
    std::cerr << s.parent_atom()->id() 
              <<  " diventa black "
              << std::endl;
  }else  if(ca==FORCE_BLACK_PARENT){
    std::cerr << "\t FORCE_BLACK_PARENT" << std::endl;
    std::cerr << " forzo " << s.parent_atom()->id() 
              <<  " black "
              << std::endl;
  }




}



bool  molecule_matching::TEST_BFS(){
  int st=1;
  _sub.DFS_step(&st);

  gruppo* g=_sub.get_pointer_gruppo();
  std::cerr << "---- 1 -> 2 ---------" << std::endl;
  _sub.DFS_find_descend_forced(g->find_atomo_id(1), g->find_atomo_id(2));
  _sub.dump();
  _sub.dump_history();
  std::cerr << "-------------" << std::endl;

  std::cerr << "---- shift ---------" << std::endl;
  _sub.DFS_shift_descendant(true);
  _sub.dump();
  _sub.dump_history();
  std::cerr << "-------------" << std::endl;


  std::cerr << "---- shift seconfo---------" << std::endl;
  _sub.DFS_shift_descendant(true);
  _sub.dump();
  _sub.dump_history();
  std::cerr << "-------------" << std::endl;


  return true;

}

bool  molecule_matching::TEST_DFS_forced(){
  int st=0;
  _sub.DFS_step(&st);

  gruppo* g=_sub.get_pointer_gruppo();
  std::cerr << "---- 0 -> 1 ---------" << std::endl;
  _sub.DFS_find_descend_forced(g->find_atomo_id(0), g->find_atomo_id(1));
  _sub.dump();
  _sub.dump_history();
  std::cerr << "-------------" << std::endl;


  std::cerr << "---- 1 -> 2 ---------" << std::endl;
  _sub.DFS_find_descend_forced(g->find_atomo_id(1), g->find_atomo_id(2));
  _sub.dump();
  _sub.dump_history();

  
  std::cerr << "---- set 2 black ---" << std::endl;
  _sub.DFS_step();

  _sub.dump();
  _sub.dump_history();
  std::cerr << "dump blacks " << std::endl;
  _sub.dump_blacks();
  
  /*

  std::cerr << "---- 2 -> 1 ---------" << std::endl;
  _sub.DFS_find_descend_forced(g->find_atomo_id(2), g->find_atomo_id(1));
  _sub.dump();
  _sub.dump_history();
  std::cerr << "-------------" << std::endl;
  */



  std::cerr << "---- pop 2 ---------" << std::endl;
  _sub.DFS_pop_current_atom(true);
  _sub.dump();

  _sub.dump_history();
  std::cerr << "MMMM " <<_sub.is_black(g->find_atomo_id(2)) << std::endl;

  

  std::cerr << "---- 1 -> 3 ---------" << std::endl;
  _sub.DFS_find_descend_forced(g->find_atomo_id(1), g->find_atomo_id(3));
  _sub.dump();
  _sub.dump_history();
  std::cerr << "MMMM " <<_sub.is_black(g->find_atomo_id(2)) << std::endl;
  
  std::cerr << "---- pop 3 ??? ---------" << std::endl;
  _sub.DFS_pop_current_atom(true);
  _sub.dump();
  _sub.dump_history();
  std::cerr << "MMMM " <<_sub.is_black(g->find_atomo_id(2)) << std::endl;
  std::cerr << "dump blacks " << std::endl;
  _sub.dump_blacks();
  
  return true;


}

bool  molecule_matching::TEST_DFS(){
  int st=0;
  _sub.DFS_step(&st);
  
  atomo* res=NULL;


  _sub.DFS_step();
  debug_print_DFS(_sub);
  _sub.DFS_step();
  debug_print_DFS(_sub);
  _sub.DFS_step();
  debug_print_DFS(_sub);
  
  //DEBUG_TO_CERR(_sub.DFS_simulate_shift_descendant(&res));
  if(res){
    std::cerr << "scenderei in " << res->id() << std::endl;
  }
  _sub.dump_history();
  _sub.dump();
  
  return false;


  for(int i=0;i<10;i++){
    if(_sub.DFS_is_finished()){
      std::cerr << "finito" << std::endl;
    }else{
      _sub.DFS_step();      

      action ca=_sub.curr_action();

      if(ca==DESCEND_NORMAL){
        std::cerr << "\tDESCEND_NORMAL" << std::endl;
        std::cerr << "partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id() 
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << std::endl;
      }else if(ca==DESCEND_TERMINAL){
        std::cerr << "\tDESCEND_TERMINAL" << std::endl;
        std::cerr << "partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id()  
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << " questo verra' eliminato "
                  << std::endl;
      }else if(ca==DELETE_TERMINAL){
        std::cerr << "\t DELETE_TERMINAL" << std::endl;
        std::cerr << " eliminato precedente " << std::endl;
      }else if(ca==DESCEND_NORMAL_CYCLE){
        std::cerr << "\t DESCEND_NORMAL_CYCLE" << std::endl;
        std::cerr << "ciclo!! partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id() 
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << std::endl;
        
        std::cerr << "\tformano un ciclo" << std::endl;
           
      }else if(ca==SET_BLACK_CURR_CYCLE){
        std::cerr << "\t SET_BLACK_CURR_CYCLE" << std::endl;
        std::cerr << _sub.curr_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
        std::cerr << "\te chiude un ciclo" << std::endl;
        
      }else  if(ca==SET_BLACK_CURR){
        std::cerr << "\t SET_BLACK_CURR" << std::endl;
        std::cerr << _sub.curr_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
      }else  if(ca==DESCEND_SET_BLACK_PARENT_CYCLE){
        std::cerr << "\t DESCEND_SET_BLACK_PARENT_CYCLE" << std::endl;
        std::cerr << "partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id() 
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << std::endl;
        std::cerr << _sub.parent_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
        std::cerr << "\te chiude un ciclo" << std::endl;
        
      }else  if(ca==DESCEND_SET_BLACK_PARENT){
        std::cerr << "\t DESCEND_SET_BLACK_PARENT" << std::endl;
        std::cerr << "partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id() 
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << std::endl;
        std::cerr << _sub.parent_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
      }
    }

 
  }

  _sub.dump_history();

  return true;

  _sub.backstep();
  _sub.backstep();
  _sub.backstep();

  std::cerr << "indietro di 3 " << std::endl;
  _sub.dump_history();

  for(int i=0;i<10;i++){
    if(_sub.DFS_is_finished()){
      std::cerr << "finito" << std::endl;
    }else{
      _sub.DFS_step();      

      action ca=_sub.curr_action();

      if(ca==DESCEND_NORMAL){
        std::cerr << "\tDESCEND_NORMAL" << std::endl;
        std::cerr << "partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id() 
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << std::endl;
      }else if(ca==DESCEND_TERMINAL){
        std::cerr << "\tDESCEND_TERMINAL" << std::endl;
        std::cerr << "partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id()  
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << " questo verra' eliminato "
                  << std::endl;
      }else if(ca==DELETE_TERMINAL){
        std::cerr << "\t DELETE_TERMINAL" << std::endl;
        std::cerr << " eliminato precedente " << std::endl;
      }else if(ca==DESCEND_NORMAL_CYCLE){
        std::cerr << "\t DESCEND_NORMAL_CYCLE" << std::endl;
        std::cerr << "ciclo!! partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id() 
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << std::endl;
        
        std::cerr << "\tformano un ciclo" << std::endl;
           
      }else if(ca==SET_BLACK_CURR_CYCLE){
        std::cerr << "\t SET_BLACK_CURR_CYCLE" << std::endl;
        std::cerr << _sub.curr_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
        std::cerr << "\te chiude un ciclo" << std::endl;
        
      }else  if(ca==SET_BLACK_CURR){
        std::cerr << "\t SET_BLACK_CURR" << std::endl;
        std::cerr << _sub.curr_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
      }else  if(ca==DESCEND_SET_BLACK_PARENT_CYCLE){
        std::cerr << "\t DESCEND_SET_BLACK_PARENT_CYCLE" << std::endl;
        std::cerr << "partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id() 
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << std::endl;
        std::cerr << _sub.parent_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
        std::cerr << "\te chiude un ciclo" << std::endl;
        
      }else  if(ca==DESCEND_SET_BLACK_PARENT){
        std::cerr << "\t DESCEND_SET_BLACK_PARENT" << std::endl;
        std::cerr << "partendo da : " << _sub.parent_atom()->id() 
                  << " scenderei in " << _sub.curr_atom()->id() 
                  << " proveniente da un legame " 
                  << _sub.bond_type()
                  << " e " << _sub.no_children() << " figli " 
                  << std::endl;
        std::cerr << _sub.parent_atom()->id() 
                  <<  " diventa black "
                  << std::endl;
      }
    }

 
  }

  _sub.dump_history();

  return true;

}


