/***************************************************************************
                          arbre.cpp  -  description
                             -------------------
    begin                : Mon Dec 18 2000
    copyright            : (C) 2000 by Olivier Langella
    email                : Olivier.Langella@pge.cnrs-gif.fr
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/


#include "arbre.h"

namespace biolib {
namespace arbres {

Arbre::~Arbre() {
	//destruction des noeuds et individus
	unsigned int i;

	for (i=0; i < _tabPind.size(); i++) delete _tabPind[i];
	for (i=0; i < _tabPnoeuds.size(); i++) delete _tabPnoeuds[i];

}

Arbre::Arbre() {
	reset();
//	_oui_taille_branches = false;
//	_oui_bootstrap = false;
//	_Pracine = 0;
}

ArbreNdBase::ArbreNdBase(Arbre * Parbre) {
	
	_Parbre = Parbre;
}

ArbreNdBase::~ArbreNdBase() {
}

void ArbreNdBase::set_Pnoeud(unsigned int pos, ArbreNdBase * Pnoeud) {
	_tabPNoeuds[pos] = Pnoeud;
}

unsigned int ArbreNdBase::get_nbbranches() const {
	return(_tabPNoeuds.size());
}
bool ArbreNdBase::est_racine() const {
	return(false);
}

void ArbreNdBase::set_nom(const string & nom) {
}

ArbreNdOTU * Arbre::new_ArbreNdOTU(const string & nom) {
	unsigned int i, taille, j;
	ArbreNdOTU * Pindswap;

	_tabPind.push_back(new ArbreNdOTU(this, nom));


	Pindswap = _tabPind.back();

	taille = _tabPind.size();
	if ((taille == 1) || (nom == "")) {Pindswap->set_id(taille-1);return(Pindswap);}
//	_tabPind.back()->set_id(taille-1);
//classement de l'individu
	// on avance jusqu'à son emplacement:
	i = 0;
	while ((i < (taille-1)) && (strcmp(_tabPind[i]->get_reference(), Pindswap->get_reference()) < 0)) i++;

	_tabPind.back()->set_id(i);
	
	if ((taille-1) == i) return (Pindswap);

	
	for ( j = (taille-1); j > i; j--) {
		_tabPind[j] = _tabPind[j-1];
		_tabPind[j]->set_id(j);
	}
	_tabPind[i] = Pindswap;

	return(Pindswap);
}

ArbreNdOTU * Arbre::new_ArbreNdOTU(ArbreNdNoeud * PArbreNdNoeudPere) {
	_tabPind.push_back(new ArbreNdOTU(this, PArbreNdNoeudPere));
	_tabPind.back()->set_id(_tabPind.size()-1);
	return(_tabPind.back());
}

ArbreNdNoeud * Arbre::new_ArbreNdNoeud(unsigned int nbbranches){
//cerr << "Arbre::new_ArbreNdNoeud(unsigned int nbbranches)" << endl;
	_tabPnoeuds.push_back(new ArbreNdNoeud(this, nbbranches));
//cerr << "Arbre::new_ArbreNdNoeud(unsigned int nbbranches) fin" << endl;
	return(_tabPnoeuds.back());
}

ArbreNdNoeud * Arbre::new_ArbreNdNoeud(ArbreNdNoeud * PArbreNdNoeudere) {
	_tabPnoeuds.push_back(new ArbreNdNoeud(this, PArbreNdNoeudere));
	return(_tabPnoeuds.back());
}

void ArbreNdBase::f_chgt_sens(ArbreNdNoeud * Pracine, ArbreNdNoeud * Psens) {
//cerr << "ArbreNdBase::f_chgt_sens" << endl;

}

void ArbreNdNoeud::f_chgt_sens(ArbreNdNoeud * Pracine, ArbreNdNoeud * Psens) {
	//Psens devient le pointeur vers la racine de l'arbre
	// => a la place de tabPNoeuds[0]
	unsigned int i;
	unsigned int pos(0);
	unsigned int taille (_tabPNoeuds.size());
	ArbreNdBase * Pswap;
	float lgbranche;

//cerr << "ArbreNdNoeud::f_chgt_sens debut" << endl;

	Pswap = _tabPNoeuds[0];
	
	for (i=0; i < taille; i++) if (_tabPNoeuds[i] == Psens) pos = i;

	if (pos != 0) {

		_tabPNoeuds[0] = _tabPNoeuds[pos];
		_tabPNoeuds[pos] = Pswap;

		lgbranche = _tabLgBranches[0];
		set_longueur(0, _tabLgBranches[pos]);
	
//	_tabLgBranches[0] = _tabLgBranches[pos];
		set_longueur(pos, lgbranche);
//	_tabLgBranches[pos] = lgbranche;
	}

	if ( Pracine == this) {
		return;
//		_tabLgBranches[pos] = _tabPNoeuds[pos]->get_tabLgBranches(0);
	}
	else {
		Pswap->f_chgt_sens(Pracine, this);
	}
//cerr << "ArbreNdNoeud::f_chgt_sens fin" << endl;
	
}

void ArbreNdNoeud::f_chgt_racine(ArbreNdNoeud * Pancracine) {
//cerr << "ArbreNdNoeud::f_chgt_racine debut" << endl;
	if (_racine) {
		set_longueur(0, _tabLgBranches[0]);
		_tabPNoeuds[0]->f_chgt_sens(Pancracine, this);
//		if (_tabLgBranches[0] != -999) _tabLgBranches[0] = -999;

//cerr << "ArbreNdNoeud::f_chgt_racine " << Pancracine->get_nbbranches() << endl;
		if (Pancracine->get_nbbranches() == 1) { //le noeud est inutile
			// il faut le squizer
			_Parbre->SquizNoeud(Pancracine);
	  }
	}
	else {
		if (Pancracine == this) {
		}
	}
//cerr << "ArbreNdNoeud::f_chgt_racine fin" << endl;
}

void ArbreNdBase::oPhylipRec(ostream & fichier) const {}//écriture d'arbres au format Phylip

ArbreNdBase * ArbreNdBase::get_Pracine() const {
	return (_tabPNoeuds[0]);
}

double ArbreNdBase::get_tabLgBranches(unsigned int i) const{
	return (_tabLgBranches[i]);
}

double ArbreNdBase::get_longueur_branche() const{
	//longueur de la branche racine
	if (est_racine()) return(0);
	else return (_tabLgBranches[0]);
}

double ArbreNdNoeud::get_longueur_max() const {
	//donne la longueur de la plus grande branche
	double taille(-1), temp;
	unsigned int i;

//	if (_oui_taille_branche) {
		if (est_racine()) {
			temp = _tabPNoeuds[0]->get_longueur_max();
			if (taille < temp) taille = temp;
		}
		for (i=1; i < _tabPNoeuds.size();i++) {
			temp = _tabPNoeuds[i]->get_longueur_max();
			if (taille < temp) taille = temp;
		}
		temp = get_longueur_branche();
		if (temp < 0) return (taille);
		else return (temp + taille);
//	}
	return(0);
}

unsigned int ArbreNdNoeud::get_nbnoeuds_max() const {
	//donne le nombre de noeuds de la plus grande branche
	unsigned int i, temp, nbnoeuds(0);

//	if (_oui_taille_branche) {
		if (est_racine()) {
			temp = _tabPNoeuds[0]->get_nbnoeuds_max();
			if (nbnoeuds < temp) nbnoeuds = temp;
		}
		for (i=1; i < _tabPNoeuds.size();i++) {
			temp = _tabPNoeuds[i]->get_nbnoeuds_max();
			if (nbnoeuds < temp) nbnoeuds = temp;
		}
		return (1 + nbnoeuds);
//	}
}

double ArbreNdNoeud::get_val_bootstrap() const{
	return (_force);
}

ArbreNdBase * ArbreNdNoeud::get_Pracine() const {
	if (_racine) return(0);
	else return (_tabPNoeuds[0]);
}

void ArbreNdNoeud::AjBootstrap() {
	_accuvalboot++;
}

ArbreVectUINT* ArbreNdOTU::f_load_id_ind() {
	ArbreVectUINT * Ptab_id_ind;

//cerr << "ArbreNdOTU::f_load_id_ind debut" <<endl;	

	Ptab_id_ind = new ArbreVectUINT;
	Ptab_id_ind->push_back(_id);


//cerr << "ArbreNdOTU::f_load_id_ind fin" <<endl;	
	return (Ptab_id_ind);	
}

ArbreVectUINT* ArbreNdNoeud::f_load_id_ind() {
	//chargement du vecteur d'id d'individus
	//à partir de la racine, déclenche une fonction récursive de remplissage
	unsigned int i,j;
	ArbreVectUINT * Ptab_id_ind;

//cerr << "ArbreNdNoeud::f_load_id_ind debut" <<endl;	
	for (i=0; i < _tabP_tab_id_ind.size(); i++) delete _tabP_tab_id_ind[i];
  _tabP_tab_id_ind.resize(0);

	if (_racine) {
		_tabP_tab_id_ind.push_back(_tabPNoeuds[0]->f_load_id_ind());
	}
	else _tabP_tab_id_ind.push_back(new ArbreVectUINT);
  	
	for (i = 1; i < _tabPNoeuds.size(); i++) {
		_tabP_tab_id_ind.push_back(_tabPNoeuds[i]->f_load_id_ind());
	}
  if (_racine) return (0);

  Ptab_id_ind = new ArbreVectUINT;
//cerr << "ArbreNdNoeud::f_load_id_ind tri " << _tabP_tab_id_ind[0] << " " << _tabP_tab_id_ind[0]->size() << endl;	
	for (i = 1; i < _tabPNoeuds.size(); i++) {
//cerr << "ArbreNdNoeud::f_load_id_ind tri " << _tabP_tab_id_ind[i] << " " << _tabP_tab_id_ind[i]->size() << endl;	
		for (j = 0; j < _tabP_tab_id_ind[i]->size(); j++) {
			Ptab_id_ind->push_back(_tabP_tab_id_ind[i]->operator[](j));
		}
	}
	// => tri de  Ptab_id_ind

//cerr << "ArbreNdNoeud::f_load_id_ind tri" <<endl;	
	Ptab_id_ind->f_tri();
//cerr << "ArbreNdNoeud::f_load_id_ind tri fin tri" <<endl;	

	//remplissage de _tabP_tab_id_ind[0]
	//avec tout ce qui n'est pas dans Ptab_id_ind
	unsigned int nbind(_Parbre->get_nbind());
//cerr << "ArbreNdNoeud::f_load_id_ind fin Ptab_id_ind " <<endl;
//Ptab_id_ind->affiche();
	for (i=0; i < nbind; i++) if (!Ptab_id_ind->Existe(i)) _tabP_tab_id_ind[0]->push_back(i);
//cerr << "ArbreNdNoeud::f_load_id_ind fin" <<endl;	
//cerr << "ArbreNdNoeud::f_load_id_ind ";
//Ptab_id_ind->affiche();
//cerr <<endl;	
	return (Ptab_id_ind);
}


void ArbreNdNoeud::set_force(float force) {
	_force = (int) force;
}

bool ArbreNdNoeud::est_racine() const {
	return(_racine);
}

ArbreNdNoeud::ArbreNdNoeud(Arbre * Parbre, ArbreNdNoeud * Pnoeud):ArbreNdBase(Parbre) {
	_force = 0;
	_accuvalboot = 0;
	if (Pnoeud == 0) {
		_racine = true;
		Parbre->set_Pracine(this);
	}
	else {
		_racine = false;
		_tabPNoeuds.resize(1);
		_tabLgBranches.resize(1);
		_tabPNoeuds[0] = Pnoeud;
		_tabLgBranches[0] = 0;
		Pnoeud->AjouterFils(this);
	}
}

ArbreNdNoeud::ArbreNdNoeud(Arbre * Parbre, unsigned int nbbranches):ArbreNdBase(Parbre) {
// création d'un noeud neutre (dont on ne connait pas encore le noeud père)
// avec 'nbbranches' branches
	unsigned int i;

	_force = 0;
	_accuvalboot = 0;
	_racine = false;
	_tabPNoeuds.resize(nbbranches);
	_tabLgBranches.resize(nbbranches);
	for (i=0; i < _tabP_tab_id_ind.size(); i++) delete _tabP_tab_id_ind[i];
//	_tabPNoeuds[0] = 0;
//	_tabLgBranches[0] = 0;
//	Pnoeud->AjouterFils(this);
}

ArbreNdNoeud::~ArbreNdNoeud() {};

unsigned int ArbreNdNoeud::get_nbbranches() const {
	if (_racine) return(_tabPNoeuds.size());
	else  return(_tabPNoeuds.size()-1);
}


ArbreNdOTU::ArbreNdOTU(Arbre * Parbre, ArbreNdNoeud * Pnoeud):ArbreNdBase(Parbre) {
	_tabPNoeuds.resize(1);
	_tabLgBranches.resize(1);
	_tabPNoeuds[0] = Pnoeud;
	_tabLgBranches[0] = 0;
	Pnoeud->AjouterFils(this);

//	_Parbre->AjouterIndividu(this);
}

ArbreNdOTU::ArbreNdOTU(Arbre * Parbre, const string & nom):ArbreNdBase(Parbre) {
	//création d'un individu orphelin de noeud
	_tabPNoeuds.resize(1);
	_tabLgBranches.resize(1);
	_tabPNoeuds[0] = 0;
	_tabLgBranches[0] = 0;
	set_nom(nom);
	set_reference(nom);
//	Pnoeud->AjouterFils(this);
//	_Parbre->AjouterIndividu(this);
}

ArbreNdOTU::~ArbreNdOTU() {
}

/*
bool ArbreNdOTU::operator== (const ArbreNdOTU &rval){
//cerr << "ArbreNdOTU::operator==" << endl;		
	return (_nom == rval._nom);
}
*/
void ArbreNdNoeud::AjouterFils(ArbreNdBase * Pnoeud) {
	_tabLgBranches.push_back(Pnoeud->get_tabLgBranches(0));
	_tabPNoeuds.push_back(Pnoeud);
}

