/***************************************************************************
                          jeupopexp.cpp  -  description
                             -------------------
    begin                : Tue Oct 24 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 "strucpop.h"
#include "jeupopexp.h"

JeuPopExp::JeuPopExp(Jeupop * Pjeu):_Pjeu(Pjeu) {

	_Pcopie = 0;
}

JeuPopExp::~JeuPopExp(){
	if (_Pcopie != 0) delete _Pcopie;

}


void JeuPopExp::oLea(unsigned long P1,unsigned long P2,unsigned long H, ostream & sortie, ostream & infos) {
	f_prepP1P2H(P1,P2,H,infos);

	unsigned long nbpop;
	unsigned long nbloc(_Pcopie->get_nbloc());
	unsigned long nball;    //nb d'alleles pour chaque locus
	unsigned long i,l,p;
	Locus * Plocus;
	bool proms;

	nbpop = _Pcopie->get_nbpop();

	sortie << "0" << endl;
	sortie << nbpop << endl;
	sortie << nbloc << endl;

	for (l=0; l < nbloc; l++) {
		Plocus = _Pcopie->get_Plocus(l);
		nball = Plocus->get_nball();
		sortie << Plocus->get_nballnonnuls() <<endl;
		for (p=0; p < nbpop; p++) {
			proms = true;		
			for (i=0; i < nball; i++) {
				if (!proms) sortie << " ";
				if (Plocus->getPall(i)->r_nonnul()) {
//					sortie << _Pcopie->get_Ppop(p)->f_calcfreq(Plocus->getPall(i));
					sortie << _Pcopie->get_Ppop(p)->f_calcfreqabsolue(Plocus->getPall(i));
					if (proms) proms = false;
				}		
			}
			sortie << endl;		
		}
	}
	
}
/** Exportation au format "admix" de G. Bertorelle
voir le site:
http://www.unife.it/genetica/Giorgio/giorgio.html
 */
void JeuPopExp::oAdmix_dat(unsigned long P1,unsigned long P2,unsigned long H, ostream & sortie, ostream & infos){

	f_prepP1P2H(H,P1,P2,infos); //inversion de l'ordre pour corriger le bug trouvé par Andrea Taylor (15/5/2002)


	unsigned long nbpop;
	unsigned long nbloc(_Pcopie->get_nbloc());
	unsigned long nball;    //nb d'alleles pour chaque locus
	unsigned long i,l,p;
	Locus * Plocus;
	bool proms;

	nbpop = _Pcopie->get_nbpop();

	for (l=0; l < nbloc; l++) {
		Plocus = _Pcopie->get_Plocus(l);
		sortie << Plocus->get_nom() << endl;
		proms = true;		
		for (p=0; p < nbpop; p++) {
			// affichage du total (nb d'alles non nuls de chaque pop pour ce locus)
			if (!proms) sortie << " ";
			sortie << _Pcopie->get_Ppop(p)->r_nballnonnuls(l);
			if (proms) proms = false;		
		}
		sortie << endl;
		
		nball = Plocus->get_nball();
		for (i=0; i < nball; i++) {
			if (Plocus->getPall(i)->r_nonnul()) {
				proms = true;		
				for (p=0; p < nbpop; p++) {
					if (!proms) sortie << " ";
					sortie << _Pcopie->get_Ppop(p)->f_calcfreqabsolue(Plocus->getPall(i));
					if (proms) proms = false;
				}
				sortie << endl;		
			}	
		}
	}
}

void JeuPopExp::oAdmix_mtx(ostream & sortie, ostream & infos){
//	f_prepP1P2H(P1,P2,H,infos);

	unsigned long nbpop;
	unsigned long nbloc(_Pcopie->get_nbloc());
	unsigned long nball;    //nb d'alleles pour chaque locus
	unsigned long i,l,p;
	unsigned long diffcarre;
	Locus * Plocus;
//	bool proms;

	if (_Pcopie == 0) throw Anomalie(1, "Admix_mtx");
	nbpop = _Pcopie->get_nbpop();
	if (nbpop != 3) throw Anomalie(1, "Admix_mtx");

	sortie << nbloc << endl;
	for (l=0; l < nbloc; l++) {
		Plocus = _Pcopie->get_Plocus(l);
		sortie << Plocus->get_nom() << endl;
		nball = Plocus->get_nballnonnuls();
		// nb d'alleles différents non nuls pour ce locus
		sortie << nball << endl;
		// matrice de distance "squared difference in allele size"
		for (i=0; i < Plocus->get_nball(); i++) {
			if (Plocus->getPall(i)->r_estnul()) continue;
			for (p=0; p < i; p++) {
				if (Plocus->getPall(p)->r_estnul()) continue;
				diffcarre =(Plocus->getPall(p)->get_nbrepet() - Plocus->getPall(i)->get_nbrepet());
				diffcarre *= diffcarre;
				sortie << diffcarre << " ";				
//cerr << ",nrepet:" << Plocus->getPall(p)->get_nbrepet();
			}
			sortie << "0" << endl;
		}
	}
}

