/*

    Bist: a chemical drawing tool
    Copyright (C) 2008 Valerio Benfante

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <global.hpp>

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


#include <FL/Fl_Pixmap.H>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Menu_Bar.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Choice.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Round_Button.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Color_Chooser.H>
#include <FL/Fl_Help_Dialog.H>

#include <prefs.hpp>

#include <interfacce.hpp>
#include <legame.hpp>
#include <etichetta.hpp>
#include <multiline_label.hpp>
#include <multifont_label.hpp>
#include <paragraph_text.hpp>
#include <atomo.hpp>
#include <procedura.hpp>
#include <gruppo.hpp>
#include <immagine.hpp>
#include <bist_plugin.hpp>
#include <mol_canvas.hpp>
#include <finestra_pr.hpp>
#include <editor.hpp>
#include <parse_residual.hpp>

#include <util.hpp>


extern finestra_pr* MainWindow;

extern Preferences  __pref;

parse_residue::parse_residue(string res)
  :_res(res),
   _pt_res(0),
   _length_leg(static_cast<float>(__pref.getBond_fixedlength())),
   _stop(false),
   _pivot_unknown(false),
   _has_error(false)

{

  create_starter();
  chain();

}


bool parse_residue::has_error(){
  return _has_error;
}

void parse_residue::dump(){
    /***********************************/

  cout << "parse: GRUPPI:" << endl;
  vector<atomo>::iterator st=_fragments.top().iniz_atom();
  vector<atomo>::iterator en=_fragments.top().fin_atom();
  cout << "parse: ID: " << (_fragments.top()).id_gruppo() << endl;
  cout << "parse: ANGOLOROT: " << (_fragments.top()).angolorot() << endl;
  cout << "parse: ROT_XPIVOT: " << (_fragments.top()).xpivot() << endl;
  cout << "parse: ROT_YPIVOT: " << (_fragments.top()).ypivot() << endl;

  while(st!=en){
    cout << (*st).id() << endl;
    st++;
  }


  vector<atomo>::iterator iniz=(_fragments.top()).iniz_atom();
  vector<atomo>::iterator fin=(_fragments.top()).fin_atom();

  while(iniz!=fin){

    etichetta tmp_et=(*iniz).etich();
    vector < pair<string,int> > tmp_str_et=tmp_et.vec_str();
    cout << "parse: Atomo:" << (*iniz).id() << " " << endl;
    cout << "parse: attach: " << (*iniz).can_attach() << endl;
    cout << "parse: Tipo:"<< (*iniz).tipo_atomo() << endl;
    cout << "parse: ***etichetta:" << endl;
    for(unsigned int i2=0;i2<tmp_str_et.size();i2++){
      // #define ET_STR   0
      // #define ET_APICE 1
      // #define ET_PEDICE 2
      //cout << "#@#" << tmp_str_et.second << endl;
      switch(tmp_str_et[i2].second){
      case ET_STR:
	cout << "parse: \tSTR: " << tmp_str_et[i2].first;
	break;
      case ET_APICE:
	cout << "parse: \tAPICE: " << tmp_str_et[i2].first;
	break;
      case ET_PEDICE:
	cout << "parse: \tPEDICE: " << tmp_str_et[i2].first;
	break;
      }
    }
    cout << endl;
    cout << "parse: \tFONT_ET: " << tmp_et.font() << endl;
    cout << "parse: \tDIM_FONT_ET: " << tmp_et.dim() << endl;;
    cout << "parse: \tX_ET: " << tmp_et.x() << " dovrebbe essere 0" << endl;
    cout << "parse: \tY_ET: " << tmp_et.y() << " dovrebbe essere 0" << endl;

    cout << "parse: \tCR_ET: " << tmp_et.cr() << endl;
    cout << "parse: \tCG_ET: " << tmp_et.cg() << endl;
    cout << "parse: \tCB_ET: " << tmp_et.cb() << endl;
    cout << "parse: \tALLINEAMENTO: " << tmp_et.allineamento() << endl;

    cout << "parse: ***fine etichetta" << endl;
    cout << "parse: Cariche: " << (*iniz).cariche() << endl;
    cout << "parse: Doppietti:" << (*iniz).doppietti() << endl;
    cout << "parse: Elettroni spaiati: " << (*iniz).el_spaiati() << endl;
    cout << "parse: Numero di massa: " << (*iniz).massa() << endl;
    cout << "parse: CR: " << (*iniz).cr() << endl;
    cout << "parse: CG: " << (*iniz).cg() << endl;
    cout << "parse: CB: " << (*iniz).cb() << endl;
    cout << "parse: POSX:" << (*iniz).phys_pos_x() << endl;
    cout << "parse: POSY: " << (*iniz).phys_pos_y() << endl;
    cout << "parse: ID_GRUPPO: " <<(*iniz).id_gruppo() << endl;
    cout << "parse: ***legami" << endl;
    vector<legame>::iterator inizl=(*iniz).primo_leg();
    vector<legame>::iterator finl=(*iniz).ultimo_leg();
    while(inizl!=finl){
      cout << "parse: \tid_atomo: " << (*inizl).id_atomo() << endl;
      cout << "parse: \tid_legame: " << (*inizl).id_legame() << endl;
      cout << "parse: \ttipo_legame " << (*inizl).tipo_legame() << endl;
      cout << "parse: \tcr " << (*inizl).cr() << endl;
      cout << "parse: \tcg " << (*inizl).cg() << endl;
      cout << "parse: \tcb " << (*inizl).cb() << endl;
      inizl++;
    }

    cout << "parse: *** fine legami ***" << endl;

    iniz++;
  }


}

