#ifndef SPHERICALTRANFORMSERVER_SEEN
#define SPHERICALTRANFORMSERVER_SEEN

#include "sphericalmap.h"
#include "fftservintf.h"
#include "fftpserver.h"
#include "alm.h"
#include "lambdaBuilder.h"


namespace SOPHYA {


template <class T>
class SphericalTransformServer
{

 public:

  SphericalTransformServer()  
    {
      fftIntfPtr_=new FFTPackServer;
      fftIntfPtr_->setNormalize(false);
    };
  ~SphericalTransformServer(){ if (fftIntfPtr_!=NULL) delete fftIntfPtr_;};
  
 /*!
 Set a fft server. The constructor sets a default fft server (fft-pack). So it is not necessary to call this method for a standard use.
*/
  void SetFFTServer(FFTServerInterface* srv=NULL) 
    {
      if (fftIntfPtr_!=NULL) delete fftIntfPtr_;
      fftIntfPtr_=srv;
      fftIntfPtr_->setNormalize(false);
    }

  void GenerateFromAlm( SphericalMap<T>& map, int_4 pixelSizeIndex, const Alm<T>& alm) const; 
  void GenerateFromAlm(SphericalMap<T>& mapq, SphericalMap<T>& mapu, int_4 pixelSizeIndex, const Alm<T>& alme,    const Alm<T>& almb) const;

  void GenerateFromCl(SphericalMap<T>& sph, int_4 pixelSizeIndex,
		     const TVector<T>& Cl, const r_8 fwhm) const; 
  void GenerateFromCl(SphericalMap<T>& sphq, SphericalMap<T>& sphu, 
		     int_4 pixelSizeIndex,
		     const TVector<T>& Cle, const TVector<T>& Clb, 
		    const r_8 fwhm) const; 


void DecomposeToAlm(SphericalMap<T>& map, Alm<T>& alm, int_4 nlmax, r_8 cos_theta_cut, int iterationOrder) const;
void DecomposeToAlm(const SphericalMap<T>& map, Alm<T>& alm, int_4 nlmax, r_8 cos_theta_cut) const;

void DecomposeToAlm(SphericalMap<T>& mapq,
		    SphericalMap<T>& mapu,
		    Alm<T>& alme,
		    Alm<T>& almb,
		    int_4 nlmax,
		    r_8 cos_theta_cut, 
		    int iterationOrder) const;
void DecomposeToAlm(const SphericalMap<T>& mapq,
		    const SphericalMap<T>& mapu,
		    Alm<T>& alme,
		    Alm<T>& almb,
		    int_4 nlmax,
		    r_8 cos_theta_cut) const;

TVector<T>  DecomposeToCl(SphericalMap<T>& sph,  
			   int_4 nlmax, r_8 cos_theta_cut, int iterationOrder) const;

TVector<T>  DecomposeToCl(const SphericalMap<T>& sph,  
			   int_4 nlmax, r_8 cos_theta_cut) const;


 private:

void carteVersAlm(const SphericalMap<T>& map, int_4 nlmax, r_8 cos_theta_cut, Alm<T>& alm) const;

void carteVersAlm(const SphericalMap<T>& mapq,
		  const SphericalMap<T>& mapu,
		  Alm<T>& alme,
		  Alm<T>& almb,
		  int_4 nlmax,
		  r_8 cos_theta_cut) const;


TVector< complex<T> >  fourierSynthesisFromB(const Bm<complex<T> >& b_m,  
				  int_4 nph, r_8 phi0) const;
TVector<T>  RfourierSynthesisFromB(const Bm<complex<T> >& b_m,  
				  int_4 nph, r_8 phi0) const;
TVector< complex<T> > CFromFourierAnalysis(int_4 mmax, 
				  const TVector<complex<T> > datain,
				  r_8 phi0) const;
  //  TVector< complex<T> > CFromFourierAnalysis(int_4 mmax, 
  //			 const TVector<T> datain,  
  //				  r_8 phi0) const;
  void CFromFourierAnalysis(int_4 mmax, const TVector<T> datain,
			    TVector< complex<T> >& dataout,
			    r_8 phi0) const;

  void almFromWX(int_4 nlmax, int_4 nmmax, r_8 phi0, 
	       r_8 domega, r_8 theta, 
	       const TVector<T>& dataq, const TVector<T>& datau,
	       Alm<T>& alme, Alm<T>& almb) const;
  void almFromPM(int_4 nph, int_4 nlmax, int_4 nmmax, 
	       r_8 phi0, r_8 domega, r_8 theta, 
	       const TVector<T>& dataq, const TVector<T>& datau,
	       Alm<T>& alme, Alm<T>& almb) const;

  void mapFromWX(int_4 nlmax, int_4 nmmax,
	       SphericalMap<T>& mapq, SphericalMap<T>& mapu, 
	       const Alm<T>& alme, const Alm<T>& almb, bool healpix) const;


  void mapFromPM(int_4 nlmax, int_4 nmmax,
	       SphericalMap<T>& mapq, SphericalMap<T>& mapu, 
	       const Alm<T>& alme, const Alm<T>& almb) const;



 FFTServerInterface* fftIntfPtr_;

};
} // Fin du namespace


#endif
