
/***************************************************************************
                          distgnt.h  -  Librairie d'objets permettant de manipuler
                          des distances entre populations
                             -------------------
    begin                : ven sep 01 10:25:55 CEST 2000
    copyright            : (C) 2000 by Olivier Langella CNRS UPR9034
    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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef DISTGNT_H
#define DISTGNT_H

#include <cmath>
//#include<map>
#include <time.h>

#include "matrices.h"
#include "jeupop.h"
//class Arbre;

// calculs de distances génétiques
class DistancesGnt {
public :
	static const string & get_nom_methode(unsigned int methode);
	static unsigned int get_nb_methodes();

	DistancesGnt(int methode, bool square_distance, Jeupop * Pjeupop, unsigned int niveau=100);
	~DistancesGnt();

	unsigned long get_nbind() const;


private :
	static void f_rempli_tab_noms_methodes();

	void f_distgntpop (MatriceLD &resultat, Vecteur<unsigned int> *PVcalcLocus);
	void f_distgntInd (MatriceLD &resultat, Vecteur<unsigned int> *PVcalcLocus);
	void f_distgntpopDas(long double * Ptab) const;
	void f_distgntpopVcalc(long double * Ptab) const;
	void f_distgntIndVcalc (long double * Ptab) const;
	void f_bootstrapIndividus(Arbre &arbreRef, int methodeArbre, unsigned int nbrepet, Vecteur<unsigned int> * PVcalcLocusRef);
	void f_bootstrapLocus(Arbre &arbreRef, int methodeArbre, unsigned int nbrepet, Vecteur<unsigned int> * PVcalcLocus, bool sur_ind);
	long double r_dist2pop(unsigned long pop1, unsigned long pop2) const;
	long double r_dist2ind(unsigned long nbind1, unsigned long nbind2) const;
	long double r_dist2ind(Individu* Pind1, Individu* Pind2) const;
	long double r_allsimilnul(Individu * pind1, Individu * pind2) const;
	long double r_distDasPsAi(unsigned long nbind1, unsigned long nbind2) const;
	long double r_distDasPsAi(const Individu * Pind1, const Individu * Pind2) const;
	long double r_distDasMoyPsAB(const StrucPop * Ppop1, const StrucPop * Ppop2) const;
	long double r_distDasMoyPsA(const StrucPop * Ppop) const;

	long double r_dpopCavalli(unsigned long pop1, unsigned long pop2) const;
	long double r_dpopFst(unsigned long pop1,unsigned long pop2) const;
//	long double r_dpopFstClassique(long double ** tabfreq1,long double ** tabfreq2) const;
	long double r_dpopGoldsteinASD(unsigned long pop1,unsigned long pop2) const;
	long double r_dpopGoldsteinMu(unsigned long pop1,unsigned long pop2) const;
	long double r_dpopNei(unsigned long pop1,unsigned long pop2, bool standard) const;
	long double r_dpopNeiDa(unsigned long pop1,unsigned long pop2) const;
	long double r_dpopPrevosti(unsigned long pop1,unsigned long pop2) const;
	long double r_dpopRoger(unsigned long pop1,unsigned long pop2) const;
	long double r_dpopShriver(unsigned long pop1,unsigned long pop2) const;
	long double r_dpopZhivotovsky(unsigned long pop1,unsigned long pop2) const;
	long double r_dpopReynoldsUnweighted(unsigned long pop1,unsigned long pop2) const;
	long double r_dpopReynoldsWeighted(unsigned long pop1,unsigned long pop2) const;
	long double r_dpopReynoldsLeast(unsigned long pop1,unsigned long pop2) const;

	void f_calcTabFreq() const;
	void f_calcTabFreqInd() const;
	void f_calcTabFreqTot() const;
	void f_calcTabFreqBootInd() const;
	void f_calcTabMu() const;
	void f_calcTabMuInd() const;
	void f_calcTabMuBootInd() const;
	void f_calcTabBootInd() const;
	void newTabMu();
	void newTabMuInd();
	void newTabFreq();
	void newTabFreqInd();
	void newTabFreqTot();

//	static map<unsigned int, string> _map_noms_methodes;
	static vector<string> _tab_noms_methodes;
//	static vector<unsigned int> _tab_numeros_methodes;

	Vecteur<unsigned int> _VcalcLocus;
	Vecteur<Locus*> _tabPloc;
	vector<Individu*> _tabPind;
	vector<StrucPop*> _tabPstrucpop;

	Jeupop * _Pjeupop;
	int _methode;
	unsigned long _nbpop;
	unsigned long _nbloc;
	long double _pi;

	long double ** _PtabFreq;
	long double * _PtabFreqTot; // moyennes des fréquences allèliques sur toutes les pops
	long double * _PtabMu;
	unsigned long * _tabNbAll;
	bool * _tabEviteLocus;// pour ne pas tenir compte des locus qui ne contiennent que des allèles nuls

	bool _bootind;
	bool _squareDistance;

public:
	friend class Jeupop;

	struct Anomalie{
		// 1-> _methode non précisée, calcul impossible
		// 2-> Pas assez d'individus dans la pop pour calculer la distance

		int le_pb;
		Anomalie (int i, const string & nompop=""):le_pb(i){
			switch (i) {
			case 1:
				_message = _("ERROR 1 in \"DistancesGnt\": The distance method was not precised");
				break;
			case 2:
				_message = _("ERROR 2 in \"DistancesGnt\": Too few individuals in the population \"");
				_message += nompop;
				_message += _("\" to compute distances");
				break;
			case 3:
				_message = _("ERROR 3 in \"DistancesGnt\": division by zero computing allelic frequencies for population \"");
				_message += nompop;
				_message += "\"";
				break;
				
			case 4:
				//_message += "\"";
				_message = _("ERROR 4 in \"DistancesGnt\": this distance method \"");
				_message += nompop;
				_message += "\" could not be applied to individuals";
				break;
			
			case 5:
				//_message += "\"";
				_message = _("ERROR 5 in \"DistancesGnt\": log of a negative number is  not defined ");
				//_message += nompop;
				//_message += "\" could not be applied to individuals";
				break;
			
			case 6:
				//_message += "\"";
				_message = _("ERROR 6 in \"DistancesGnt\": this distance method does not exist ");
				//_message += nompop;
				//_message += "\" could not be applied to individuals";
				break;

			default:
				_message = _("ERROR in \"DistancesGnt\"");
				break;
			}
		};

		string _message;

		string& fmessage(){
			return(_message);
		}
	};


};

#endif