gruppo parse_residue::return_fragment()
{
  return _fragments.top();
}


parse_residue::~parse_residue(){

}


atomo* parse_residue::search_for_attach(gruppo* the_mol){
  vector<atomo>::iterator inatom=the_mol->iniz_atom();
  vector<atomo>::iterator finatom=the_mol->fin_atom();

  while(inatom!=finatom){
    if((*inatom).can_attach()){
      return &(*inatom);
    }
    inatom++;
  }

  return 0;
}



string parse_residue::etich_sticky_atom(gruppo* mol){
  atomo* atm=search_for_attach(mol);
  etichetta et=atm->etich();

  string prs_stringa;

  for(unsigned int i=0;i<et.vec_str().size();i++){
    prs_stringa +=((et.vec_str())[i]).first;
  }

  return prs_stringa;

}

void parse_residue::add_atoms(gruppo* mol,string et,int tipo, bool new_sticky){


      atomo* to_attach;
      if((to_attach=search_for_attach(mol))==0){
	cout << "parse: qui nun si dovrebbe arrivare" << endl;
	atomo tmp;
	tmp.can_attach(true);
	tmp.aggiungi_genitore(mol);
	tmp.etich_punt()->aggiungi(et, ET_STR);
	tmp.costruisci_arrivati();
	mol->add_atomo_id(tmp);
      }else{
	//cout << "parse :: cerco attach" << to_attach << " " << to_attach->id() << endl;

	atomo tmp;
	tmp.aggiungi_genitore(mol);
	tmp.etich_punt()->aggiungi(et, ET_STR);
	tmp.costruisci_arrivati();
	tmp.pos_x(-1);
	tmp.pos_y(-1);
	int id_ul=mol->add_atomo_id(tmp);

	//   aggiungi_legame(int	nw_leg_id_atomo,
// 			    int nw_leg_tipo_legame,int nwcr,
// 			    int nwcg , int nwcb)


	to_attach=search_for_attach(mol);
	atomo* attached=mol->find_atomo_id(id_ul);

	to_attach->aggiungi_legame(attached->id(),tipo,0,0,0);

	attached->aggiungi_legame(to_attach->id(),tipo,0,0,0);

	if(new_sticky){
	  search_for_attach(mol)->can_attach(false);
	  attached->can_attach(true);
	}
      }
}


void parse_residue::chain(){
  //  while(!_stop){
  frammento();
  //}
  /*
  cout << "PARSING TERMINATO" << endl;
  cout << "_res " << _res << " _res.size() "
       << _res.size() << " _pt_res "
       << _pt_res << endl;
  */

  if(!has_error()){
    atomo* not_to_attach;
    if((not_to_attach=search_for_attach(&_fragments.top()))!=0){
      not_to_attach->can_attach(false);
    }


    atomo* dum=_fragments.top().find_atomo_id(0);

    vector<legame>::iterator primo=dum->primo_leg();
    atomo* primo_carb=_fragments.top().find_atomo_id((*primo).id_atomo());
    float xcomp=_length_leg*cos(_angle_exa);
    float ycomp=_length_leg*sin(_angle_exa);
    primo_carb->pos_x(xcomp);
    primo_carb->pos_y(ycomp);
    /*cout << "primo_carb " << primo_carb->id() << " " 
      << primo_carb->pos_x() << " " << primo_carb->pos_y() << endl;
    */
    //dump();
    int leafs=0;
    
    _fragments.top().cancel_visitato_all();
    no_of_leaf(_fragments.top(), *(_fragments.top().iniz_atom()), leafs);
    leafs--;
    //cout << "foglie: " << leafs << endl;
  

    _fragments.top().cancel_visitato_all();
    (*(_fragments.top().iniz_atom())).visitato(true);
    clean(_fragments.top(),*(_fragments.top().iniz_atom()+1));
  

    _fragments.top().cancel_visitato_all();
  
    float distmax=_length_leg*leafs;
    
    int level=0;
    int xst=90;
    
    clean_as_tree(_fragments.top(), *(_fragments.top().iniz_atom()+1), 
		  distmax, level, xst);
    
  }

  

}