void ArbreNdBase::set_longueur(unsigned int pos, float taille) {
	_tabLgBranches[pos] = taille;

//cerr << "ArbreNdBase::set_longueur" << endl;	
	if (_tabPNoeuds[pos] != 0) _tabPNoeuds[pos]->set_longueur(this,taille);
//cerr << "ArbreNdBase::set_longueur fin" << endl;	
	
}

void ArbreNdNoeud::set_longueur(unsigned int pos, float taille) {
	_tabLgBranches[pos] = taille;
	
//cerr << "ArbreNdNoeud::set_longueur debut" << endl1
	if (_tabPNoeuds[pos] != 0) {
		if ((_racine == true) && (pos == 0)) _tabPNoeuds[0]->set_longueur(this,taille);
		else if (pos > 0) _tabPNoeuds[pos]->set_longueur(this,taille);
	}
//cerr << "ArbreNdNoeud::set_longueur fin" << endl;	
	
}

void ArbreNdNoeud::oPhylipRec(ostream & fichier) const {
	//écriture d'arbres au format Phylip
	unsigned int i;
//	char car;
//cerr << "ArbreNdNoeud::oPhylipRec debut" << endl;

	fichier << "(";
	if (_racine) {
		_tabPNoeuds[0]->oPhylipRec(fichier);
		fichier << ",";
	}
	for (i=1; i < _tabPNoeuds.size(); i++) {
		if (i>1) fichier << ",";
		_tabPNoeuds[i]->oPhylipRec(fichier);
	}
	fichier << ")";
	if (_Parbre->get_oui_bootstrap() && _force != -999) fichier << _force;
	if ((_racine == false) && (_Parbre->get_oui_taille_branches())) {
		fichier << ":";
		fichier << _tabLgBranches[0];
//		if ((_tabLgBranches[0] < 1e-6) || (_tabLgBranches[0] < 0)) fichier << 0;
//		else fichier << _tabLgBranches[0];
	}
}