/** Prépare une copie de jeupop avec 3
populations P1, P2, H (special admixture) */
void JeuPopExp::f_prepP1P2H(unsigned long P1,unsigned long P2,unsigned long H, ostream & infos){
	unsigned long nbpop(_Pjeu->get_nbpop());
	unsigned long p;
	Population * PP1;
	Population * PP2;
	Population * PH;
	Population * Ppop;
	//-------préparation des données:
	if (_Pcopie != 0) delete (_Pcopie);
	_Pcopie = new Jeupop(*_Pjeu);

	PP1 = _Pcopie->get_Ppop(P1);
	PP2 = _Pcopie->get_Ppop(P2);
	PH = _Pcopie->get_Ppop(H);

	_Pcopie->f_deplacePop(PP1,0);
	_Pcopie->f_deplacePop(PP2,1);
	_Pcopie->f_deplacePop(PH,2);


//cerr << "JeuPopExp::oAile" << endl;
//cerr << _Pcopie->get_nbpop() << " " <<_Pcopie->get_nbind() << endl;

  p=nbpop;
	while (nbpop > 3) {
		p--;
	  Ppop = _Pcopie->get_Ppop(p);
		if (Ppop == PP1) continue;
		if (Ppop == PP2) continue;
		if (Ppop == PH) continue;
		_Pcopie->SupprPop(Ppop);
		nbpop--;
//cerr << _Pcopie->get_nbpop() << " " <<_Pcopie->get_nbind() << endl;
	}

//	_Pcopie->oGenepop(cout);	
	// elimination des alleles inutiles (non présents dans l'échantillon)
	_Pcopie->f_nettoieAlleles();

}

void JeuPopExp::oGenetix(ostream & sortie, ostream & infos){
// sortie au format Genetix
// http://www.univ-montp2.fr/~genetix/genetix.htm
// 1ere ligne : nb de locus
// 2eme ligne : nb de populations
//description des locus:
// nom de locus sur une ligne (5 caracteres max)
// nombre d'alleles, et numéros d'allèles sur 3 chiffres
// description des populations:
// nom de population sur une ligne
// taille de l'échantillon sur une ligne
// Identifiant de l'individu sur 10 caractères, suivi du génotype
// retour chariot : CRLF

//cerr << "JeuPopExp::oGenetix(ostream & sortie, ostream & infos)" << endl;
	unsigned long nbpop;
	unsigned long nbind;
	unsigned long nbloc(_Pjeu->get_nbloc());
	unsigned long nball;    //nb d'alleles pour chaque locus
	unsigned long i,l,p;
	Locus * Plocus;
	Population * Ppop;
	Individu * Pind;
	
	char crlf[3];
	
	crlf[0] = 13;
	crlf[1] = 10;
	crlf[2] = '\0';
//	bool proms;

	if (_Pjeu == 0) throw Anomalie(1, "Genetix");
	
	if (_Pjeu->get_nploidie() != 2) {
		//le format Genetix ne permet que le stockage de pop diploïdes
		throw Anomalie(100, "Genetix");
	}

	if (!(_Pjeu->f_verifnum(3))) {
		//il faut renuméroter les allèles pour le format génétix
		throw Anomalie(2, "Genetix");
	}


	nbpop = _Pjeu->get_nbpop();
//	if (nbpop != 3) throw Anomalie(1);

	sortie << nbloc << crlf;
	sortie << nbpop << crlf;
	
	for (l=0; l < nbloc; l++) {
		Plocus = _Pjeu->get_Plocus(l);
		sortie << Plocus->get_nom() << crlf; //attention ! pas plus de 5 caractères
		if (Plocus->get_nom().size() > 5) throw Anomalie(1000, "Genetix");
		nball = Plocus->get_nball();
		// nb d'alleles pour ce locus
		sortie << Plocus->get_nballnonnuls();
		// matrice de distance "squared difference in allele size"
		for (i=0; i < nball; i++) {
			if (Plocus->getPall(i)->r_estnul() != true) {
				sortie << " ";
				if (Plocus->getPall(i)->get_nom().size() == 2) sortie << "0";
				else if (Plocus->getPall(i)->get_nom().size() == 1) sortie << "00";
				sortie << Plocus->getPall(i)->get_nom();
			}
		}
		sortie << crlf;
	}
	
	for (p=0; p < nbpop; p++) {
		// _Pcopie->get_Ppop(p);
		Ppop = _Pjeu->get_Ppop(p);
		sortie << Ppop->get_nom() << crlf;
		nbind = Ppop->get_nbind();
		sortie << nbind << crlf;
		
		for (i=0; i < nbind; i++) {
			Pind = Ppop->get_Pind(i);
			if (Pind->get_nom().size() > 10) throw Anomalie(1001, "Genetix");		
			Pind->affiche (sortie, 4); //affichage de l'individu au format genetix
			sortie << crlf;		
		}
	}
}

