#include "sopnamsp.h"
#include "machdefs.h"
#include <stdlib.h>
#include <typeinfo>
#include <iostream>
#include <string>
#include <complex>

#include "datatype.h"

#include "nomtarradapter.h"
#include "tvector.h"
#include "pitvmaad.h"
#include "piyfxdrw.h"

#include "fioarr.h"

#include "nobjmgr.h"


//----------------------------------------------------------------
// Class Adaptateur d'objet (Pour NamedObjMgr) d'objet TMatrix<T> 
//----------------------------------------------------------------


/* --Methode-- */
template <class T> 
NOMAdapter_TArray<T>::NOMAdapter_TArray(TArray<T>* o)
  : NObjMgrAdapter(o)
{
mArr = o;
}

/* --Methode-- */
template <class T> 
NOMAdapter_TArray<T>::~NOMAdapter_TArray()
{
}

/* --Methode-- */
template <class T> 
NObjMgrAdapter* NOMAdapter_TArray<T>::Clone(AnyDataObj* o)
{
TArray<T>* a = dynamic_cast<TArray<T> *>(o);
if (a) return ( new NOMAdapter_TArray<T>(a) );
return ( new NObjMgrAdapter(o) );
}

/* --Methode-- */
template <class T> 
string NOMAdapter_TArray<T>::GetDataObjType()
{
string type = "TArray< ";

// type +=  DecodeTypeIdName(typeid(T).name());
type += DataTypeInfo<T>::getTypeName();
type +=  " > ";
return(type);
}

/* --Methode-- */
template <class T> 
AnyDataObj* NOMAdapter_TArray<T>::CloneDataObj(bool share)
{
return ( new TArray<T>(*mArr, share) );
}

/* --Methode-- */
template <class T> 
string NOMAdapter_TArray<T>::GetInfoString(vector<string>& opts)
{
  if (opts.size() == 0) return mArr->InfoString();
  else {
    char buff[128];
    if (opts[0] == "rank") {
      sprintf(buff,"%d", (int)mArr->Rank());
      return string(buff);      
    }
    if (opts[0] == "sizes") {
      string rs;
      for(int_4 kd=0; kd<mArr->Rank(); kd++) {
	sprintf(buff, "%ld ", (long)mArr->Size(kd)); 
	rs += buff;
      }
      return rs;      
    }
    else if ((opts[0] == "size") || (opts[0] == "nelts")) {
      sprintf(buff, "%ld", (long)mArr->Size()); 
      return string(buff);
    }
    else if (opts[0] == "sum") {
      MuTyV mtv(mArr->Sum());
      string s;
      return mtv.Convert(s);
    }
    else if (opts[0] == "sumsq") {
      MuTyV mtv(mArr->SumSq());
      string s;
      return mtv.Convert(s);
    }
    else if (opts[0] == "norm2") {
      MuTyV mtv(mArr->Norm2());
      r_8 nrm2 = mtv.Convert(nrm2);  // we force the conversion to double
      mtv = nrm2;
      string s;
      return mtv.Convert(s);
    }
    else if ((opts[0] == "min")||(opts[0] == "max")||(opts[0] == "minmax")) {
      T amin, amax;
      MuTyV mtv;
      string s;
      mArr->MinMax(amin, amax);
      if (opts[0] == "minmax") {
	mtv = amin;  mtv.Convert(s);
	s += " ";
	string mms;
	mtv = amax;  mtv.Convert(mms);
	s += mms;
      }
      else {
	if (opts[0] == "min")  mtv = amin;
	else if (opts[0] == "max")  mtv = amax;
	mtv.Convert(s); 
      }
      return s;
    }
    else if (opts[0] == "info") { // Acces aux valeurs stockes ds le DVList Info()
      if (opts.size() < 2)  return string(""); 
      else if (mArr->Info().HasKey(opts[1]) == false) return string(""); 
      else return mArr->Info().GetS(opts[1]);
    }
    else return "TArray.Att: rank sizes size/nelts sum sumsq/norm2 min max minmax";
  }
}