void ArbreNdOTU::oPhylipRec(ostream & fichier) const {
	//écriture d'arbres au format Phylip
	fichier << _nom;
	if ( _tabLgBranches[0]!=-999) fichier << ":" << _tabLgBranches[0];
}

void ArbreNdBase::set_longueur(ArbreNdBase * Pnoeudbase, float taille) {
	unsigned int i;

	for (i=0; i < _tabPNoeuds.size();i++) {
		if (Pnoeudbase == _tabPNoeuds[i]) _tabLgBranches[i] = taille;
	}
}

int ArbreNdBase::get_posnoeuds(ArbreNdNoeud * Pnoeud) const {
	unsigned int i;

	for (i=0; i < _tabPNoeuds.size();i++) {
		if (Pnoeud == _tabPNoeuds[i]) return ((int) i);
	}
	return (-1);
}


int Arbre::PositionInd(const char * nom_ind) const {
	unsigned int taille(_tabPind.size()),i;

	for (i = 0; i < taille; i++) {
//cerr << "Arbre::PositionInd " << endl;
//cerr << _tabPind[i]->get_nom_c_str() << "[" << endl;
//cerr << nom_ind << "[" << endl ;
		if ( strcmp(_tabPind[i]->get_reference(),nom_ind) == 0) return ((int)i);
	}

	string nom(nom_ind);
	for (i = 0; i < taille; i++) {
//cerr << "Arbre::PositionInd " << endl;
//cerr << _tabPind[i]->get_nom_c_str() << "[" << endl;
//cerr << nom_ind << "[" << endl ;
		if (_tabPind[i]->get_nom() == nom) return ((int)i);
	}

	return (-1);
}

void Arbre::AjBootstrap(Arbre & rval) {

//	if (!_ind_charge) f_load_vectind();
	if (!_ind_charge) f_load_vect_id_ind();
	if (!rval._ind_charge) rval.f_load_vect_id_ind();
//cerr << "Arbre::AjBootstrap" << endl;		
	unsigned int i,j, taille(_tabPnoeuds.size());

	bool * tab_dejatrouve;
	tab_dejatrouve = new bool[taille];
  for (i = 0; i < taille; i++) tab_dejatrouve[i] = false;

//cerr << "Arbre::AjBootstrap for debut" << endl;
	for (i = 0; i < taille; i++) {
//cerr << "Arbre::AjBootstrap for " << i << endl;
		for (j = 0; j < taille; j++) {
			if (!tab_dejatrouve[j]){
				if (*(_tabPnoeuds[i]) == *(rval._tabPnoeuds[j])) {
					_tabPnoeuds[i]->AjBootstrap();
					tab_dejatrouve[j] = true;
					break;
				}
			}
		}	
	}
//cerr << "Arbre::AjBootstrap fin" << endl;
	_cumulbootstrap++;
}

void Arbre::set_Pracine(ArbreNdNoeud * Pracine) {
	if (Pracine == 0) return;

	if (_Pracine == 0) {
		_Pracine = Pracine;
		return;
	}
	if (Pracine == _Pracine) return;
	// si il ya déjà un pointeur Pracine =>
	//   changement de racine de l'arbre
	ArbreNdNoeud * Pancien(_Pracine);
	_Pracine = Pracine;

	Pancien->set_racine(false);
	_Pracine->set_racine(true);
//cerr << "Arbre::set_Pracine" << endl;
	// réarrangement de l'arbre par propagation dans les noeuds
		
	_Pracine->f_chgt_racine(Pancien);
}

void Arbre::iFichier(istream & fichier) {
	_oui_taille_branches =  false;
	iPhylip(fichier);
	f_tri_ind_alpha();
}

void Arbre::iPhylip(istream & fichier) {
//lecture d'arbres au format Phylip

//cerr << "Arbre::iPhylip debut" << endl;
	char car;
	unsigned int i;

	car = fichier.peek();
	if (car == '[') {
		ChaineCar ligne;
		fichier.get(car);
		fichier.get(car);

		while (fichier.good() && (car != ']')) {
			ligne += car;
			fichier.get(car);		
		}
		if (fichier.fail()) throw Anomalie(100);
		else {
			unsigned int nblignes(ligne.GetNbMots("\\"));
			for (i=0; i < nblignes; i++) {
				_titre.push_back("");
				ligne.GetMot(i+1,_titre.back(),"\\");
			}
		}
		GetLigneFlot(fichier, ligne);
	}

	fichier.get(car);
	if (car != '(') throw Anomalie(100);
	iPhylipRec(fichier,0);

	f_tri_ind_alpha();
	for (i=0; i < _titre.size(); i++) {
		if (_titre[i].Position("#G") == 0) {
			//définition d'un groupe
			iPhylipDefGroupe(_titre[i]);
			_titre.Suppr(i);
			i--;
		}
	}

//cerr << "Arbre::iPhylip fin " << _oui_taille_branches << endl;

//	if (_tabPnoeuds.size() > 0) set_Pracine(_tabPnoeuds[0]);
}

void Arbre::oFichier(ostream & fichier, unsigned int format) const {
	if ((format == 0) || (format > 2)) format = _oFormat;

	switch (format) {
		case 1:
			oPhylip(fichier);
			break;
		case 2:
			oXML(fichier);
			break;

		default:
			oPhylip(fichier);
			break;
	}

}

void Arbre::oPhylip(ostream & fichier) const {
//lecture d'arbres au format Phylip
	unsigned int i;

	if (_titre.size() > 0) {
		fichier << "[";
		for (i=0; i < _titre.size() ; i++) {
			fichier << _titre[i];
			if (i != (_titre.size()-1)) fichier << "\\";
		}
		oPhylipEcritGroupes(fichier);
		fichier << "]" << endl;
	}
	else {
		oPhylipEcritGroupes(fichier);
	}
	_Pracine->oPhylipRec(fichier);

	fichier << ";" << endl;
}

void Arbre::iPhylipRec(istream & fichier, ArbreNdNoeud * Pnoeudracine) {
	char nomcar[50];
//	string individu;
	float force, taille;
	char car;
	ArbreNdNoeud * Pnoeud(new_ArbreNdNoeud(Pnoeudracine));


//	fichier.clear();

//	_tabPnoeuds.push_back(new ArbreNdNoeud(this, Pnoeudracine));
//	ArbreNdNoeud * Pnoeud(_tabPnoeuds.back());

	fichier.get(car);
	while (fichier.good()) {
//cerr << "Arbre::iPhylipRec deb " << car << endl;
		switch (car) {
		case ';': //fin de l'arbre
			return;
			break;

		case ')': //fin du noeud
		// force du noeud
		// taille de la branche mere
//			iPhylipRecPasser(fichier);
			force = iPhylipRecGetForce(fichier);
			taille = iPhylipRecGetTaille(fichier);
			Pnoeud->set_force(force);
			if (Pnoeud->est_racine() == false) Pnoeud->set_longueur(0, taille);
//			if ((taille == -999) && (Pnoeud.est_racine())) _taille_branches = false;
			if (force > 0) _oui_bootstrap = true;
			return;
			break;

		case '(': //nouveau noeud
			iPhylipRec(fichier, Pnoeud);
			break;
		case ',': //nouvelle branche
			break;
		case ' ': //rien
			break;
		case 13: //retour chariot CR
			break;
		case 9: //tabulation
			break;
		case 10: //LF Line Feed
			break;
		default: //branche terminale
//			_tabPind.push_back(new ArbreNdOTU(this, Pnoeud));
			//new ArbreNdOTU(this, Pnoeud);
			new_ArbreNdOTU(Pnoeud);
			nomcar[0] = car;
//cerr << "//branche terminale deb" << endl;
			i_PhylipRecGetNom(fichier, nomcar);
			_tabPind.back()->set_nom(nomcar);
			_tabPind.back()->set_reference(nomcar);
//			iPhylipRecPasser(fichier);
			taille = iPhylipRecGetTaille(fichier);
			_tabPind.back()->set_longueur((unsigned int) 0,taille);
			break;
		}
		fichier.get(car);
	}
	// traitement du noeud terminé
}