void parse_residue::create_aa_bb(gruppo grp, 
				 int st, int child, 
				 res_aa_bb& res){
  
  cout << "clean_as_tree: create aa_bb " << st << " " << child << endl;
  cout << "clean_as_tree:\t parto da: " << endl 
       << "clean_as_tree:\t aa_b rx " << res.r_x << endl
       << "clean_as_tree:\t aa_b ry " << res.r_y << endl
       << "clean_as_tree:\t aa_b sx " << res.s_x << endl
       << "clean_as_tree:\t aa_b sy " << res.s_y << endl;
  
  atomo* par=grp.find_atomo_id(st);
  par->visitato(true);
  atomo* chld=grp.find_atomo_id(child);
  chld->visitato(true);
  
  cout << "clean_as_tree: inserisco chld: " << chld->id()
       << endl;

  if(chld->phys_pos_x() < res.s_x){
    res.s_x=chld->phys_pos_x();
  }

  if (chld->phys_pos_x() > res.r_x){
    res.r_x=chld->phys_pos_x();
  }
  
      
  if(chld->phys_pos_y() < res.r_y){
    res.r_y=chld->phys_pos_y();
  }

  if (chld->phys_pos_y() > res.s_y){
    res.s_y=chld->phys_pos_y();
  }  
  
  vector<legame>::iterator primo=chld->primo_leg();
  vector<legame>::iterator ultimo=chld->ultimo_leg();
  

  while(primo != ultimo){
    atomo* legato=grp.find_atomo_id((*primo).id_atomo());
    if(! legato->visitato()){
      //ampliamo eventualmente la aa_bb
      
      cout << "clean_as_tree: legato posx " << legato->phys_pos_x() 
	   << "posy: " << legato->phys_pos_y() << "id" << legato->id()<< endl;
      
      if(legato->phys_pos_x() < res.s_x){
	
	cout <<"clean_as_tree: sx " << res.s_x << " -> " 
	     << legato->phys_pos_x() << endl;
	
	res.s_x=legato->phys_pos_x();

      }else if (legato->phys_pos_x() > res.r_x){
	
	cout <<"clean_as_tree: rx " << res.r_x << " -> " 
	     << legato->phys_pos_x() << endl;
	
	res.r_x=legato->phys_pos_x();
      }

      
      if(legato->phys_pos_y() < res.r_y){
	
	cout <<"clean_as_tree: ry " << res.r_y << " -> " 
	     << legato->phys_pos_y() << endl;
	
	res.r_y=legato->phys_pos_y();
      }else if (legato->phys_pos_y() > res.s_y){
	
	cout <<"clean_as_tree: sy " << res.s_y << " -> " 
	     << legato->phys_pos_y() << endl;
	
	res.s_y=legato->phys_pos_y();
      }

      //ricorsione
      create_aa_bb(grp,st,legato->id(),res);
    }else{
      cout << "attenzione " << (*primo).id_atomo() << "gia' visitato" << endl; 
    }
    primo++;
  }
}


void parse_residue::frammento(){
  pivot();
  figlio();

  if(!_stop){
    frammento();
  }

}


void parse_residue::pivot(){
  try{
    string tmp;
    tmp+=_res.at(_pt_res);
    if(tmp==carb){
      _pivot_unknown=false;
      _the_pivot=carb;
      add_atoms(&_fragments.top(),NO_ETIC,LEGAME_SINGOLO, true);
      //cout << "pivot : " << _the_pivot << endl;
      _pt_res++; //AVANZIAMO di UNO
    }else if(tmp==oxyg){
      _pivot_unknown=false;
      _the_pivot=oxyg;
      add_atoms(&_fragments.top(),oxyg,LEGAME_SINGOLO, true);
      //cout << "pivot : " << _the_pivot << endl;
      _pt_res++; //AVANZIAMO di UNO
    }else if (tmp==sulf){
      _pivot_unknown=false;
      _the_pivot=sulf;
      add_atoms(&_fragments.top(),sulf,LEGAME_SINGOLO, true);
      //cout << "pivot : " << _the_pivot << endl;
      _pt_res++; //AVANZIAMO di UNO
    }else if (tmp==nytr){
      _pivot_unknown=false;
      _the_pivot=nytr;
      add_atoms(&_fragments.top(),nytr,LEGAME_SINGOLO, true);
      //cout << "pivot : " << _the_pivot << endl;
      _pt_res++; //AVANZIAMO di UNO
    }else{
      //cout << "pivot sconosciuto: " << _res.at(_pt_res) << endl;
      _pivot_unknown=true;
      //_stop=true; //errore
    }


  }catch(std::out_of_range exc){
    _stop=true; //stringa finita
  }

}

