#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include <iostream>

#include "sopnamsp.h"
#include "pisysdep.h"

#include PIAPP_H
#include PIMENU_H 
#include PISTDWDG_H 
#include PIWIN_H
#include PIPERIODIC_H

#include "piscdrawwdg.h"
#include "piimage.h"
#include "parradapter.h"

#include "psfile.h"

#include "piimgtools.h"
#include "pidrwtools.h"

#include "pisurfdr.h"
#include "piyfxdrw.h"

#include "pi3dwdg.h"

//  ---------- classe PITApp -----------------------
class PITApp : public PIApplication {
public:
     PITApp(int narg=0, char* arg[]=NULL);
     ~PITApp();
     virtual void   Process(PIMessage msg, PIMsgHandler* sender, void* data=NULL);

  PIMenu* m[2];
  PIPixmap* zoom;  
  PIWindow *mCurW;
};


/* --Methode-- */
PITApp::PITApp(int narg, char* arg[])
: PIApplication(250, 130, narg, arg) 
{

// Menu creation 
// First menu 
m[0] = new PIMenu(Menubar(),"Fichier");
// Show Image Tools window
m[0]->AppendItem("ShowImageTools", 10101);    
// Show drawer Tools (Graphic Att.) window
m[0]->AppendItem("ShowDrawerTools", 10102);   
// Creating eps file from a graphic / image
m[0]->AppendItem("PostScript (EPS)", 10105);  
m[0]->AppendItem("Exit", 10150);
// Appending menu to menu bar 
AppendMenu(m[0]);

// 2nd Menu
m[1] = new PIMenu(Menubar(),"Graphics");
m[1]->AppendItem("2-Drawers", 10201); //  2D drawer superposition 
m[1]->AppendItem("Surf-3D", 10202);   //  Surface (3D) drawer
m[1]->AppendItem("Image", 10203);     //  Image view object
// Appending menu to menu bar 
AppendMenu(m[1]);

// Creating Zoom PixMap for PIImage
zoom = new PIPixmap(MainWin(), "Zoom", 150, 120, 5, 5);
zoom->SetBinding(PIBK_elastic,PIBK_elastic,PIBK_elastic,PIBK_elastic);
mCurW = NULL;
SetReady();
}

/* --Methode-- */
PITApp::~PITApp()
{
for(int i=0; i<2; i++)  delete m[i]; 
delete zoom;
}  

static int nbwin = 0;
static int numpsf = 0;
static int fgswcol = 0;

// Sin(x)/x function 
static double fsinc(double x) 
{ if ( (x>-1.e-8) && (x<1.e-8) ) return(0.); else return (sin(x)/x); }
// fill 50x50 array
static float *  surf_fill_matx();   
// fill sx * sy array with random stars
static float *  img_fill_array(int sx, int sy);   