/* --Methode-- */
template <class T> 
int NOMAdapter_TArray<T>::PerformOperation(vector<string>& opts)
{
  bool ok = false;
  if ((mArr->Rank() >= 3) && (opts.size() >= 2)) {
    int_4 ks = atoi(opts[1].c_str());
    TMatrix<T> * slice = new TMatrix<T>;
    char buff[40];
    if (opts[0] == "slicexy") {
      slice->Share(mArr->SubArray(Range::all(), Range::all(), Range(ks), 
				  Range::first(), Range::first()) );  
      ok = true; 
      sprintf(buff,"slicexy_%ld",(long)ks);
      cout << "PerformOperation(): Extracting SliceXY(" << ks << ") from array" << endl;
    }
    else if (opts[0] == "sliceyz") {
      slice->Share(mArr->SubArray(Range(ks), Range::all(), Range::all(), Range::first(), 
				  Range::first()).CompactAllDimensions() );  
      ok = true; 
      sprintf(buff,"sliceyz_%ld",(long)ks);
      cout << "PerformOperation(): Extracting SliceYZ(" << ks << ") from array" << endl;
    }
    else if (opts[0] == "slicexz") {
      slice->Share(mArr->SubArray(Range::all(), Range(ks), Range::all(), Range::first(), 
				  Range::first()).CompactAllDimensions() );  
      ok = true; 
      sprintf(buff,"slicexz_%ld",(long)ks);
      cout << "PerformOperation(): Extracting SliceYZ(" << ks << ") from array" << endl;
    }
    if (ok) {
      string nslice;
      if(opts.size() > 2)  nslice = opts[2];
      else nslice = buff;
      NamedObjMgr omg;
      omg.AddObj(slice, nslice, true); 
    }
    else delete slice;
    return 0;
  }
  else if (opts.size() >= 1) {
    if (opts[0] == "compactalldim") {
      mArr->CompactAllDimensions();   ok = true;
      cout << "PerformOperation(): mArr->CompactAllDimensions() " << endl;
    }
    else if (opts[0] == "compactdim") {
      mArr->CompactTrailingDimensions();   ok = true;
      cout << "PerformOperation(): mArr->CompactTrailingDimensions() " << endl;
    }
    else ok = false;
    if (ok) return 0;
  }

  if (!ok) {
    cout << "NOMAdapter_TArray<T>::PerformOperation(): Error operation/arguments !" << endl;
    cout << "...Valid args: slicexy idxZ [slicename], sliceyz idxX [nm] slicexz idxY [nm]" << endl;
    cout << "... compactdim (=CompactTrailingDimensions()), compactalldim (=CompactAllDimensions())" << endl;
    return 1; 
  }

  return 0;
}

/* --Methode-- */
template <class T> 
void NOMAdapter_TArray<T>::SavePPF(POutPersist& pos, string const & nom)
{
FIO_TArray<T> fio(mArr);
fio.Write(pos, nom);
}

/* --Methode-- */
template <class T> 
void NOMAdapter_TArray<T>::Print(ostream& os, int lev)
{
if (lev < 3) mArr->Show(os, false);
else  mArr->Show(os, true);
if (lev > 0) mArr->Print(os, 10*lev);
}

/* --Methode-- */
template <class T> 
PIDrawer * NOMAdapter_TArray<T>::GetDrawer(string & dopt)
{
TArray<T> arr(*mArr, true);      // on partage les donnees 
arr.CompactAllDimensions();
if (arr.NbDimensions() == 1) {
  // On peut en faire un vecteur ...
  TVector<T>* v = new TVector<T>(arr, true);  // on partage les donnees
  dopt = "thinline," + dopt;
  return( new PIYfXDrawer( new POTVectorAdapter<T>(v, true, StringToCmplxDispOption(dopt)), NULL, true) );
}
else { 
  cout << "NOMAdapter_TArray<T>::GetDrawer() NDim[Size>1]>1 -> No PIDrawer" << endl;
  return(NULL);
}
}

/* --Methode-- */
template <class T> 
P2DArrayAdapter* NOMAdapter_TArray<T>::Get2DArray(string & dopt)
{
TArray<T> arr(*mArr, true);    // on partage les donnees 
arr.CompactAllDimensions();
if (arr.NbDimensions() <= 2) {
  // On peut en faire un tableau 2-D ...
  TMatrix<T>* m = new TMatrix<T>(arr, true);  // on partage les donnees
  return ( new POTMatrixAdapter<T>(m, true, StringToCmplxDispOption(dopt)) );
}
else { 
  cout << "NOMAdapter_TArray<T>::Get2DArray() NDim[Size>1]>2 -> No 2DArrAdapt" << endl;
  return(NULL);
}
}