void parse_residue::figlio(){
  try{
    string tmp;
    tmp+=_res.at(_pt_res);

    if(tmp==hidr){ //atomo e' idrogeno
      //cout << "\tatomo " << hidr ;
      unsigned int preso=1;
      _pt_res++; //AVANZIAMO di UNO
      number(preso);
      if(preso==0) preso++; //niente numero
      //cout << " preso: " << preso << " volta/e" << endl;
      if(_the_pivot!=carb){
	for(unsigned int i=0;i<preso;i++){
	  add_atoms(&_fragments.top(),hidr,LEGAME_SINGOLO, false);
	}
      }
      figlio();
    }else if(tmp==fluorine){ //atomo e' idrogeno
      //cout << "\tatomo " << hidr ;
      unsigned int preso=1;
      _pt_res++; //AVANZIAMO di UNO
      number(preso);
      if(preso==0) preso++; //niente numero
      //cout << " preso: " << preso << " volta/e" << endl;
      for(unsigned int i=0;i<preso;i++){
	add_atoms(&_fragments.top(),fluorine,LEGAME_SINGOLO, false);
      }
      figlio();

    }else if(tmp==iodine){ //atomo e' idrogeno
      //cout << "\tatomo " << hidr ;
      unsigned int preso=1;
      _pt_res++; //AVANZIAMO di UNO
      number(preso);
      if(preso==0) preso++; //niente numero
      //cout << " preso: " << preso << " volta/e" << endl;
      for(unsigned int i=0;i<preso;i++){
	add_atoms(&_fragments.top(),iodine,LEGAME_SINGOLO, false);
      }
      figlio();
    }else if(_res.substr(_pt_res,2)==db_o){
      //cout << "\tatomo " << db_o << endl;
      unsigned int preso=1;
      _pt_res+=2; //AVANZIAMO di DUE
      number(preso);
      if(preso==0) preso++; //niente numero
      cout << "preso: " << preso << "volta/e" << endl;
      for(unsigned int i=0;i<preso;i++){
	add_atoms(&_fragments.top(),oxyg,LEGAME_DOPPIO, false);
      }
      figlio();

    }else if(_res.substr(_pt_res,2)==clor){
      //cout << "\tatomo " << db_o << endl;
      unsigned int preso=1;
      _pt_res+=2; //AVANZIAMO di DUE
      number(preso);
      if(preso==0) preso++; //niente numero
      cout << "preso: " << preso << "volta/e" << endl;
      for(unsigned int i=0;i<preso;i++){
	add_atoms(&_fragments.top(),clor,LEGAME_SINGOLO, false);
      }
      figlio();
    }else if(_res.substr(_pt_res,2)==bromine){
      //cout << "\tatomo " << db_o << endl;
      unsigned int preso=1;
      _pt_res+=2; //AVANZIAMO di DUE
      number(preso);
      if(preso==0) preso++; //niente numero
      cout << "preso: " << preso << "volta/e" << endl;
      for(unsigned int i=0;i<preso;i++){
	add_atoms(&_fragments.top(),bromine,LEGAME_SINGOLO, false);
      }
      figlio();
    }else if(tmp==par_a){ //parentesi aperta
      //cout << "parentesi aperta:" << endl;
      _pt_res++; //AVANZIAMO di UNO
      create_starter();
      frammento();
      atomo* not_to_attach;

      if((not_to_attach=search_for_attach(&_fragments.top()))!=0){
	not_to_attach->can_attach(false);
      }



      if(_res.at(_pt_res)!=par_c[0]){
	_stop=true;
      }else{
	//cout << "parentesi chiusa:" << endl;
	_pt_res++; //AVANZIAMO di UNO
	unsigned int preso=1;
	number(preso);
	if(preso==0) preso++;
	cout << "\t branch preso " << preso << " volta/e" << endl;
	//qua si deve  recuperare la testa della pila  e appiccicarla al
	//suo successivo MIZZICA...
	gruppo the_branch=_fragments.top();
	_fragments.pop(); //lo eliminiamo
	the_branch.elimina_atomo(0); //eliminiamo il dummy del gruppo di
				     //arrivo
	atomo* hole=the_branch.find_atomo_id(1); // atomo id 1
	atomo* hook=search_for_attach(&_fragments.top()); //atomo     che
	                                                  //aggancia
	//ora  eliminiamo i  legami di  hole che  referenziano  il dummy
	//estinto
	hole->elimina_legame(0);

	assert(hook);
	for(unsigned int i=0;i<preso;i++){
	  gruppo branch_added=the_branch;
	  merge_groups(&_fragments.top(),
		       &branch_added,
		       search_for_attach(&_fragments.top()),
		       hole, LEGAME_SINGOLO);
	}

	//riprendiamo il parsing;
	_stop=false;

      }

    }else if(tmp==par_c){
      _stop=true;

    }else{
      if(_pivot_unknown){
	cout << "da pivot sconosciuto" << endl;
	_stop=true;
	_has_error=true;
      }
      cout << "atomo sconosciuto: " << _res.at(_pt_res) <<  endl;
      cout << "resto: " << _res.substr(_pt_res) << endl;
    }
  }catch(std::out_of_range exc){
    _stop=true; //stringa finita
  }

}

bool parse_residue::number(unsigned int& res){
  string a_number="";
  try{
    while(isdigit(_res.at(_pt_res))){
      a_number+=_res.at(_pt_res);
      _pt_res++; //AVANZIAMO di UNO
    }

    res=strtol(a_number.c_str(),NULL,0);

  }catch(std::out_of_range exc){
    res=strtol(a_number.c_str(),NULL,0);
    _stop=true; //stringa finita

    //return true;
  }


  if(res>3){  //orrenda patch!!!
    //cout << "RES >3" << std::endl;
    res=3;
  }


  return true;
}



void parse_residue::create_starter(){
  gruppo starter;
  atomo tmp;
  tmp.can_attach(true);
  tmp.aggiungi_genitore(&starter);
  tmp.etich_punt()->aggiungi("dummy", ET_STR);
  tmp.costruisci_arrivati();
  tmp.visitato(true);
  starter.add_atomo_id(tmp);
  _fragments.push(starter);

}