/* --Methode-- */
void PITApp::Process(PIMessage msg, PIMsgHandler* sender, void* data)
{
char strg[64];
int i,j;

// Defining ative window 
if ( ModMsg(msg) == PIMsg_Active) {
  PIWdg *sndw = (PIWdg *)sender;      
  if (sndw->kind() ==  PIWindow::ClassId) mCurW = (PIWindow *)sender;
  return;
}

switch(UserMsg(msg))
  {
// --------- 1st menu ----------
  case 10101 :
    PIImgTools::ShowPIImgTools();    // Image tools window
    break;
  case 10102 :
    PIDrwTools::ShowPIDrwTools();    // drawer tool (graphic att. window)
    break;

  case 10105 :                       // Creating eps file
    if(mCurW) {
      char buff[64];
      sprintf(buff, "xp3_%d.eps", numpsf);        numpsf++;
      printf("Creating EPS File %s (Encapsulated PostScript) \n", buff);
      PSFile *mps;
      mps = new PSFile(buff);
      mCurW->PSPrint(mps,0,0);
      delete mps;
      }
      break;

  case 10150:                        // Exit 
    Stop();
    break;


// ----------  2nd menu --------
  case 10201 :    // FunDrawer + PIYfXDrawer
    {
    // Creating two tables y[k] = 3 cos(x[k]) + 2 sin(x[k])
    float* vpx = new float[30]; 
    float* vpy = new float[30]; 
    int i;   double x;
    for(i=0; i<30; i++) { x = 8.*i/30;  vpx[i] = x;  vpy[i] = 3*cos(x)+2*sin(x); }
      
    // Using PIYfXDrawer and P1DAdapter<T> 
    PIYfXDrawer* mxyd = new PIYfXDrawer(new P1DAdapter<float>(vpx, 30, true), 
                                  new P1DAdapter<float>(vpy, 30, true), true); 
    // Changing graphic attributes for the drawer
    mxyd->GetGraphicAtt().SetColAtt(PI_Magenta);
    mxyd->GetGraphicAtt().SetMarkerAtt(7, PI_FBoxMarker);

    // Using PIFuncDrawer and changing its attributes
    PIFuncDrawer* mfd = new PIFuncDrawer(fsinc);
    mfd->GetGraphicAtt().SetColAtt(PI_Blue);
    mfd->GetGraphicAtt().SetLineAtt(PI_NormalLine);

    nbwin++; sprintf(strg,"2D Graphics (PI W %d)", nbwin);
    // Creating a window 
    PIWindow* awp = new PIWindow(this, strg, PIWK_normal, 400, 400, 300, 300);
    // Creating a PIScDrawWdg (manages drawers with zoom, ... capabilities)
    PIScDrawWdg* scd = new PIScDrawWdg(awp, "scwdg-YfX", 400, 400, 0, 0);
    scd->SetBinding(PIBK_fixed,PIBK_fixed,PIBK_fixed, PIBK_fixed);

    // Adding the two drawers to  PIScDrawWdg
    scd->AddScDrawer(mxyd,true);
    scd->AddScDrawer(mfd,true);
    scd->SetTitles(" --- PIYfXDrawer + PIFuncDrawer --- ", "");
    awp->SetAutoDelChilds(true);
    awp->Show();
    }
   break;

   case 10202:   //  3D surface drawer         
    {
    float * tf = surf_fill_matx();   // Creating and filling a 50x50 Matrix 
    // Creating a new window
    nbwin++; sprintf(strg,"PI W# %d 3D Surf", nbwin);
    PIWindow* awp = new PIWindow(this, strg, PIWK_normal, 500, 500, 200, 200);
    // Creating a 3-D surface drawer , using 2D array adapter (P2DAdapter<float>)
    PISurfaceDrawer* sd = new PISurfaceDrawer(
                  new P2DAdapter<float>(tf, 50, 50, true), true, true, true);
    // Selecting color map
    if (fgswcol%3 == 0) sd->GetGraphicAtt().SetColMapId(CMAP_COLRJ32);
    else if (fgswcol%3 == 1) sd->GetGraphicAtt().SetColMapId(CMAP_COLBR32);
    else sd->GetGraphicAtt().SetColMapId(CMAP_GREY32);
    fgswcol++;
    // Creating a 3D Widget (managing 3D-Drawers, rotation , ... )
    PIDraw3DWdg* drw3 = new PIDraw3DWdg(awp, "ex3ddrw", 600, 600, 0, 0);
    drw3->SetBinding(PIBK_fixed , PIBK_fixed , PIBK_fixed, PIBK_fixed);
    // Adding the drawer
    drw3->AddDrawer3D(sd, false);
    drw3->SetTitles(" --- PISurfaceDrawer (50x50) --- ", "");
    // Showing the window
    awp->SetAutoDelChilds(true);
    awp->Show();
    }
    break;

  case 10203 :     // Image display
    {
    int sx, sy;
    sx = 400; 
    sy = 600;
    float * img = img_fill_array(sx, sy);   // Creating and filling a 400x600 array 
   
    // Creating a new window  
    nbwin++; sprintf(strg,"Image (PI W %d)", nbwin);
    PIWindow* awp = new PIWindow(this, strg, PIWK_normal, sx, sy, 300, 300);
    // Creating an image view object PIImage
    PIImage * pii = new PIImage(awp, "fitsimage", sx, sy, 0, 0);
    pii->SetBinding(PIBK_fixed, PIBK_fixed, PIBK_fixed, PIBK_fixed);
    pii->SetZoomWin(zoom, false);  // assigning zoom Pixmap 
    pii->ShowCursor(true);
    // Showing the window
    awp->SetAutoDelChilds(true);
    awp->Show();
    // Assigning data to PIImage object, using 2D array adapter P2DAdapter<float>
    pii->SetImage(new P2DAdapter<float>(img, sx, sy, true), true);
    }
    break;

    default :
//      printf("PITApp::Process() Msg= %d (%d - %d)??? \n", 
//            (int)msg, (int)UserMsg(msg),(int)ModMsg(msg));
     break;
    }
  
return;
}



// ................................................................
//                     main program 
// ................................................................

int main(int narg, char *arg[])
{
if ( (narg > 1) && (strcmp(arg[1],"-h") == 0) ) {
  printf("xp3 : PI graphic object example program \n");
  printf("  Usage : xp3 [Xt options] \n");
  }

// Creating and running the application
PITApp* app = new PITApp(narg, arg);
app->Run();

delete app;
exit(0);
}

// -------------------------------------------------------
// ---- test function to fill 50x50 matrix ----
static float *  surf_fill_matx()
{
float * tf =   new float[2500];
int i,j;
double xp,yp,rp;
for(i=0; i<50; i++)
  for(j=0; j<50; j++) { 
    xp = i-15;   yp = j-25;
    rp = (xp*xp)/16.+(yp*yp)/16.;
    tf[j*50+i] = 11.*exp(-rp);
    xp = i-35;   yp = j-15;
    rp = (xp*xp)/9.+(yp*yp)/9.;
    tf[j*50+i] += 3.*exp(-rp);
    xp = i-45;   yp = j-40;
    rp = (xp*xp)/10.+(yp*yp)/20.;
    tf[j*50+i] += 6.*exp(-rp);
    }
return(tf);
}

//---- test function to fill an image array (with random stars) ----
static float *  img_fill_array(int sx, int sy)
{
  float* img = new float[sx*sy];
  int i, j, k, kk, i0, j0;
  double lamp, amp,x,y;
  for(k=0; k<sx*sy; k++)   img[k] = 1000.+(random()%200-100);
//   On genere 500 etoiles
  for(k=0; k<500; k++) {
    i0 = 20+random()%(sx-20);
    j0 = 20+random()%(sy-20);
    lamp = 2.0+0.012*(random()%100);
    amp = pow(10., lamp);
//        if (k%5 == 0)  printf(" DBG %d %d - %g \n", i0, j0, flux);
    for(i=i0-15; i<i0+15; i++) {
      if(i<0 || i>=sx) continue;
      for(j=j0-15; j<j0+15; j++) {
	if(j<0 || j>=sy) continue;
	x = i-i0;  y = j-j0;
	kk = j*sx+i;
	img[kk] += amp*exp(-(x*x)/7.-(y*y)/8.);
      }
    }
  }
  return(img);
}