/*void Arbre::iPhylipRecPasser(istream & fichier) {
	char car;

	car = fichier.peek();
//	car = fichier[pos]; pos++;
	while ((((car > 47 ) && (car < 58)) || (car == '.') || (car == ':')) && fichier.good()) {
		fichier.get(car);
		car = fichier.peek();
	}
}
*/

float Arbre::iPhylipRecGetForce(istream & fichier) {
	char car;
	char temp[10]; //ATTENTION à la taille de temp !!!!!
	int i(0);

	car = fichier.peek();
//	car = fichier[pos]; pos++;

	while ((car == 13) || (car == 10) || (car == '\'')) {//passage du retour chariot
		fichier.get(car);
		car = fichier.peek();		
	}

	while (((car > 47 ) && (car < 58)) || (car == '.') && fichier.good() && (car != '\'')) {
		_oui_bootstrap = true;
		temp[i] = car;
		i++;
		fichier.get(car);
		car = fichier.peek();
	}
	temp[i] = '\0';
	if (car == '\'') {
		fichier.get(car);
		car = fichier.peek();
	}
	if (i == 0) return(-999);

	if (fichier.fail()) cerr << "Arbre::iPhylipRecGetForce fichier.fail()" << endl;
	
	return(atof(temp));
}

float Arbre::iPhylipRecGetTaille(istream & fichier) {
	char car;
	char temp[15]; //ATTENTION à la taille de temp !!!!!
	int i(0);
//	bool neg(false);
//cerr << "Arbre::iPhylipRecGetTaille" << endl;

	car = fichier.peek();
	while ((car == 13) || (car == 10)) {//passage du retour chariot
		fichier.get(car);
		car = fichier.peek();		
	}

	if (car == ':') {
		_oui_taille_branches = true;
		fichier.get(car);
		car = fichier.peek();
		if (car == '-') {
			fichier.get(car);
			temp[i] = car;
			i++;
			car = fichier.peek();
		}
		while ((((car > 47 ) && (car < 58)) || (car == '.') || (car == 'e'))) {
			if (car == 'e') {
				temp[i] = car;
				i++;
				fichier.get(car);
				car = fichier.peek();
				if (car == '-') {
					temp[i] = car;
					i++;
					fichier.get(car);
					car = fichier.peek();
				}
			}
			temp[i] = car;
			i++;
			fichier.get(car);
			car = fichier.peek();
		}
	}
//cerr << "Arbre::iPhylipRecGetTaille " << car << endl;
	temp[i] = '\0';
//	if (i == 0) _oui_taille_branches =  false;

	if (fichier.fail()) cerr << "Arbre::iPhylipRecGetTaille fichier.fail()" << endl;

//	return(0);
	return(atof(temp));
}

void Arbre::i_PhylipRecGetNom(istream & fichier, char * nom) {
//	string nom;
	char car;
	unsigned int i(1);

	car = fichier.peek();
	
	if (nom[0] == '\'') {
		i = 0;
//		nom[0] = car;
//		fichier.get(car);
//		car = fichier.peek();
	}
	while ((car != ':' ) && (car != ',' ) && (car != ')' ) && (car != '\'' )) {
		nom[i] = car;
		i++;
		fichier.get(car);
		car = fichier.peek();
	}
	if (car == '\'') {
		fichier.get(car);
		car = fichier.peek();
	}
	nom[i] = '\0';

//	if (fichier.fail()) cerr << "Arbre::i_PhylipRecGetNom fichier.fail()" << endl;

//	return(nom);
}

void Arbre::f_test() {

	set_Pracine(_tabPnoeuds[4]);
}

void Arbre::SquizNoeud(ArbreNdNoeud * Pndaeffacer) {
	//élimination d'un noeud à 1 branche

//	cerr << "Arbre::SquizNoeud" << endl;

	if (Pndaeffacer->get_nbbranches()!=1) {
		cerr << "erreur Arbre::SquizNoeud" << endl;
		return;
	}

	ArbreNdBase * Phaut;
	ArbreNdBase * Pbas;
	float longueur(0);
	int pos;
	unsigned int i;

	Phaut = Pndaeffacer->get_Pnoeud(0);
	Pbas = Pndaeffacer->get_Pnoeud(1);
	pos = Phaut->get_posnoeuds(Pndaeffacer);
	if (pos == -1) {
		cerr << "Erreur Arbre::SquizNoeud" << endl;
		return;
	}
//	cerr << "Arbre::SquizNoeud "<< longueur << endl;
	if (Phaut->get_tabLgBranches(pos) != -999) longueur = Phaut->get_tabLgBranches(pos);
//	cerr << "Arbre::SquizNoeud "<< longueur << endl;
	if (Pbas->get_tabLgBranches(0) != -999) longueur += Pbas->get_tabLgBranches(0);
	if ((Pbas->get_tabLgBranches(0) == -999) && (Phaut->get_tabLgBranches(pos) == -999))
		longueur = -999;
	Phaut->set_longueur(pos, longueur);
	Pbas->set_longueur((unsigned int)0, longueur);
	Phaut->set_Pnoeud(pos, Pbas);
	Pbas->set_Pnoeud(0, Phaut);
	
	for (i = 0; i < _tabPnoeuds.size(); i++) {
		if (_tabPnoeuds[i] == Pndaeffacer) _tabPnoeuds.erase(_tabPnoeuds.begin()+i);
	}

	delete Pndaeffacer;
}

bool ArbreNdNoeud::ExisteBranche(const ArbreVectUINT & tabInd) const {
  unsigned int i;

	for (i=0; i < _tabP_tab_id_ind.size(); i++) {
			if (tabInd == *(_tabP_tab_id_ind[i])) {
				return (true);
			}
	}
	
	return (false);	
}


ArbreNdNoeud * Arbre::RechercheNoeud(const ArbreVectUINT & tabInd) const {
  ArbreNdNoeud * Presultat(0);
  unsigned int i;

	for (i=0; i < _tabPnoeuds.size(); i++) {
			if (_tabPnoeuds[i]->ExisteBranche(tabInd)) {
				Presultat = _tabPnoeuds[i];
				break;
			}
	}
	
	return (Presultat);	
}

void Arbre::f_load_vect_id_ind() {
	//chargement du vecteur d'id d'individus
	//à partir de la racine, déclenche une fonction récursive de remplissage
//cerr << "Arbre::f_load_vect_id_ind debut" <<endl;	

//cerr << "Arbre::f_load_vectind " << endl;
	// chargement descendant
	_Pracine->f_load_id_ind();

	_ind_charge = true;
//cerr << "Arbre::f_load_vect_id_ind fin" <<endl;	
}

/*
void Arbre::f_load_vectind() {
	//chargement du vecteur de vecteurs de pointeurs d'individus
	//à partir de la racine, déclenche une fonction récursive de remplissage
	unsigned int i;
	unsigned int taille (_tabPind.size());
cerr << "Arbre::f_load_vectind debut" <<endl;	

//cerr << "Arbre::f_load_vectind " << endl;
	// chargement descendant
	_Pracine->f_load_vectind();
	// chargement ascendant
	for (i = 0; i < taille; i++) {
		_tabPind[i]->f_load_vectind_parent();
	}
	_ind_charge = true;
cerr << "Arbre::f_load_vectind fin" <<endl;	
}
*/

void Arbre::fCalcValBootstrap() {
	//calcul de la force des noeuds

	if (_cumulbootstrap != 0) _Pracine->fCalcValBootstrap(_cumulbootstrap);

	_oui_bootstrap = true;
}

void ArbreNdNoeud::fCalcValBootstrap(unsigned int total_bootstrap) {
	
	double resultat;

	if (modf ((((double) _accuvalboot / (double) total_bootstrap) * (double) 100),&resultat) > 0.5) {
		_force = (int)resultat + 1;
	}
	else _force = (int)resultat;

	unsigned int i;

	if (_racine) _tabPNoeuds[0]->fCalcValBootstrap(total_bootstrap);
	for (i=1; i < _tabPNoeuds.size();i++) {
		_tabPNoeuds[i]->fCalcValBootstrap(total_bootstrap);
	}
}