void parse_residue::transl_branch(gruppo& group,atomo* start,
				  atomo* parent,
				  float dx, float dy){
  stack<atomo*> the_st;
  vector <int> visited;

  the_st.push(start);
  visited.push_back(parent->id());
  
  while(the_st.size()>0){
    atomo* cima=the_st.top();
    the_st.pop();
    //cout << "trsl: estratto " << cima->id()<<endl;
    //bool e_visto=false;
    vector<int>::iterator exist_it=find(visited.begin(),
					   visited.end(),
					   cima->id());
    if(exist_it==visited.end()){ //non e' stato visitato
      vector<legame>::iterator primo=cima->primo_leg();
      vector<legame>::iterator ultimo=cima->ultimo_leg();
      //cout << ultimo -primo << " "<< endl;
      /*
      if((*primo).id_atomo()!=parent->id()){
	group.find_atomo_id((*primo).id_atomo())->trasla(dx,dy);
	cout << "trsl: traslato " <<  (*primo).id_atomo() << ""
	  "startid" << " " <<start->id() <<endl;
      }
      */
      while(primo!=ultimo){
	the_st.push(group.find_atomo_id((*primo).id_atomo()));
	primo++;
      }

    }else{
      //cout << "trsl " << cima->id() << "visitato" << endl;
    }
    //cout << "--------------" << endl;
    if(exist_it==visited.end()){
    cima->trasla(dx,dy);
    
    //cout << "trsl: traslato " <<  cima->id() << endl;
    }
    visited.push_back(cima->id());
  }
}



bool parse_residue::aa_bb_intersects(gruppo& grp, 
				     atomo start){

  vector<res_aa_bb> the_bb;
  vector<legame>::iterator primo=start.primo_leg();
  vector<legame>::iterator ultimo=start.ultimo_leg();
  


  cout << "clean_as_tree: controllo le aa_bb di " << start.id() << endl;
  while(primo!=ultimo){
    gruppo nuovo_g=grp;
    nuovo_g.cancel_visitato_all();
    atomo *son=nuovo_g.find_atomo_id( (*primo).id_atomo() );
    cout << "clean_as_tree: figlio id " << (*primo).id_atomo() << " " 
	 << son->id() << endl;

    res_aa_bb a_aa_bb;
    
    a_aa_bb.r_x=-1E10;
    a_aa_bb.r_y=1E10;

    a_aa_bb.s_x=1E10;
    a_aa_bb.s_y=-1E10;
      
    if(son->id()>start.id()){
      
      cout << "clean_as_tree: lato "<<  start.id() 
	   << " " <<  son->id() << endl;
      
      create_aa_bb(nuovo_g, 
		   start.id(), son->id(), 
		   a_aa_bb);
    }
      
    the_bb.push_back(a_aa_bb);
    
    cout << "clean_as_tree: fin aa_b rx " << a_aa_bb.r_x << endl
	 << "clean_as_tree: fin aa_b ry " << a_aa_bb.r_y << endl
	 << "clean_as_tree: fin aa_b sx " << a_aa_bb.s_x << endl
	 << "clean_as_tree: fin aa_b sy " << a_aa_bb.s_y << endl;
    
    primo++;
  }
    
  bool intersect=true;

  for(unsigned int i=0;i<the_bb.size();i++){
    for(unsigned int i2=0;i2<the_bb.size();i2++){
      if(i2!=i){
	
	cout << "clean_as_tree: confronto:" << endl
	     << "clean_as_tree: the_bb[i] rx " << the_bb[i].r_x << endl
	     << "clean_as_tree: the_bb[i] ry " << the_bb[i].r_y << endl
	     << "clean_as_tree: the_bb[i] sx " << the_bb[i].s_x << endl
	     << "clean_as_tree: the_bb[i] sy " << the_bb[i].s_y << endl
	     << "clean_as_tree: con " << endl
	     << "clean_as_tree: the_bb[i2] rx " << the_bb[i2].r_x << endl
	     << "clean_as_tree: the_bb[i2] ry " << the_bb[i2].r_y << endl
	     << "clean_as_tree: the_bb[i2] sx " << the_bb[i2].s_x << endl
	     << "clean_as_tree: the_bb[i2] sy " << the_bb[i2].s_y << endl;
	
	if(the_bb[i].r_x < the_bb[i2].s_x){
	  intersect=false;
	  
	  cout << "clean_as_tree: non si intersecano "
	       << "the_bb[i].r_x < the_bb[i2].s_x " 
	       << the_bb[i].r_x << " " 
	       << the_bb[i2].s_x << endl;
	  
	}else if(the_bb[i].s_x > the_bb[i2].r_x ){
	  intersect=false;
	  
	  cout << "clean_as_tree: non si intersecano "
	       << "the_bb[i].s_x > the_bb[i2].r_x " 
	       << the_bb[i].s_x << " " 
	       << the_bb[i2].r_x << endl;
	  
	}else if(the_bb[i].r_y >  the_bb[i2].s_y){
	  intersect=false;
	  
	  cout << "clean_as_tree: non si intersecano "
	       << "the_bb[i].r_y > the_bb[i2].s_y " 
	       << the_bb[i].r_y << " " 
	       << the_bb[i2].s_y << endl;
	  
	}else if(the_bb[i].s_y <  the_bb[i2].r_y){
	  
	  cout << "clean_as_tree: non si intersecano "
	       << "the_bb[i].s_y < the_bb[i2].r_y " 
	       << the_bb[i].s_y << " " 
	       << the_bb[i2].r_y << endl;
	  
	  intersect=false;
	}else{
	  cout << "clean_as_tree: si intersecano!" << endl;
	  return true;
	  //break;
	}
      }
    }
  }

  return intersect;
}