/* --Methode-- */
template <class T> 
NTupleInterface* NOMAdapter_TArray<T>::GetNTupleInterface(bool& adel)
{
adel = true;
return( new NTupInt_TArray<T>(mArr) );
}




// -------------------------------------------------------------

/* --Methode-- */
template <class T> 
NTupInt_TArray<T>::NTupInt_TArray(TArray<T>* a)
{
mArr = a;
}

/* --Methode-- */
template <class T> 
NTupInt_TArray<T>::~NTupInt_TArray()
{
}

/* --Methode-- */
template <class T> 
sa_size_t NTupInt_TArray<T>::NbLines() const
{
return( mArr->Size() );
}

/* --Methode-- */
template <class T> 
sa_size_t NTupInt_TArray<T>::NbColumns() const 
{
return(11);
}

/* --Methode-- */
template <class T> 
r_8 NTupInt_TArray<T>::GetCell(sa_size_t n, sa_size_t k) const
{
  if ((n < 0) || (n >= (int)(mArr->Size()) ) ) 
    return 0.;
  if ((k < 0) || (k > 10))  return 0.;
  GetLineD(n);
  return mRet[k];
}

/* --Methode-- */
template <class T> 
sa_size_t NTupInt_TArray<T>::ColumnIndex(string const & nom)  const 
{
 if (nom == "n") return 0;
 else if (nom == "x") return 1;
 else if (nom == "y") return 2;
 else if (nom == "z") return 3;
 else if (nom == "t") return 4;
 else if (nom == "u") return 5;
 else if (nom == "val") return 6;
 else if (nom == "real") return 7;
 else if (nom == "imag") return 8;
 else if (nom == "mod") return 9;
 else if (nom == "phas") return 10;
 else return -1;
}

/* --Methode-- */
template <class T> 
void NTupInt_TArray<T>::GetMinMax(sa_size_t k, double& min, double& max) const
{
  if (k == 0) {
    min = 0.; max = (r_8)(mArr->Size());  }
  else if (k == 1) {
    min = 0.; max = (r_8)(mArr->SizeX());  }
  else if (k == 2) {
    min = 0.; max = (r_8)(mArr->SizeY());  }
  else if (k == 3) {
    min = 0.; max = (r_8)(mArr->SizeZ());  }
  else if (k == 4) {
    min = 0.; max = (r_8)(mArr->Size(3));  }
  else if (k == 5) {
    min = 0.; max = (r_8)(mArr->Size(4));  }
  else if ((k == 6) || (k == 7) || (k == 9)) {
    T tmin, tmax;
    mArr->MinMax(tmin, tmax);
    min = (r_8)(tmin); 
    max = (r_8)(tmax); 
  }
  else { min = max = 0.; }
  return;
}

/* --Methode-- */
template <class T> 
r_8* NTupInt_TArray<T>::GetLineD(sa_size_t n) const 
{
if ((n < 0) || (n >= (int)(mArr->Size()) ) ) {
  mRet[0] = n;
  for(int i=1; i<11; i++)  mRet[i] = 0.;
}
else { 
  sa_size_t ix, iy, iz, it, iu;
  mArr->IndexAtPosition(n, ix, iy, iz, it, iu);
  mRet[0] = n;   mRet[1] = ix;  mRet[2] = iy;  
  mRet[3] = iz;  mRet[4] = it;  mRet[5] = iu;  
  mRet[6] = (*mArr)(ix,iy,iz,it,iu);
  mRet[7] = mRet[6];  mRet[8] = 0.;
  mRet[9] = mRet[6];  mRet[10] = 0.;
  }
return(mRet);
}

/* --Methode-- */
template <class T> 
string NTupInt_TArray<T>::VarList_C(const char* nx) const 
{
string nomx;
if (nx) nomx = nx;
else nomx = "_xh_";
string vardec = "double n,x,y,z,t,u,val,real,imag,mod,phas; \n";
vardec += "n = " + nomx + "[0];  x = " + nomx + "[1]; y = " + nomx + "[2]; \n"; 
vardec += "z = " + nomx + "[3];  t = " + nomx + "[4]; u = " + nomx + "[5]; \n"; 
vardec += "val = " + nomx + "[6]; \n";
vardec += "real = " + nomx + "[7];  imag = " + nomx + "[8]; \n";
vardec += "mod  = " + nomx + "[9];  phas = " + nomx + "[10]; \n";
return(vardec);
}