void Arbre::reset() {
//remise à zéro de l'arbre
	//destruction des noeuds et individus
	unsigned int i;

	for (i=0; i < _tabPind.size(); i++) delete _tabPind[i];
	for (i=0; i < _tabPnoeuds.size(); i++) delete _tabPnoeuds[i];
  _tabPind.resize(0);
  _tabPnoeuds.resize(0);

	_ind_charge = false;
	_oui_taille_branches = false;
	_oui_bootstrap = false;
	_cumulbootstrap = 0;
	_Pracine = 0;
}

void Arbre::iNeighborJoining(Matrice & distances) {
//cerr << "nj" << endl;
	//pour accelerer le traitement des bootstrap:
//	if (_PtabPnoeud == 0) _PtabPnoeud = new vector<Noeud *>;
//	else _PtabPnoeud->resize(0);
	reset();
//cerr << "Arbre::iNeighborJoining debut "  << distances.GetType() << endl;

	bool *etatMat;
//	Vecteur<Branche *> tabPbranches;
	vector<ArbreNdBase *> tabPNoeuds;
	long nblignemat;
	long taille(distances.GetNL());
	long i, j, pos1(0), pos2(0), pos3, id, jd, refi, refj;
	long double sumbr1, sumbr2;
	long double comparer;
	long double critere;
	long double * Ptab(distances._tab);
	vector<long double> accDistances;
	long double distance;


	ArbreNdNoeud * Pnoeud;

	if (distances.GetType() != 2) throw Anomalie(4);

//cerr << "Arbre::iNeighborJoining debut 2" << endl;
	if (taille < 3) throw Anomalie(5);

	for (i = 0; i < taille; i++) {
		for (j = 0; j < i; j++) {
			if (distances.GetCase(i,j) < 0) throw Anomalie(6);
		}
	}
//cerr << "Arbre::iNeighborJoining debut3" << endl;

	etatMat = new bool[taille];
//	tabPbranches.resize(taille);
	tabPNoeuds.resize(taille);
//	_tabPotu.resize(taille);
	accDistances.resize(taille);

	for (i=0; i < taille ; i++) {
		etatMat[i] = true;
//		cerr << distances._tlig[i] << endl;
//		_tabPotu[i] = new Otu(distances._tlig[i]);
//		_tabPind[i] = new ArbreNdOTU(this, distances._tlig[i]);
//		tabPNoeuds[i] = _tabPind[i];
		tabPNoeuds[i] = new_ArbreNdOTU(distances._tlig[i]);
//		tabPNoeuds[i] = new ArbreNdOTU(this, distances._tlig[i]);
//		tabPbranches[i] = new Branche(this, _tabPotu[i]);
	}

	nblignemat = taille;

	while (nblignemat > 3) {
//cerr << "Arbre::iNeighborJoining Critere Q debut" << endl;
		comparer = 9999999;
		for (i = 1; i < taille; i++) {
			if (etatMat[i]) {
				for (j = 0;  j < i; j++) {
					if (etatMat[j]) {
						for (critere = 0, refj = (j * taille), refi = (i * taille),id = 0; id < taille; id++, refi++, refj++) {
							if (etatMat[id]) {
								if (id != i) critere += *(Ptab + refi);
											
								if (id != j) critere += *(Ptab + refj);
							}
						}
						critere = ((nblignemat - 2) * *(Ptab + ((i * taille) + j))) - critere;

						//recherche du couple ou la distance est minimum
						if (comparer > critere) {
							comparer = critere;
							pos1 = j;
							pos2 = i;
						}
					}
				}
			}
		}
	// ----- Critere Q Fin ----

//cerr << "Arbre::iNeighborJoining Critere Q fin" << endl;

		//--------------calcul des longueurs de branches
		distance = Ptab[(pos1 * taille) + pos2];
		sumbr1 = 0;
		sumbr2 = 0;
		for (i = 0; i < taille; i ++) {
			if ((etatMat[i]) && (i != pos1) && (i != pos2)) {
				sumbr1 += Ptab[(pos1 * taille) + i];
				sumbr2 += Ptab[(pos2 * taille) + i];
			}
		}
		sumbr1 /= (nblignemat - 2);
		sumbr2 /= (nblignemat - 2);

		tabPNoeuds[pos1]->set_longueur((unsigned int)0,((distance + sumbr1 - sumbr2) /2) - accDistances[pos1]);
//cerr << "Arbre::iNeighborJoining set_longueur" << endl;
		//tabPbranches[pos1]->_taille = (distance + sumbr1 - sumbr2) /2;
		tabPNoeuds[pos2]->set_longueur((unsigned int)0,((distance + sumbr2 - sumbr1) /2) - accDistances[pos2]);
		//tabPbranches[pos2]->_taille = (distance + sumbr2 - sumbr1) /2;

		accDistances[pos1] = (distance / 2);
		//------------fin du calcul des longueurs de branches

		//grouper les branches dans un Noeud
		//creer une nouvelle Branche

//		Pnoeud = new Noeud(new Branche(this));
		Pnoeud =  new_ArbreNdNoeud((unsigned int) 1);
		//pour accelerer le traitement des bootstrap:
//		_PtabPnoeud->push_back(Pnoeud);
//		_tabPnoeuds.push_back(Pnoeud);

//		Pnoeud->_tabPbranche.resize(2);
//		Pnoeud->_tabPbranche[0] = tabPbranches[pos1];
//		Pnoeud->_tabPbranche[1] = tabPbranches[pos2];
//cerr << "Arbre::iNeighborJoining AjouterFils" << endl;
		Pnoeud->AjouterFils(tabPNoeuds[pos1]);
		tabPNoeuds[pos1]->set_Pnoeud(0,Pnoeud);
		Pnoeud->AjouterFils(tabPNoeuds[pos2]);
		tabPNoeuds[pos2]->set_Pnoeud(0,Pnoeud);
		
		
//		tabPbranches[pos1] = Pnoeud->_PbrMere;
//		tabPbranches[pos1]->_type = 1;
		tabPNoeuds[pos1] = Pnoeud;
		etatMat[pos2] = false;
		nblignemat--;

		//recalculer les distances
		jd = pos1; //colonne pos1
		id = (pos1 * taille); //ligne pos1
		for (i = 0; i < taille; i ++,id ++,jd += taille) {
			if ((etatMat[i]) && (i != pos1)) {
//				distances.GetCase(pos1,i) = (distances.GetCase(pos1,i) + distances.GetCase(pos2,i)) / 2;
				Ptab[id] += Ptab[(pos2 * taille) + i];
				Ptab[id] /= (long double) 2;
				Ptab[jd] = Ptab[id];
			}
		}
//cerr << "+" << endl;

	}

	pos2 = pos3 = -1;
	for (i = 0; i < taille; i++) {
		if ((etatMat[i]) && (i != pos1)) {
			if (pos2 < 0) pos2 = i;
			else if (pos3 < 0) pos3 = i;
	//		else pos3 = i;
		}
	}

//	_PndRoot = 	new Noeud(new Branche(this));
//cerr << "Arbre::iNeighborJoining racine" << endl;
	_Pracine = new_ArbreNdNoeud();
	//pour accelerer le traitement des bootstrap:
//	_PtabPnoeud->push_back(_PndRoot);
//	_tabPnoeuds.push_back(_Pracine);

	_Pracine->AjouterFils(tabPNoeuds[pos1]);
	_Pracine->AjouterFils(tabPNoeuds[pos2]);
	_Pracine->AjouterFils(tabPNoeuds[pos3]);
	tabPNoeuds[pos1]->set_Pnoeud(0,_Pracine);
	tabPNoeuds[pos2]->set_Pnoeud(0,_Pracine);
	tabPNoeuds[pos3]->set_Pnoeud(0,_Pracine);

	_Pracine->set_longueur(0,((Ptab[(pos2 * taille) + pos1] + Ptab[(pos3 * taille) + pos1] - Ptab[(pos3 * taille) + pos2]) /2) - accDistances[pos1]);
	_Pracine->set_longueur(1,((Ptab[(pos1 * taille) + pos2] + Ptab[(pos3 * taille) + pos2] - Ptab[(pos3 * taille) + pos1]) /2) - accDistances[pos2]);
	_Pracine->set_longueur(2,((Ptab[(pos1 * taille) + pos3] + Ptab[(pos2 * taille) + pos3] - Ptab[(pos1 * taille) + pos2]) /2) - accDistances[pos3]);

	delete[] etatMat;

	_oui_bootstrap = false;
	_oui_taille_branches = true;
	//_construction = 2;
}