void parse_residue::clean_as_tree(gruppo& group, atomo& start, 
				  float distmax, int level, int xst){
  //static bool un_stop=false;

  
  cout << "clean_as_tree: inizio: " 
       << "start id: " << start.id()
       << endl;
  
  start.visitato(true);
  vector<legame>::iterator primo=start.primo_leg();
  vector<legame>::iterator ultimo=start.ultimo_leg();
  int numleg=ultimo-primo -1;
  cout << "clean_as_tree: numleg=" << numleg <<endl;

  if(numleg <=1){
    
    cout << "clean_as_tree: start("
	 << start.id() << ")"
	 << "e' foglia, o al piu' ha un figlio esco" << endl;
    
    return;
  }else{
    while(primo!=ultimo){
      atomo *son=group.find_atomo_id( (*primo).id_atomo() );
      if(!son->visitato()){
	
	cout << "clean_as_tree: " 
	     << "scendo in " 
	     << son->id()
	     << " da " << start.id() <<endl;
	
	clean_as_tree(group,*son, 
		      distmax,level,xst);
      }
      primo++;
    }
    //if (un_stop) return;
    //bool shdst=false;
    while(aa_bb_intersects(group,start)){
      vector<legame>::iterator primo_s=start.primo_leg();
      vector<legame>::iterator ultimo_s=start.ultimo_leg();
      
      cout << "clean_as_tree numleg son: " 
	   <<  ultimo_s - primo_s << endl;
      
      while(primo_s!=ultimo_s){
	atomo *son=group.find_atomo_id( (*primo_s).id_atomo() );
	float dx=(son->phys_pos_x() - start.phys_pos_x())*0.5;
	float dy=(son->phys_pos_y() - start.phys_pos_y())*0.5;
	cout << "clean_as_tree traslo "
	     << son->id() << " figlio di " 
	     << start.id() 
	     << "di " << dx <<  " e " << dy <<  endl;  
	transl_branch(group,son,&start,dx,dy);
	//un_stop=true;
	primo_s++;
      }
      //shdst=true;
    }

  }


  /*

  cout << "tree: iniz " << " level " << level << 
       " id start" << " " << start.id()  
       << "visitato " << start.visitato() <<endl;
  vector<legame>::iterator primo=start.primo_leg();
  vector<legame>::iterator ultimo=start.ultimo_leg();
  int numleg=ultimo-primo;

  cout << "numleg " << numleg << endl;
  if(!start.visitato()){
    
    vector<res_aa_bb> the_bb;
    
    while(primo!=ultimo){
      gruppo nuovo_g=group;
      nuovo_g.cancel_visitato_all();
      atomo *son=nuovo_g.find_atomo_id( (*primo).id_atomo() );
      res_aa_bb a_aa_bb;

      a_aa_bb.r_x=-1E10;
      a_aa_bb.r_y=1E10;

      a_aa_bb.s_x=1E10;
      a_aa_bb.s_y=-1E10;
      
      if(son->id()>0){
	cout << "WW" << endl;
	create_aa_bb(nuovo_g, 
		     start.id(), son->id(), 
		     a_aa_bb);
      }
      
      the_bb.push_back(a_aa_bb);
      cout << "aa_b rx " << a_aa_bb.r_x << endl
	   << "aa_b ry " << a_aa_bb.r_y << endl
	   << "aa_b sx " << a_aa_bb.s_x << endl
	   << "aa_b sy " << a_aa_bb.s_y << endl;

      primo++;
    }
    
    bool intersect=true;
    bool real_clean=true;

    for(unsigned int i=0;i<the_bb.size();i++){
      for(unsigned int i2=0;i2<the_bb.size();i2++){
	if(i2!=i){
	  if(the_bb[i].r_x < the_bb[i2].s_x){
	    intersect=false;
	  }else if(the_bb[i].s_x > the_bb[i2].r_x ){
	    intersect=false;
	  }else if(the_bb[i].r_y >  the_bb[i2].s_y){
	    intersect=false;
	  }else if(the_bb[i].s_y <  the_bb[i2].r_y){
	    intersect=false;
	  }else{
	    intersect=true;
	  }
	}
      }
    }
    

    if(!intersect){
      cout << "do not intersect!" << endl;
      return;
    }else if(the_bb.size() > 1){
      cout << "intersect!" << endl;
    }else{
      cout << "do not intersect! again ;-)" << endl;
      real_clean=false;
    }
    
    primo=start.primo_leg();
    ultimo=start.ultimo_leg();

    start.visitato(true);

    if(numleg>=2){
      numleg--;
    }else if(level==0){
      numleg=1;
    }else{
      cout << "uscito"<< endl;
      return;
    }

    
    cout << "tree: " << " id: " <<  start.id()
	 << " numleg " << numleg 
	 << endl;
    

    
    float inc=0;

    if(numleg==1){
      inc=0;
    }else{
      inc=distmax/(numleg -1);
    }


    float ystart=start.pos_y();

    if(numleg==2 || numleg ==3){
      ystart-= distmax/2;
    }

    while(primo!=ultimo){

      int legato=(*primo).id_atomo();
      
      vector<atomo>::iterator inatom=group.iniz_atom();
      vector<atomo>::iterator finatom=group.fin_atom();

      while(inatom!=finatom){
	//cout << "cerco: " << (*inatom).id() << " " << legato << endl;
	if((*inatom).id()==legato && !(*inatom).visitato()){
	  if(real_clean){
	    float old_posx=(*inatom).pos_x();
	    float old_posy=(*inatom).pos_y();
	    (*inatom).pos_y(ystart);
	    (*inatom).pos_x(xst*(level+1));


	    vector<legame>::iterator primo_tr=(*inatom).primo_leg();
	    vector<legame>::iterator ultimo_tr=(*inatom).ultimo_leg();
	    while(primo_tr!=ultimo_tr){
	      if((*primo_tr).id_atomo()!= (*inatom).id() &&
		 (*primo_tr).id_atomo() !=start.id()){
		cout << "trsl: transl_branch!" << " " << level 
		     << "startid " << (*primo_tr).id_atomo()
		     << "parent " << group.find_atomo_id((*inatom).id())->id() 
		     <<endl;
		transl_branch(group,group.find_atomo_id((*primo_tr).id_atomo()),
			      group.find_atomo_id((*inatom).id()),
			      xst*(level+1) - old_posx , ystart - old_posy);
	      }
	      primo_tr++;
	    }
	    
	  }
	  cout << "tree: " << "trasl... id" << (*inatom).id()
	       << " xst*(level+1)= " << xst*(level+1) << " " << "ystart= "
	       << start.pos_y() 
	       << " level "<< level << endl;
	  float nwdist=0;
	  if(inc==0){
	    nwdist=distmax;
	  }else{
	    nwdist=inc;
	  }
	  //	  cout << "tree: nwdist" << xst/level << endl;
	  clean_as_tree(group, (*inatom), 
			nwdist/2, level+1, xst-xst/8);

	  ystart+= inc;
	}
	inatom++;
      }
      primo++;
    }
  }else{
    
  }
  */

}