/* --Methode-- */
DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
r_8* NTupInt_TArray< complex<r_4> >::GetLineD(sa_size_t n) const 
{
if ((n < 0) || (n >= (int)(mArr->Size()) ) ) {
  mRet[0] = n;
  for(int i=1; i<11; i++)  mRet[i] = 0.;
}
else { 
  sa_size_t ix, iy, iz, it, iu;
  mArr->IndexAtPosition(n, ix, iy, iz, it, iu);
  mRet[0] = n;   mRet[1] = ix;  mRet[2] = iy;  
  mRet[3] = iz;  mRet[4] = it;  mRet[5] = iu;  
  mRet[7] = (*mArr)(ix,iy,iz,it,iu).real();
  mRet[8] = (*mArr)(ix,iy,iz,it,iu).imag();
  mRet[6] = mRet[9] = sqrt(mRet[7]*mRet[7]+mRet[8]*mRet[8]);
  mRet[10] = atan2(mRet[8], mRet[7]);
}
return(mRet);
}

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
r_8* NTupInt_TArray< complex<r_8> >::GetLineD(sa_size_t n) const 
{
if ((n < 0) || (n >= (int)(mArr->Size()) ) ) {
  mRet[0] = n;
  for(int i=1; i<11; i++)  mRet[i] = 0.;
}
else { 
  sa_size_t ix, iy, iz, it, iu;
  mArr->IndexAtPosition(n, ix, iy, iz, it, iu);
  mRet[0] = n;   mRet[1] = ix;  mRet[2] = iy;  
  mRet[3] = iz;  mRet[4] = it;  mRet[5] = iu;  
  mRet[7] = (*mArr)(ix,iy,iz,it,iu).real();
  mRet[8] = (*mArr)(ix,iy,iz,it,iu).imag();
  mRet[6] = mRet[9] = sqrt(mRet[7]*mRet[7]+mRet[8]*mRet[8]);
  mRet[10] = atan2(mRet[8], mRet[7]);
}
return(mRet);
}

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
void NTupInt_TArray< complex<r_4> >::GetMinMax(sa_size_t k, double& min, double& max) const
{
  if (k == 0) {
    min = 0.; max = (r_8)(mArr->Size());  }
  else if (k == 1) {
    min = 0.; max = (r_8)(mArr->SizeX());  }
  else if (k == 2) {
    min = 0.; max = (r_8)(mArr->SizeY());  }
  else if (k == 3) {
    min = 0.; max = (r_8)(mArr->SizeZ());  }
  else if (k == 4) {
    min = 0.; max = (r_8)(mArr->Size(3));  }
  else if (k == 5) {
    min = 0.; max = (r_8)(mArr->Size(4));  }
  else if ((k >= 6) || (k <= 9)) {
    r_8 tmin[3] = {9.e39,9.e39,9.e39};
    r_8 tmax[3] = {-9.e39,-9.e39,-9.e39};
    for(sa_size_t jj=0; jj<mArr->Size(); jj++) {
      sa_size_t ix, iy, iz, it, iu;
      mArr->IndexAtPosition(jj, ix, iy, iz, it, iu);
      r_8 cv[3];
      cv[0] = (*mArr)(ix,iy,iz,it,iu).real();
      cv[1] = (*mArr)(ix,iy,iz,it,iu).imag();
      cv[2] = sqrt(cv[0]*cv[0]+cv[1]*cv[1]);
      for(int i=0; i<3; i++) {
	if (cv[i] < tmin[i]) tmin[i] = cv[i];
	if (cv[i] > tmax[i]) tmax[i] = cv[i];
      }
    }
    if (k == 7) { min = tmin[0]; max = tmax[0]; }
    else if (k == 8) { min = tmin[0]; max = tmax[0]; }
    else { min = tmin[2]; max = tmax[2]; }
  }
  else { min = max = 0.; }
  return;
}
DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
void NTupInt_TArray< complex<r_8> >::GetMinMax(sa_size_t k, double& min, double& max) const
{
  if (k == 0) {
    min = 0.; max = (r_8)(mArr->Size());  }
  else if (k == 1) {
    min = 0.; max = (r_8)(mArr->SizeX());  }
  else if (k == 2) {
    min = 0.; max = (r_8)(mArr->SizeY());  }
  else if (k == 3) {
    min = 0.; max = (r_8)(mArr->SizeZ());  }
  else if (k == 4) {
    min = 0.; max = (r_8)(mArr->Size(3));  }
  else if (k == 5) {
    min = 0.; max = (r_8)(mArr->Size(4));  }
  else if ((k >= 6) || (k <= 9)) {
    r_8 tmin[3] = {9.e39,9.e39,9.e39};
    r_8 tmax[3] = {-9.e39,-9.e39,-9.e39};
    for(sa_size_t jj=0; jj<mArr->Size(); jj++) {
      sa_size_t ix, iy, iz, it, iu;
      mArr->IndexAtPosition(jj, ix, iy, iz, it, iu);
      r_8 cv[3];
      cv[0] = (*mArr)(ix,iy,iz,it,iu).real();
      cv[1] = (*mArr)(ix,iy,iz,it,iu).imag();
      cv[2] = sqrt(cv[0]*cv[0]+cv[1]*cv[1]);
      for(int i=0; i<3; i++) {
	if (cv[i] < tmin[i]) tmin[i] = cv[i];
	if (cv[i] > tmax[i]) tmax[i] = cv[i];
      }
    }
    if (k == 7) { min = tmin[0]; max = tmax[0]; }
    else if (k == 8) { min = tmin[0]; max = tmax[0]; }
    else { min = tmin[2]; max = tmax[2]; }
  }
  else { min = max = 0.; }
  return;
}