void JeuPopExp::oFstat(ostream & sortie, ostream & infos){
// sortie au format FSTAT 2.91
// http://www.unil.ch/izea/softwares/fstat.html
// 1ere ligne : nb de pop, nb de locus, plus grand numero d'allele, nb de digits
// nom des locus sur n lignes

	unsigned long nbpop;
	unsigned long nbind;
	unsigned long nbloc(_Pjeu->get_nbloc());
	unsigned long i,l,p;
	Locus * Plocus;
	Population * Ppop;
	Individu * Pind;
	char crlf[3];
	
	crlf[0] = 13;
	crlf[1] = 10;
	crlf[2] = '\0';
//	bool proms;

	if (_Pjeu == 0) throw Anomalie(1, "Fstat");
	
	if (_Pjeu->get_nploidie() != 2) {
		//le format Fstat ne permet que le stockage de pop diploïdes
		throw Anomalie(100, "Fstat");
	}

	if (!(_Pjeu->f_verifnum(2))) {
		//il faut renuméroter les allèles pour le format Fstat
		throw Anomalie(2, "Fstat");
	}


	nbpop = _Pjeu->get_nbpop();
//	if (nbpop != 3) throw Anomalie(1);

	p = 0;
	for (l=0; l < nbloc; l++) {
		if (_Pjeu->get_Plocus(l)->get_nballnonnuls() > p) p = _Pjeu->get_Plocus(l)->get_nballnonnuls();
	}
	
	//sortie << nbpop << "\t" << nbloc << "\t" << p << "\t2"<< crlf;
	sortie << nbpop << "\t" << nbloc << "\t" << "99" << "\t2"<< crlf;
	
	for (l=0; l < nbloc; l++) {
		Plocus = _Pjeu->get_Plocus(l);
		sortie << Plocus->get_nom() << crlf;
	}
	
	for (p=0; p < nbpop; p++) {
		// _Pcopie->get_Ppop(p);
		Ppop = _Pjeu->get_Ppop(p);
		nbind = Ppop->get_nbind();
		
		for (i=0; i < nbind; i++) {
			if (p < 9) sortie << "   ";
			else if (p < 99) sortie << "  ";
			else if (p < 999) sortie << " ";
			
			sortie << (p+1);
			Pind = Ppop->get_Pind(i);
			//if (Pind->get_nom().size() > 10) throw Anomalie(1001, "Fstat");		
			Pind->affiche (sortie, 5); //affichage de l'individu au format Fstat
			sortie << crlf;		
		}
	}
}

void JeuPopExp::oPopulationsXML(ostream & sortie, ostream & infos) const{
  unsigned int l, i, nball(0), nbloc(_Pjeu->get_nbloc());
	Locus * Plocus;
  biolib::vecteurs::ChaineCar idXML;
  
  //export into "populations" XML format
  // pas fini
  sortie << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" << endl;
  sortie << "<!--  " << endl;
  sortie << "created by Populations" << endl;
  sortie << "http://www.pge.cnrs-gif.fr/bioinfo/populations" << endl;
  sortie << "-->" << endl;
  
  sortie << "<populations version=\"0.1\">" << endl;
  sortie << "<comments>" << endl;
	for (l=0; l < _Pjeu->get_commentaires().size(); l++) {
    sortie << _Pjeu->get_commentaires().operator[](l) << endl;
  }
  sortie << "</comments>" << endl;
  
  sortie << "<loci>" << endl;
	for (l=0; l < nbloc; l++) {
		Plocus = _Pjeu->get_Plocus(l);
    sortie << "<locus";
		sortie << " id=\"l" << l << "\"";
		sortie << " name=\"" << Plocus->get_nom() << "\"";
    sortie << ">" << endl;
		//if (Plocus->get_nom().size() > 5) throw Anomalie(1000, "Genetix");
		nball = Plocus->get_nball();
		// nb d'alleles pour ce locus
		for (i=0; i < nball; i++) {
      sortie << "<allele";
      idXML = "l";
      idXML.AjEntier(l);
      idXML += "a";
      idXML.AjEntier(i);
      Plocus->getPall(i)->set_idXML((string) idXML);
      sortie << " id=\"" << Plocus->getPall(i)->get_idXML() << "\"";
      if (Plocus->getPall(i)->r_estnul()) sortie << " name=\"missing\"";
	  	else {
        sortie << " name=\"" << Plocus->getPall(i)->get_nom() << "\"";
	  	  sortie << " nbrepeat=\"" << Plocus->getPall(i)->get_nbrepet() << "\"";
      }
      sortie << ">" << endl;
      
      sortie << "</allele>" << endl;
		}
    sortie << "</locus>" << endl;
	}
  sortie << "</loci>" << endl;
  
  _Pjeu->get_Pracinepop()->oPopulationsXML(0, sortie, infos);

  sortie << "</populations>" << endl;
  
}