void parse_residue::clean(gruppo& group, atomo& start){

  if(!start.visitato()){
    start.visitato(true);

    vector<float> angl;
    vector<legame>::iterator primo=start.primo_leg();
    vector<legame>::iterator ultimo=start.ultimo_leg();
    int numleg=ultimo-primo;
    //cout << "numleg: " << numleg << endl;
    if(numleg==2){
      angl=trova_pos_libere(group,start,2);
    }else if(numleg==3){
      angl=trova_pos_libere(group,start,3);
    }else {
      //cout << "OK" << endl;
      angl=trova_pos_libere(group,start,4);
    }


    while(primo!=ultimo){

      int legato=(*primo).id_atomo();

        vector<atomo>::iterator inatom=group.iniz_atom();
	vector<atomo>::iterator finatom=group.fin_atom();

	while(inatom!=finatom){
	  if((*inatom).id()==legato){
	    if(!(*inatom).visitato()){
	      //ripulisci
	      //cout << "ripulisci: " << angl[0] << endl;
	      (*inatom).pos_x(start.phys_pos_x()+_length_leg*cos(angl[0]));
	      (*inatom).pos_y(start.phys_pos_y()+_length_leg*sin(angl[0]));
	      angl.erase(angl.begin());
	      clean(group,(*inatom));
	    }
	  }
	  inatom++;
	}


      primo++;
    }

  }

}


