/***************************************************************************
 matrices.h  -  Librairie d'objets pour manipuler des matrices
 -------------------
 begin                : ven aug 14 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.                                   *
 *                                                                         *
 ***************************************************************************/

// Objets permettant de manipuler des matrices
// Olivier Langella le 11/3/98
// langella@pge.cnrs-gif.fr

//#include "vecteurs.h"

// les matrices
#ifndef MATRICES_H
#define MATRICES_H

//#define WITHOUT_EXPAT
//#ifndef WITHOUT_EXPAT
//#include "expat.h"
//#endif

#include <iostream>
#include <sstream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <vector>
#include <cmath>
#include <QDebug>
#include <QXmlStreamWriter>
#include <QString>
//#include <locale>
#include "vecteurs.h"

namespace biolib {
namespace vecteurs {

class MatriceLD;
// les matrices
class Matrice {
public:
	Matrice();
	Matrice(unsigned long nl, unsigned long nc = 0);
	Matrice(const Matrice&); //constructeur de copie
	//Matrice(const MatriceLD& lamatrice):Matrice<long double>(lamatrice) {}; //constructeur de copie
	//Matrice(const MatriceF& lamatrice):Matrice<float>(lamatrice) {}; //constructeur de copie
	virtual ~Matrice() {
		if (_tab != 0)
			delete[] _tab;
	}

	virtual long double& GetCase(const ChaineCar& nomLig, const ChaineCar& nomCol) const {
		long ni(_tlig.Position(nomLig));
		long nj(_tcol.Position(nomCol));
		//cerr << nomLig << "GetCase ni " << ni;
		//cerr << nomCol << "GetCase nj " << nj;
		if ((ni < 0) || (nj < 0))
			throw Anomalie(7);
		return (GetCase(ni, nj));
	}

	virtual long double& GetCase(unsigned long i, unsigned long j) const {
		if ((i >= _nl) || (j >= _nc))
			throw Anomalie(7);
		//renvoie la valeur de la case i (ligne), j (colonne)
		long swap;
		if ((_type == 3) && (j > i)) {
			swap = i;
			i = j;
			j = swap;
		}
		return (_tab[(i * _nc) + j]);
	}

	virtual void SetFlag(int i) {
		_flag = i;
	}
	//etiquettes sur lignes ou colonnes


	long GetNC() const {
		return (_nc);
	}

	long GetNL() const {
		return (_nl);
	}

	int GetType() const {
		return (_type);
	}

	int GetFlag() const {
		return (_flag);
	}

	virtual long double get_ppvaleur() const; //recherche la plus petite valeur

	virtual bool SetType(int type); //type de matrice:
	//1 -> rectangulaire
	//3 -> triangulaire
	virtual void resize(unsigned long nblig, unsigned long nbcol); //efface et réalloue de la mémoire
	virtual void SupprCol(unsigned long); //efface et réalloue de la mémoire
	virtual void SupprLig(unsigned long); //efface et réalloue de la mémoire
	virtual bool redim(unsigned long, unsigned long); //redimensionne la matrice

	void ftranspose();
	virtual void f_neg2zero();
	void fscol(vector<long double> & somme) const; //somme des colonnes
	void fslig(vector<long double> & somme) const; //somme des colonnes
	void fswapcol(long i, long j);
	long double fdet() const;
	long double ftrace() const;

	inline void fmultiplier(const Matrice& matA, const Matrice& matB);

	Titre _titre;

	Titre _tcol;
	Titre _tlig;

	virtual void iFichier(istream& ientree);
	void iFichier(istream & entree, int i) {
		//cerr << "coucou " << i << endl;

		switch (i) {
		case 1:
			iExcel(entree);
			return;
			break;
		case 2:
			iNtsys(entree);
			return;
			break;
		case 4:
			iPhylip(entree);
			return;
			break;
		case 5:
			iGnumeric(entree);
			return;
			break;
		default:
			return;
		}
	}