void Arbre::iUPGMA(Matrice & distances) {
	reset();

	Vecteur<int> etatMat;
	vector<long double> accDistances;
	Vecteur<ArbreNdBase *> tabPNoeuds;
	long taille(distances.GetNL());
	long i, j, pos1(0), pos2(0);
	long double comparer;
	ArbreNdNoeud * Pnoeud(0);

	if (distances.GetType() != 2) throw Anomalie(4);

	if (taille < 2) throw Anomalie(5);

	for (i = 0; i < taille; i++) {
		for (j = 0; j < i; j++) {
			if (distances.GetCase(i,j) < 0) throw Anomalie(6);
		}
	}

	etatMat.resize(taille);
	accDistances.resize(taille);

	tabPNoeuds.resize(taille);

	for (i=0; i < taille ; i++) {
		accDistances[i] = 0;
		etatMat[i] = 1;

		tabPNoeuds[i] = new_ArbreNdOTU(distances._tlig[i]);
	}

	while (etatMat.getNbOccurence(1) > 1) {
		//trouver la + courte distance
		comparer = -1;
		for (i = 1; i < taille; i++) {
			for (j = 0;  j < i; j++) {
				if ((etatMat[i] == 1)&&(etatMat[j] == 1)) {
					if (comparer == -1) {
						comparer = distances.GetCase(i,j);
						pos1 = j;
						pos2 = i;
					}
					else {
						if (comparer > distances.GetCase(i,j)) {
							comparer = distances.GetCase(i,j);
							pos1 = j;
							pos2 = i;
						}
					}
				}
			}
		}
		//grouper les branches dans un Noeud
		Pnoeud =  new_ArbreNdNoeud((unsigned int) 1);
		Pnoeud->AjouterFils(tabPNoeuds[pos1]);
		tabPNoeuds[pos1]->set_Pnoeud(0,Pnoeud);
		Pnoeud->AjouterFils(tabPNoeuds[pos2]);
		tabPNoeuds[pos2]->set_Pnoeud(0,Pnoeud);



		tabPNoeuds[pos1]->set_longueur((unsigned int)0,(comparer/2) - accDistances[pos1]);
		tabPNoeuds[pos2]->set_longueur((unsigned int)0,(comparer/2) - accDistances[pos2]);
		accDistances[pos1] = (comparer/2);

		tabPNoeuds[pos1] = Pnoeud;
		etatMat[pos2] = 0;

		//recalculer les distances
		for (i = 0; i < taille; i ++) {
			if ((etatMat[i] == 1 ) && (i != pos1)) {
				distances.GetCase(pos1,i) = (distances.GetCase(pos1,i) + distances.GetCase(pos2,i))/2;
			}
		}

	}

	_Pracine = Pnoeud;
	_oui_bootstrap = false;
	_oui_taille_branches = true;
}

void Arbre::iNeighborJoiningTopo(Matrice & distances) {
	reset();
//cerr << "Arbre::iNeighborJoiningTopo debut" << endl;

	bool *etatMat;
	vector<ArbreNdBase *> tabPNoeuds;
	long nblignemat;
	long taille(distances.GetNL());
	long i, j, pos1(0), pos2(0), pos3, id, jd, refi, refj;
	long double comparer;
	long double critere;
	long double * Ptab(distances._tab);
	vector<long double> accDistances;


	ArbreNdNoeud * Pnoeud;

	if (distances.GetType() != 2) throw Anomalie(4);

	if (taille < 3) throw Anomalie(5);

	for (i = 0; i < (taille * taille); i++) {
		if (Ptab[i] < 0) throw Anomalie(6);
	}
/*	for (i = 0; i < taille; i++) {
		for (j = 0; j < i; j++) {
			if (distances.GetCase(i,j) < 0) throw Anomalie(6);
		}
	}
*/
	etatMat = new bool[taille];
	tabPNoeuds.resize(taille);
	accDistances.resize(taille);

	for (i=0; i < taille ; i++) {
		etatMat[i] = true;
		tabPNoeuds[i] = new_ArbreNdOTU(distances._tlig[i]);
	}

	nblignemat = taille;

	while (nblignemat > 3) {
//cerr << "Arbre::iNeighborJoiningTopo Critere Q debut" << endl;
		comparer = 9999999;
		for (i = 1; i < taille; i++) {
			if (etatMat[i]) {
				for (j = 0;  j < i; j++) {
					if (etatMat[j]) {
						for (critere = 0, refj = (j * taille), refi = (i * taille),id = 0; id < taille; id++, refi++, refj++) {
							if (etatMat[id]) {
								if (id != i) critere += *(Ptab + refi);
											
								if (id != j) critere += *(Ptab + refj);
							}
						}
						critere = ((nblignemat - 2) * *(Ptab + ((i * taille) + j))) - critere;

						//recherche du couple ou la distance est minimum
						if (comparer > critere) {
							comparer = critere;
							pos1 = j;
							pos2 = i;
						}
					}
				}
			}
		}
	// ----- Critere Q Fin ----

//cerr << "Arbre::iNeighborJoining Critere Q fin" << endl;

		//grouper les branches dans un Noeud
		//creer une nouvelle Branche

//		Pnoeud = new Noeud(new Branche(this));
		Pnoeud =  new_ArbreNdNoeud((unsigned int) 1);
		Pnoeud->AjouterFils(tabPNoeuds[pos1]);
		tabPNoeuds[pos1]->set_Pnoeud(0,Pnoeud);
		Pnoeud->AjouterFils(tabPNoeuds[pos2]);
		tabPNoeuds[pos2]->set_Pnoeud(0,Pnoeud);
		
		
		tabPNoeuds[pos1] = Pnoeud;
		etatMat[pos2] = false;
		nblignemat--;

		//recalculer les distances
		jd = pos1; //colonne pos1
		id = (pos1 * taille); //ligne pos1
		for (i = 0; i < taille; i ++,id ++,jd += taille) {
			if ((etatMat[i]) && (i != pos1)) {
				Ptab[id] += Ptab[(pos2 * taille) + i];
				Ptab[id] /= (long double) 2;
				Ptab[jd] = Ptab[id];
			}
		}
//cerr << "+" << endl;

	}

	pos2 = pos3 = -1;
	for (i = 0; i < taille; i++) {
		if ((etatMat[i]) && (i != pos1)) {
			if (pos2 < 0) pos2 = i;
			else if (pos3 < 0) pos3 = i;
	//		else pos3 = i;
		}
	}

//	_PndRoot = 	new Noeud(new Branche(this));
//cerr << "Arbre::iNeighborJoining racine" << endl;
	_Pracine = new_ArbreNdNoeud();

	_Pracine->AjouterFils(tabPNoeuds[pos1]);
	_Pracine->AjouterFils(tabPNoeuds[pos2]);
	_Pracine->AjouterFils(tabPNoeuds[pos3]);
	tabPNoeuds[pos1]->set_Pnoeud(0,_Pracine);
	tabPNoeuds[pos2]->set_Pnoeud(0,_Pracine);
	tabPNoeuds[pos3]->set_Pnoeud(0,_Pracine);


	delete[] etatMat;

	_oui_bootstrap = false;
	_oui_taille_branches = false;
	//_construction = 2;
}

double ArbreNdOTU::get_longueur_max()const {
	if (get_longueur_branche() < 0) return (0);
	else return (get_longueur_branche());
}

unsigned int ArbreNdOTU::get_nbnoeuds_max()const {
	return (1);
}