vector<float> trova_pos_libere(gruppo& grp, atomo& atm, int numleg){
  /*
  cout << "scansione atomo->id " << atm.id()<< " "   
       << atm.pos_x() << " " << atm.pos_y() << endl;
  */
  static float length_leg=static_cast<float>(__pref.getBond_fixedlength());
  static const float  angle_exa=.523598775598298873078;
  //troviamo i legami
  //cerchiamo la posizione del legame precedente
  float res_angl=0;
  bool stop_search=false;
  atomo* res_atm=0;
  for(float i=0;i<=2*M_PI;i+=angle_exa){
    if(stop_search) break;
    //float tmp_x=length_leg*cos(i);// + atm.pos_x();
    //float tmp_y=length_leg*sin(i);// + atm.phys_pos_y();
    vector<legame>:: iterator legin=atm.iniz_leg();
    vector<legame>:: iterator legfin=atm.fin_leg();
    cout << "i: " << i << endl;

    while(legin!=legfin){

      //cout << "cerco atomo: " << (*legin).id_atomo() << endl;
      atomo* q=grp.find_atomo_id((*legin).id_atomo());
      float angle_ref=atan2f(q->phys_pos_y() - atm.phys_pos_y(),
			     q->phys_pos_x() - atm.phys_pos_x());

      if(angle_ref<0){
	//	cout << "angle_ref < 0" << angle_ref << "->" <<
	angle_ref+=2*M_PI;
      }
      /*
      cout << static_cast<int>(rintf(q->pos_x())) <<" -> " << q->pos_x() << " " 
	   << " " << static_cast<int>(rintf(q->pos_y())) << "-> " << q->pos_y()
	   << " " <<static_cast<int>(rintf(tmp_x)) << "->" << tmp_x 
	   << " " 
	   << static_cast<int>(rintf(tmp_y)) << "->" << tmp_y <<endl;
      */
      /*
      cout << "angle_ref=" << angle_ref 
	   << " " << "angle_att=" << i << endl;
      */
      /*

      if(static_cast<int>(rintf(q->pos_x()))==static_cast<int>(rintf(tmp_x+0.1)) &&
	 static_cast<int>(rintf(q->pos_y()))==static_cast<int>(rintf(tmp_y+0.1))){
	cout << "trovato!!" << endl;
	res_angl=i/angle_exa;
	break;
      }
      */

      if(q->visitato() && check_if_inside_arc(angle_ref,i,0.34)){
	//cout << "trovato!!" << endl;
	res_angl=i/angle_exa;
	res_atm=q;
	stop_search=true;
	break;
      }else{
	if(!q->visitato()){
	  /*
	  cout << "atomo id(" << q->id() 
	       <<") non visitato, scarto..." << endl;
	  */
	}
      }


      legin++;
    }
  }




  vector<float> result;
  /*
  cout << "res_angl " << res_angl  
       << " " << static_cast<int>(rintf(res_angl))
       << endl;
  */
  switch(static_cast<int>(rintf(res_angl))){

  case 0:
    place_bonds(result,*res_atm, length_leg,
		0,numleg ,angle_exa);

    break;


  case 2:
    place_bonds(result,*res_atm, length_leg,
		angle_exa*2,numleg ,angle_exa);
    break;


  case 7:

    place_bonds(result,*res_atm, length_leg,
		angle_exa*7,numleg ,angle_exa);
    break;
  case 11:

    place_bonds(result,*res_atm, length_leg,
		angle_exa*11,numleg ,angle_exa);
    break;  
  case 5:
    place_bonds(result,*res_atm, length_leg,
		angle_exa*5,numleg ,angle_exa);
    break;
  case 1:
    place_bonds(result,*res_atm, length_leg,
		angle_exa,numleg ,angle_exa);
    break;

  case 9:  
    place_bonds(result,*res_atm, length_leg,
		angle_exa*9,numleg ,angle_exa);
    break;

  case 3:
    place_bonds(result,*res_atm, length_leg,
		angle_exa*3,numleg ,angle_exa);
    break;
  case 4:
    place_bonds(result,*res_atm, length_leg,
		angle_exa*4,numleg ,angle_exa);
    break;
  case 10:
    place_bonds(result,*res_atm, length_leg,
		angle_exa*10,numleg ,angle_exa);
    break;

  case 8:
    place_bonds(result,*res_atm, length_leg,
		angle_exa*8,numleg ,angle_exa);
    break;

  case 6:
    place_bonds(result,*res_atm, length_leg,
		angle_exa*6,numleg ,angle_exa);
    break;
  }

  //  cout << "risultati scanning "  << result[0]  << endl;
  return result;

}


bool check_if_inside_arc(float angle_ref, 
					float angle_probe, 
					float tolerance){

  if(angle_probe <=angle_ref+tolerance && 
     angle_probe >=angle_ref-tolerance){
    return true;
  }else{
    return false;
  }

}



void place_bonds(vector<float>& result, atomo atm,float length_leg,
		 float start_angle,int numleg ,float step){

  float f=start_angle + step  * 4;
  float f2=start_angle + step * 8;

  if(numleg==3){
    result.push_back(f);
    result.push_back(f2);
  }else if(numleg==2){
    float dist_a= sqrt( pow(atm.phys_pos_x() + length_leg * cos(f) ,2) +
			pow(atm.phys_pos_y() + length_leg * sin(f),2));
    
    float dist_b= sqrt( pow(atm.phys_pos_x() + length_leg * cos(f2) ,2) +
			pow(atm.phys_pos_y() + length_leg * sin(f2),2));
    if(dist_a>dist_b){
      result.push_back(f);
    }else{
      result.push_back(f2);
    }
  }else if(numleg==4){
    result.push_back(start_angle + step * 3);
    result.push_back(start_angle + step * 6);
    result.push_back(start_angle + step * 9);
  }

}



void no_of_leaf(gruppo& grp, atomo& start , int& res){
  //cout << "noleaf visitato" <<  start.visitato() << endl;

 if(!start.visitato()){
    start.visitato(true);
    vector<legame>::iterator primo=start.primo_leg();
    vector<legame>::iterator ultimo=start.ultimo_leg();
    int numleg=ultimo-primo;
    //cout << "numleg: " << numleg << endl;
    if(numleg==1){
      res++;
    }

    while(primo!=ultimo){

      int legato=(*primo).id_atomo();

        vector<atomo>::iterator inatom=grp.iniz_atom();
	vector<atomo>::iterator finatom=grp.fin_atom();

	while(inatom!=finatom){
	  if((*inatom).id()==legato){
	    if(!(*inatom).visitato()){
	      no_of_leaf(grp, (*inatom) , res);
	    }
	  }
	  inatom++;
	}
      primo++;
    }
  }
}


const string parse_residue::par_a="(";
const string parse_residue::par_c=")";

const string parse_residue::carb="C";
const string parse_residue::oxyg="O";
const string parse_residue::sulf="S";
const string parse_residue::nytr="N";
const string parse_residue::db_o="=O";
const string parse_residue::hidr="H";

const string parse_residue::clor="Cl";
const string parse_residue::iodine="I";
const string parse_residue::bromine="Br";
const string parse_residue::fluorine="F";

const float  parse_residue::_angle_exa=.523598775598298873078;