	virtual void oFormat(ostream & sortie, int i) {
		switch (i) {
		case 1:
			oExcel(sortie);
			break;
		case 2:
			oNtsys(sortie);
			break;
		case 3:
			//	oXgobi(sortie);
			throw Anomalie(6);
			break;
		case 4:
			oPhylip(sortie);
			//	throw Anomalie(6);
			break;
		case 5:
			oGnumeric(sortie);
			//	throw Anomalie(6);
			break;
		default:
			break;
		}

	}

	//1= Excel
	//2= Ntsys
	//3= xgobi  ==!!!! seulement en ofstream !!!!!

	virtual void ofFormat(ofstream & sortie, int i = 1) {
		if (i == 3) {
			string fichier("xgobi");
			oXgobi(fichier);
		} else {
			oFormat(sortie, i);
		}
	}

	virtual void ofFormat(ofstream & sortie, int i, const string &fichier) {
		if (i == 3) {
			oXgobi(fichier);
		} else {
			oFormat(sortie, i);
		}
	}

	virtual void iNtsys(istream & entree);
	virtual void iExcel(istream & entree);
	virtual void iGnumeric(istream & entree);
	virtual void iPhylip(istream & entree);
	void oNtsys(ostream & sortie);
	void oExcel(ostream & sortie);
	void oGnumeric(ostream & sortie);
	void
			oGnumericSheet(QXmlStreamWriter& xml_stream,
					const QString & sheetname) const;
	void oPhylip(ostream& sortie);
	void oXgobi(const string&);

	virtual const Matrice& operator=(const Matrice &rval);
	const Matrice& operator=(vector<long double> &rval);
	Matrice operator*(Matrice &rval) const;
	vector<long double> operator*(const vector<long double> &rval);
	Matrice operator*(long double scalaire);
	Matrice operator-(Matrice &rval);
	Matrice operator+(Matrice &rval);
	Matrice operator+(long double rval);

protected:

	long double fdetrec() const;

	long rindice(long ligne, long colonne) {
		//if (_type == 3) if (colonne > ligne) return((colonne * _nc) + ligne);
		return ((ligne * GetNC()) + colonne);
	}

	unsigned long _t; //taille (_nc * _nl)
	unsigned long _nc; //nb de colonnes (i)
	unsigned long _nl; //nb de lignes (j)
	unsigned int _type; //type de matrice
	int _miss; //missing value
	unsigned int _flag; //étiquettes
	//1=> titres des lignes 2=> titres des colonnes
	//3=> les 2 //0=> rien

public:

	long double* _tab; // matrice
	//formats de fichiers
	unsigned int _oformat; //1-> Excel 2->NTsys 3->xgobi (UNIX) 4->phylip

	struct Anomalie {
		Anomalie(int i) :
			le_pb(i) {
		}

		// 1-> erreur pendant lecture de fichier
		// 2-> erreur dans mdiaggl
		// 3-> opération impossible sur ce type de matrice
		// 4-> calcul impossible
		// 5-> Echec de la conversion de la matrice en matrice symétrique

		// 6-> erreur pendant l'écriture du fichier
		// 7-> acces hors bornes dans la matrice
		int le_pb;
		string _message;

		string& fmessage(int num) {
			switch (num) {
			case 1:
				_message = "Erreur pendant la lecture du fichier...";
				break;
			case 2:
				_message = "Cette matrice ne peut être diagonalisée";
				break;
			case 3:
				_message = "Opération impossible sur ce type de matrice";
				break;
			case 4:
				_message = "Calcul impossible";
				break;
			case 5:
				_message
						= "Echec de la conversion de la matrice en matrice symétrique";
				break;
			case 6:
				_message = "Erreur pendant l'ecriture du fichier";
				break;
			case 7:
				_message = "Acces hors bornes dans la matrice";
				break;

			default:
				_message = "";
				break;
			}
			return (_message);
		}
	};

};

// les matrices
class MatriceLD: public Matrice {
public:
	MatriceLD();
	MatriceLD(long nl, long nc = 0) :
		Matrice (nl, nc) {
	}