void Arbre::f_tri_ind_alpha() {

	unsigned int i;
	
//cerr << "Arbre::f_tri_ind_alpha debut " << _tabPind.size() << endl;
	if (_tabPind.size() < 2) return;

	//f_tribulle_ind_alpha();
	sort (_tabPind.begin(),_tabPind.end(),moins<ArbreNdOTU *> ());
/*	if (_tabPind.size() < 4) f_tribulle_ind_alpha();
//	if (size() < 4) return;	
	else f_trishell_ind_alpha(0, _tabPind.size()-1);
//cerr << "Arbre::f_tri_ind_alpha num"<< endl;
*/
	for (i=0; i < _tabPind.size(); i++) {
		_tabPind[i]->set_id(i);

//cerr << _tabPind[i]->get_nom_c_str() << endl;
	}
//cerr << "Arbre::f_tri_ind_alpha fin"<< endl;
}


void Arbre::f_tribulle_ind_alpha() {
	unsigned int ok,i;
	ArbreNdOTU * swap;
	unsigned int n(_tabPind.size());

	do{
		ok=1;
		for(i=1;i<n;i++) if (strcmp(_tabPind[i-1]->get_reference(), _tabPind[i]->get_reference()) > 0) {
			ok=0;
			swap = _tabPind[i];
			_tabPind[i] = _tabPind[i-1];
			_tabPind[i-1] = swap;
		}
	}while(!ok);
}

void Arbre::f_trishell_ind_alpha(unsigned int lb, unsigned int ub) {
	//tri de _tabPind en fonction du nom des individus
	//T *a,
	unsigned int n, h, i, j;
//	unsigned int t;
	ArbreNdOTU * Pswap;

   /**************************
    *  sort array a[lb..ub]  *
    **************************/
//cerr << "Arbre::f_trishell_ind_alpha debut "<< lb << " " << ub << endl;

    /* compute largest increment */
	n = ub - lb + 1;
	h = 1;
	if (n < 14) h = 1;
//    else if (sizeof(unsigned int) == 2 && n > 29524)
 //       h = 3280;
	else {
		while (h < n) h = 3*h + 1;
		h /= 3;
		h /= 3;
	}

	while (h > 0) {

        /* sort-by-insertion in increments of h */
		for (i = lb + h; i <= ub; i++) {
//cerr << "Arbre::f_trishell_ind_alpha i "<< i << endl;
			Pswap = _tabPind[i];
//cerr << "Arbre::f_trishell_ind_alpha ok " << endl;
//cerr << "i-h " << (i-h) << endl;
			for (j = i-h; ((j >= lb) && (strcmp(_tabPind[j]->get_reference(), Pswap->get_reference()) > 0)); j -= h)
				_tabPind[j+h] = _tabPind[j];
			_tabPind[j+h] = Pswap;
		}

        /* compute next increment */
		h /= 3;
	}
//cerr << "Arbre::f_trishell_ind_alpha fin "<< lb << " " << ub << endl;
}

void ArbreVectUINT::f_tri() {
	//tri du vecteur
	sort(begin(), end(), less<unsigned int>());
	//return;
	//vector<unsigned int>::sort();
	//return;
//cerr << "ArbreVectUINT::f_tri debut " << endl;
	//if (size() < 2) return;
	//if (size() == 2) {
	//	unsigned int swap;
	//	if (operator[](0) > operator[](1)) {
	//		swap = operator[](0);
	//		operator[](0) = operator[](1);
	//		operator[](1) = swap;
	//	}
	//	return;
	//}
	//if (size() == 3) f_tribulle();
//	if (size() < 4) return;	
	//else f_tribulle();
//	else f_trishell(0,size()-1);
//cerr << "ArbreVectUINT::f_tri fin " << endl;
}


void ArbreVectUINT::f_tribulle() {
	unsigned int ok,i, swap;
	unsigned int n(size());

	do{
		ok=1;
		for(i=1;i<n;i++) if (operator[](i-1)>operator[](i)) {
			ok=0;
			swap = operator[](i-1);
			operator[](i-1) = operator[](i);
			operator[](i) = swap;
		}
	} while(!ok);
}

void ArbreVectUINT::f_trishell(unsigned int lb, unsigned int ub) {
	//T *a,
	unsigned int n, h, i, j;
	unsigned int t;

   /**************************
    *  sort array a[lb..ub]  *
    **************************/

    /* compute largest increment */
    n = ub - lb + 1;
    h = 1;
    if (n < 14)
        h = 1;
//    else if (sizeof(unsigned int) == 2 && n > 29524)
 //       h = 3280;
    else {
        while (h < n) h = 3*h + 1;
        h /= 3;
        h /= 3;
    }

    while (h > 0) {

        /* sort-by-insertion in increments of h */
        for (i = lb + h; i <= ub; i++) {
            t = operator[](i);
//            for (j = i-h; j >= lb && compGT(operator[](j), t); j -= h)
            for (j = i-h; ((j >= lb) && (operator[](j)> t)); j -= h)
                operator[](j+h) = operator[](j);
            operator[](j+h) = t;
        }

        /* compute next increment */
        h /= 3;
    }
}

bool ArbreVectUINT::operator== (const ArbreVectUINT &rval) {
	//=>remplir les vecteurs avant
//cerr << "ArbreNdNoeud::operator==" << endl;		
	unsigned int i, taille (size());
	
	if (taille != rval.size()) return (false);

	for (i = 0; i < taille; i ++) {
  	if (operator[](i) != rval[i]) return (false); 	
	}	
  return (true);
}

void ArbreVectUINT::affiche() const {

	string affichage;
	unsigned int i, taille (size());

	for (i = 0; i < taille; i ++) {
		cout << " " << operator[](i);
	}	
	
}

void Arbre::iDistances(MatriceLD & matrice) {
	iNeighborJoining(matrice);
//	f_tri_ind_alpha();
}

void Arbre::iDistances(MatriceLD & distances, int methode) {
//reconstruction d'arbres a partir d'une matrice de distances:
	// int -> methode de reconstruction
		// 1 -> UPGMA	
		// 2 -> Neighbor Joining	
	//on efface l'arbre si il yen a deja un
//cerr << "Arbre::iDistances(MatriceLD & distances, int methode) debut" << endl;
	reset();

	switch (methode) {
	case 1: // UPGMA
			 iUPGMA(distances);
			 break;
	case 101: // UPGMA, topologie seulement
			 iUPGMA(distances);
			 break;
	case 2: // Neighbor Joining
			 iNeighborJoining(distances);
			 break;
	case 102: // Neighbor Joining, topologie seulement
			 iNeighborJoiningTopo(distances);
			 break;
	}
//cerr << "Arbre::iDistances(MatriceLD & distances, int methode) tri" << endl;
//	f_tri_ind_alpha();
}

void Arbre::f_forceiDistances(MatriceLD & distancesRef,int methodeArbre) {
	bool continuer(true);

	while (continuer) {
		try {
			continuer = false;
			iDistances(distancesRef,methodeArbre);
		}
		catch (Anomalie pb) {
			cout << _("Error while building tree...") << endl;
			switch (pb.le_pb) {
				case 4:
					cout << _("Inconsistant matrix file format") << endl;
					throw Anomalie(4);					
					break;
				case 5:
					cout << _("the matrix is too small") << endl;
					throw Anomalie(5);					
					break;
				case 6:
					cout << _("Negative distances in the matrix...") << endl;
					cout << _("the smallest value is: ") << distancesRef.get_ppvaleur() << endl;
					cout << _("all negative values are replaced by zero to proceed") << endl;
					distancesRef.f_neg2zero();
					continuer = true;
					break;
				default:
					throw Anomalie(pb.le_pb);
					break;
			}
		}
	}
}