#ifdef __CXX_PRAGMA_TEMPLATES__
#pragma define_template NOMAdapter_TArray<uint_1>
#pragma define_template NOMAdapter_TArray<uint_2>
#pragma define_template NOMAdapter_TArray<uint_4>
#pragma define_template NOMAdapter_TArray<uint_8>
#pragma define_template NOMAdapter_TArray<int_1>
#pragma define_template NOMAdapter_TArray<int_2>
#pragma define_template NOMAdapter_TArray<int_4>
#pragma define_template NOMAdapter_TArray<int_8>
#pragma define_template NOMAdapter_TArray<r_4>
#pragma define_template NOMAdapter_TArray<r_8>
#pragma define_template NOMAdapter_TArray< complex<r_4> >
#pragma define_template NOMAdapter_TArray< complex<r_8> >
#pragma define_template NTupInt_TArray<uint_1>
#pragma define_template NTupInt_TArray<uint_2>
#pragma define_template NTupInt_TArray<uint_4>
#pragma define_template NTupInt_TArray<uint_8>
#pragma define_template NTupInt_TArray<int_1>
#pragma define_template NTupInt_TArray<int_2>
#pragma define_template NTupInt_TArray<int_4>
#pragma define_template NTupInt_TArray<int_8>
#pragma define_template NTupInt_TArray<r_4>
#pragma define_template NTupInt_TArray<r_8>
#pragma define_template NTupInt_TArray< complex<r_4> >
#pragma define_template NTupInt_TArray< complex<r_8> >
#endif

#if defined(ANSI_TEMPLATES) 
template class NOMAdapter_TArray<uint_1>;
template class NOMAdapter_TArray<uint_2>;
template class NOMAdapter_TArray<uint_4>;
template class NOMAdapter_TArray<uint_8>;
template class NOMAdapter_TArray<int_1>;
template class NOMAdapter_TArray<int_2>;
template class NOMAdapter_TArray<int_4>;
template class NOMAdapter_TArray<int_8>;
template class NOMAdapter_TArray<r_4>;
template class NOMAdapter_TArray<r_8>;
template class NOMAdapter_TArray< complex<r_4> >;
template class NOMAdapter_TArray< complex<r_8> >;
template class NTupInt_TArray<uint_1>;
template class NTupInt_TArray<uint_2>;
template class NTupInt_TArray<uint_4>;
template class NTupInt_TArray<uint_8>;
template class NTupInt_TArray<int_1>;
template class NTupInt_TArray<int_2>;
template class NTupInt_TArray<int_4>;
template class NTupInt_TArray<int_8>;
template class NTupInt_TArray<r_4>;
template class NTupInt_TArray<r_8>;
template class NTupInt_TArray< complex<r_4> >;
template class NTupInt_TArray< complex<r_8> >;
#endif