	MatriceLD(const MatriceLD& lamatrice) :
		Matrice (lamatrice) {
	}
	//constructeur de copie
	MatriceLD(const Matrice& lamatrice) :
		Matrice (lamatrice) {
	}
	//constructeur de copie
	virtual ~MatriceLD() {
	}

	void fatd(MatriceLD&, MatriceLD&);
	void fscalaire(MatriceLD& pscalaire);
	void fdiagonalisation(MatriceLD &, vector<long double> &);
	void fmdiagql(int m, long double *ps, vector<long double> & pvlp);
	int ftridiag(long double *ps, vector<long double> & pvlp);
	void fcoordcol(MatriceLD& stat, MatriceLD& res, MatriceLD& norm, vector<
			long double> & pvlp);
	/*

	 void folicovariance(MatriceLD& pcov, bool facteur=false); //ya un truc
	 void fcovariance(MatriceLD& pcov); //ya un truc
	 // pourquoi on n eprend qu'une partie de l'originale ?
	 void fnormalise(MatriceLD & ,MatriceLD & , vector<long double> &) const;
	 void ftrivectshell(int, int, vector<long double> & pvlp);
	 void fprojection(MatriceLD& mccord,MatriceLD& mstat,MatriceLD& vectpropres,  vector<long double> & pvlp) const;

	 void fafc (MatriceLD&, MatriceLD&);
	 void foliafc (MatriceLD&, MatriceLD&, long double precision=0.000001);
	 void foliatd (MatriceLD&, MatriceLD&, long double precision=0.000001);
	 void facp (MatriceLD&, MatriceLD&, long double precision=0.000001);
	 void fvalpropres (MatriceLD&, vector<long double> &, long double precision=0.000001);

	 */

	void finv(MatriceLD& resultat) const;

	void fvalpropres(MatriceLD&, vector<float> &, float precision =
			0.000001);

};

// les tableaux de matrices
class JeuMatriceLD {
public:

	JeuMatriceLD(istream& entree);
	JeuMatriceLD() {
	}

	//	JeuMatriceLD(deque<VecteurLD *>, Titre &, ) {};
	~JeuMatriceLD() {
		long i, t(_tableau.size());
		for (i = 0; i < t; i++)
			delete _tableau[i];
	}

	MatriceLD& GetMatrice(long i) {
		return *(_tableau[i]);
	}
	const MatriceLD& GetConstMatrice(long i) const {
		return *(_tableau[i]);
	}
	MatriceLD& GetMatrice(ChaineCar chaine) {
		long i(_titres.Position(chaine));
		if (i < 0)
			throw Anomalie(1);
		return GetMatrice(i);
	}
	MatriceLD& back() {
		return *(_tableau.back());
	}

	void iFlux(istream& entree);

	void oFlux(ostream& sortie, int format = 1) const;

	void push_back(MatriceLD* Pmatrice, const string titre) {
		_titres.push_back(titre);
		_tableau.push_back(Pmatrice);
	}

	void SetTitre(long i, const char * chaine);
	void resize(long i);
	long size() const {
		return (_tableau.size());
	}

private:
	void iFluxXML(istream& entree);
	void oGnumeric(ostream& sortie) const;

	vector<MatriceLD*> _tableau;
	Titre _titres;

public:
	struct Anomalie {
		Anomalie(int i) :
			le_pb(i) {
		}

		// 1-> Matrice introuvable
		int le_pb;
		string _message;

		string& fmessage(int num) {
			switch (num) {
			case 1:
				_message = "Matrice introuvable...";
				break;

			default:
				_message = "";
				break;
			}
			return (_message);
		}
	};

};

ostream& operator<<(ostream& sortie, Matrice& lamatrice);

//ofstream& operator<<(ofstream& sortie,MatriceLD& lamatrice);
ofstream& operator<<(ofstream& sortie, Matrice& lamatrice);

istringstream& operator>>(istringstream& ientree,
		Matrice& lamatrice);

} //namespace biolib {
} //namespace vecteurs {

#endif