void Arbre::iNimbus(unsigned int nbessais , unsigned int nbind, unsigned int * Ptemp, char * * PPotu) {
	unsigned int i, j;
	ChaineCar nom;
	MatriceLD tab_nimbus(nbind, nbessais) ;
	unsigned int * Puint(Ptemp);
//cerr << "Arbre::iNimbus debut"  << endl;
//	Visu.reset((long unsigned int) nbind, (long unsigned int) nbessais);
	for (i=0; i < nbind ; i++) {
		tab_nimbus._tlig[i].assign(PPotu[i]);
		for (j=0; j < nbessais ; j++) {
			tab_nimbus.GetCase(i, j) = *Puint;
			Puint++;
		}
	}
	tab_nimbus.SetFlag(1);
//	tab_nimbus.oExcel(cerr);

	reset();

	for (i=0; i < nbind ; i++) {
		new_ArbreNdOTU("");
		_tabPind[i]->set_nom(tab_nimbus._tlig[i]);
	}

	_Pracine = new_ArbreNdNoeud();

	iNimbusRec(_Pracine, tab_nimbus, 0, 0, nbind);

	_Pracine->AjouterFils(new_ArbreNdOTU(""));
	_tabPind.back()->set_nom("____");
	_tabPind.back()->set_longueur((unsigned int) 0, (float) nbessais);

	_oui_bootstrap = false;
	_oui_taille_branches = true;

//cerr << "Arbre::iNimbus fin " << _tabPind.size() << endl;

}

void Arbre::iNimbusRec(ArbreNdNoeud * Pnoeud, MatriceLD & tab_nimbus, unsigned int numessai, unsigned int deb, unsigned int fin, unsigned int longueur) {
// pos: position en nb d'essais
	// branche regroupant les otus de 'deb' a 'fin'
	unsigned int i, nbessais(tab_nimbus.GetNC());
	unsigned int pos;
//  ArbreNdNoeud * Pnoeud (_tabPnoeud.back());

//cerr << "Arbre::iNimbusRec debut"  << endl;
	if ((numessai >= nbessais)&&(numessai != 0)) { //dernière colonne
//cerr << "Arbre::iNimbusRec derniere col numessai " << numessai  << endl;
		Pnoeud->AjouterFils(new_ArbreNdNoeud((unsigned int) 1));
//cerr << "coucou1 " << Pnoeud->get_nbbranches() << endl;
//		PPnoeudnov = _tabPnoeuds.back();
//cerr << "coucou2 nbb " << _tabPnoeuds.back()->get_nbbranches() << endl;
		_tabPnoeuds.back()->set_longueur(0, longueur);
//cerr << "coucou3" << endl;
//cerr << "Arbre::iNimbusRec dernier deb " << _tabPind[deb]->get_nom() << endl;
			_tabPnoeuds.back()->AjouterFils(_tabPind[deb]);
			_tabPind[deb]->set_longueur((unsigned int) 0, 0.25);
		for (i = deb+1; i < fin; i++) {
//cerr << "coucou4" << endl;
//cerr << "Arbre::iNimbusRec dernier " << _tabPind[i]->get_nom() << endl;
			_tabPnoeuds.back()->AjouterFils(_tabPind[i]);
			_tabPind[i]->set_longueur((unsigned int) 0, 0.25);
		}
		return;
	}

	if ((fin - deb) == 1) {
//cerr << "Arbre::iNimbusRec one " << _tabPind[deb]->get_nom() << endl;
		// branche terminale
		Pnoeud->AjouterFils(_tabPind[deb]);
		_tabPind[deb]->set_longueur((unsigned int) 0, nbessais - numessai);
		return;
	}

	for (pos = numessai; pos < nbessais; pos ++) {

//cerr << "Arbre::iNimbusRec pos "<< pos << " numessai " << numessai  << endl;
		for (i = deb+1; i < fin; i ++) {
			if (tab_nimbus.GetCase(i-1, pos) != tab_nimbus.GetCase(i, pos)) {
				//nouveau noeud
				Pnoeud->AjouterFils(new_ArbreNdNoeud((unsigned int) 1));
				Pnoeud = _tabPnoeuds.back();
				Pnoeud->set_longueur(0, pos-numessai);
				iNimbusRec(Pnoeud, tab_nimbus, pos, deb,i,pos-numessai);
				//les autres
				deb = i;
				i++;
				while (i < fin) {
          if (tab_nimbus.GetCase(i-1, pos) != tab_nimbus.GetCase(i, pos)){
						iNimbusRec(Pnoeud, tab_nimbus, pos, deb,i,pos-numessai);
						deb = i;
					}
					i ++;
				}
				iNimbusRec(Pnoeud, tab_nimbus, pos, deb,fin,pos-numessai);
				return;
			}

		}

	}

	iNimbusRec(Pnoeud, tab_nimbus, pos, deb,fin,pos-numessai);
}

void Arbre::operator>>(ostream& sortie) {
	switch (_oFormat) {
		case 1:
			oPhylip(sortie);
			break;
		default:
			oPhylip(sortie);
			break;
	}
}

const ArbreNdOTU * Arbre::RecherchePOTU(unsigned int id) const {

	unsigned int i;

	for (i=0 ; i < _tabPind.size(); i++) {
		if (_tabPind[i]->get_id() == id) return(_tabPind[i]);
	}
	return (0);
}

void ArbreNdOTU::set_nom(const string & nom) {
	//a faire : vérifier l'unicité du nom
	_nom.assign(nom);
}

void Arbre::oXML(ostream & fichier) const {
//écriture d'arbres au format XML
/*
<!ELEMENT trees (tree+)>
<!ELEMENT tree (comments?,branch,branch,branch?,length?)>
<!ELEMENT branch (node,length?)>
<!ELEMENT node ((branch,branch)|specie)>
<!ELEMENT length (#PCDATA)>
<!ELEMENT specie (#PCDATA)>

*/
  fichier << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" << endl;
  fichier << "<!DOCTYPE trees SYSTEM \"treefile.dtd\">" << endl;
  fichier << "<!--  " << endl;
  fichier << "created by biolib library" << endl;
  fichier << "Olivier Langella <Olivier.Langella@pge.cnrs-gif.fr>" << endl;
  fichier << "http://www.pge.cnrs-gif.fr/bioinfo" << endl;
  fichier << "-->" << endl;

  fichier << "<trees>" << endl;
  fichier << "<tree>" << endl;
	unsigned int i;

	if (_titre.size() > 0) {
		fichier << "<comments>" << endl;
		for (i=0; i < _titre.size() ; i++) {
			fichier << _titre[i];
		}
		//oPhylipEcritGroupes(fichier);
		fichier << "</comments>" << endl;
	}

	_Pracine->oXML(fichier);

  fichier << "</tree>" << endl;
  fichier << "</trees>" << endl;
}


void ArbreNdNoeud::oXML(ostream & fichier) const {
	//écriture d'arbres au format Phylip
	unsigned int i;
//	char car;
//cerr << "ArbreNdNoeud::oPhylipRec debut" << endl;

	if (_racine) {
  	fichier << "<branch>" << endl;
		_tabPNoeuds[0]->oXML(fichier);
  	fichier << "</branch>" << endl;
	}
  else fichier << "<node>" << endl;

	for (i=1; i < _tabPNoeuds.size(); i++) {
  	fichier << "<branch>" << endl;
		_tabPNoeuds[i]->oXML(fichier);
	  fichier << "</branch>" << endl;
	}
  if (!(_racine)) fichier << "</node>" << endl;
	if (_Parbre->get_oui_bootstrap() && _force != -999) {
	  fichier << "<force>" << endl;
    fichier << _force;
	  fichier << "<force>" << endl;
  }
	if ((_racine == false) && (_Parbre->get_oui_taille_branches())) {
	  fichier << "<length>" << endl;
		fichier << _tabLgBranches[0] << endl;
	  fichier << "</length>" << endl;
//		if ((_tabLgBranches[0] < 1e-6) || (_tabLgBranches[0] < 0)) fichier << 0;
//		else fichier << _tabLgBranches[0];
	}

}

void ArbreNdOTU::oXML(ostream & fichier) const {
	//écriture d'arbres au format Phylip
//	char car;
//cerr << "ArbreNdNoeud::oPhylipRec debut" << endl;

  fichier << "<branch>" << endl;
  fichier << "<species>" << endl;
  fichier << get_nom() << endl;
  fichier << "</species>" << endl;
	if (_Parbre->get_oui_taille_branches()) {
	  fichier << "<length>" << endl;
		fichier << _tabLgBranches[0] << endl;
	  fichier << "</length>" << endl;
	}
  fichier << "</branch>" << endl;
}

} //namespace biolib {
} //namespace arbres {

