#include "machdefs.h"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <complex>
#include <unistd.h>
#include "ntoolsinit.h"
#include "pexceptions.h"
#include "ndatablock.h"

void  Fonction(NDataBlock<r_4> Arg);
NDataBlock<r_4> Fonction2(NDataBlock<r_4> Arg);

void  Fonction(NDataBlock<r_4> Arg)
{
cout<<"Fonction: arg.Size()="<<Arg.Size()<<" arg.Data()="<<Arg.Data()<<endl;
}
NDataBlock<r_4> Fonction2(NDataBlock<r_4> Arg)
{
cout<<"Fonction2: arg.Size()="<<Arg.Size()<<" arg.Data()="<<Arg.Data()<<endl;
return Arg;
}

//////////////////////////////////////////////////////////////////////////////
int main(int narg,char *arg[])
{
//-- Decodage arguments
int lp = 0;
char c;
while((c = getopt(narg,arg,"hd:")) != -1) {
  switch (c) {
  case 'd' :
    sscanf(optarg,"%d",&lp);
    break;
  case 'h' :
    cout<<"tstndblk [-h] [-d debug_level]"<<endl;
    exit(-1);
  }
}

//-- Initialization
SophyaInit();
const int NDim = 8;
r_4 *x1 = new r_4[NDim];
r_4 *x2 = new r_4[NDim];
r_4 *x3 = new r_4[NDim];
for(int k=0;k<NDim;k++)
  {x1[k]=k+1; x2[k]=(k+1)*10; x3[k]=(k+1)*100;}

NDataBlock<int_4>::SetPrintDebug(lp);
NDataBlock<r_4>::SetPrintDebug(lp);
NDataBlock<r_8>::SetPrintDebug(lp);
NDataBlock< complex<r_4> >::SetPrintDebug(lp);
NDataBlock< complex<r_8> >::SetPrintDebug(lp);

{  // Pour voir explicitement le travail du destructeur

//-----------------------------------------------------
cout<<endl<<"Createur par defaut Va"<<endl;
NDataBlock<int_4> V1; V1.Print(1,99);
try {
  cout<<endl<<"...Createur par copie V2e(V1)"<<endl;
  NDataBlock<int_4> V2e(V1);
} catch(PException exc) {
  cout<<"...Exception catched : " << exc.Msg() << endl;
} 

//-----------------------------------------------------
cout<<endl<<"Createur A1(3)"<<endl;
NDataBlock<r_4> A1(3);
cout<<endl<<"Createur B1("<<NDim<<")"<<endl;
NDataBlock<r_4> B1(NDim);
A1.FillFrom(NDim,x1); A1.Print(0,999);
B1.FillFrom(NDim,x1); B1.Print(0,999);

cout<<endl<<"Createur A2(3)"<<endl;
NDataBlock<r_4> A2(3);
A2.FillFrom(NDim,x2); A2.Print(0,999);
cout<<endl<<"Createur B2("<<NDim<<")"<<endl;
NDataBlock<r_4> B2(NDim);
B2.FillFrom(NDim,x2); B2.Print(0,999);

cout<<endl<<"Createur A3(3)"<<endl;
NDataBlock<r_4> A3(3);
A3.FillFrom(NDim,x3); A3.Print(0,999);
cout<<endl<<"Createur B3("<<NDim<<")"<<endl;
NDataBlock<r_4> B3(NDim);
B3.FillFrom(NDim,x3); B3.Print(0,999);

//-----------------------------------------------------
cout<<endl<<"Createur par copie AA1(A1)"<<endl;
NDataBlock<r_4> AA1(A1);

cout<<endl<<"Createur par copie BB1(B1)"<<endl;
NDataBlock<r_4> BB1(B1);

{cout<<endl<<"Createur par copie {BBB1(B1)}"<<endl;
NDataBlock<r_4> BBB1(B1);}

{cout<<endl<<"Createur avec bridge {Abr("<<NDim<<",x3,new Bridge)}"<<endl;
NDataBlock<r_4> Abr(NDim,x3,new Bridge);
Abr.Print(0,999);
cout<<"x3 existe encore: "<<x3[0]<<",...,"<<x3[4]<<endl;}

{cout<<endl<<"Createur avec bridge {Abr("<<NDim<<",dum,NULL)}"<<endl;
r_4 *dum = new r_4[10];
for(int i=0;i<10;i++) dum[i] = 1000.+i;
NDataBlock<r_4> Abr(10,dum);
Abr.Print(0,999);}

//-----------------------------------------------------
cout<<endl<<"Passage par argument a une fonction"<<endl;
NDataBlock<r_4> Arg;
cout<<"... Argument cree par defaut"<<endl;
Fonction(Arg);
cout<<"... Argument normal"<<endl;
Fonction(A1);

cout<<endl<<"Passage par argument a une fonction avec retour d un NDataBlock"<<endl;
cout<<"... Argument cree par defaut"<<endl;
NDataBlock<r_4> fdum = Fonction2(Arg); cout<<fdum;
NDataBlock<r_4> fdum1(Fonction2(Arg)); cout<<fdum1;
cout<<"... Argument normal"<<endl;
NDataBlock<r_4> fdum2 = Fonction2(A1); cout<<fdum2;
NDataBlock<r_4> fdum3(Fonction2(A1)); cout<<fdum3;

//-----------------------------------------------------
cout<<endl<<endl;
NDataBlock<r_4> AC(3);
AC.Reset();
cout<<endl<<"AC=2"<<endl;
AC = 2; AC.Print(0,999);
AC.Reset();
cout<<endl<<"AC=A1"<<endl;
AC = A1; AC.Print(0,999);

//-----------------------------------------------------
cout<<endl<<endl;
AC.Reset();
cout<<endl<<"AC+=2"<<endl;
AC += 2; AC.Print(0,999);
cout<<endl<<"AC+=2+3"<<endl;
AC += 2+3; AC.Print(0,999);
cout<<endl<<"AC+=3"<<endl;
AC += 3; AC.Print(0,999);
cout<<endl<<"AC-=3"<<endl;
AC -= 3; AC.Print(0,999);
cout<<endl<<"AC*=10"<<endl;
AC *= 10; AC.Print(0,999);
cout<<endl<<"AC/=10"<<endl;
AC /= 10; AC.Print(0,999);

//-----------------------------------------------------
cout<<endl<<endl;
AC.Reset(1000);
cout<<endl<<"AC+=A1"<<endl;
AC += A1; AC.Print(0,999);
cout<<endl<<"AC-=A1"<<endl;
AC.Reset(1000);
AC -= A1; AC.Print(0,999);
cout<<endl<<"AC*=A1"<<endl;
AC.Reset(1000);
AC *= A1; AC.Print(0,999);
cout<<endl<<"AC/=A1"<<endl;
AC.Reset(1000);
AC /= A1; AC.Print(0,999);

//-----------------------------------------------------
cout<<endl<<endl;
cout<<endl<<"AC=A1+2"<<endl;
AC = A1+2.f; AC.Print(0,999);
cout<<endl<<"AC=2+A1"<<endl;
AC = 2.f+A1; AC.Print(0,999);
cout<<endl<<"AC=A1*2"<<endl;
AC = A1*2.f; AC.Print(0,999);
cout<<endl<<"AC=2*A1"<<endl;
AC = 2.f*A1; AC.Print(0,999);
cout<<endl<<"AC=A1-2"<<endl;
AC = A1-2.f; AC.Print(0,999);
cout<<endl<<"AC=2-A1"<<endl;
AC = 2.f-A1; AC.Print(0,999);
cout<<endl<<"AC=A1/2"<<endl;
AC = A1/2.f; AC.Print(0,999);
cout<<endl<<"AC=2/A1"<<endl;
AC = 2.f/A1; AC.Print(0,999);

//-----------------------------------------------------
cout<<endl<<endl;
cout<<endl<<"AC=A1+A2"<<endl;
AC = A1 + A2; AC.Print(0,999);
cout<<endl<<"AC=A2-A1"<<endl;
AC = A2 - A1; AC.Print(0,999);
cout<<endl<<"AC=A1*A2"<<endl;
AC = A1 * A2; AC.Print(0,999);
cout<<endl<<"AC=A2/A1"<<endl;
AC = A2 / A1; AC.Print(0,999);

//-----------------------------------------------------
cout<<endl<<endl;
cout<<endl<<"AC=A1+A2+A3"<<" "<<&A1<<","<<&A2<<","<<&A3<<endl;
AC = A1 + A2 + A3; AC.Print(0,999);


cout<<"\n\n\n"<<endl;
}  // Pour voir explicitement le travail du destructeur
cout<<"Fin du Job"<<endl;
cout<<"delete x1"<<endl; delete [] x1;
cout<<"delete x2"<<endl; delete [] x2;
cout<<"delete x3"<<endl; delete [] x3;

//---- Final debug print
cout<<endl<<endl<<"FINAL DEBUG SUMMARY : lp="<<lp<<endl<<endl;
cout<<"DEBUG int_4:\n";        NDataBlock<int_4>::PrintDebug();
cout<<"DEBUG r_4:\n";          NDataBlock<r_4>::PrintDebug();
cout<<"DEBUG r_8:\n";          NDataBlock<r_8>::PrintDebug();
cout<<"DEBUG complex<r_4>:\n"; NDataBlock< complex<r_4> >::PrintDebug();
cout<<"DEBUG complex<r_8>:\n"; NDataBlock< complex<r_8> >::PrintDebug();

exit(0);
}
