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

#include "../src/param.h"
#include "../src/tdef.h"
#include "../src/common.c"

#include "../src/libutility/utility.h"

#define MLAPM_HEADERSTRING  100      /* this value must agree with the value in param.h */
#define MLAPM_FILLHEADER (508-MLAPM_HEADERSTRING-4-5*8-4-6*8-20*4)


/*======================================================================
 *             THIS VERSION READS THE OLD MLAPM DATA FORMAT
 *                   THAT STORED "float numerics[]"
 *======================================================================*/
struct mlapm_header
{
  char          header[MLAPM_HEADERSTRING];
  long unsigned no_part;
  double        boxsize;
  double        omega0;
  double        lambda0;
  double        a_initial;
  double        a_current;
  int           no_timestep;
  double        K_initial;
  double        U_initial;
  double        K_current;
  double        U_current;
  double        Eintegral;
  double        Econst;
  float         numerics[20];
  char          dummy[MLAPM_FILLHEADER];
} mlapm_header;


int main(argc,argv)
int argc;
char **argv;
{
  long unsigned i,j,k,np,no_part;
  int           no_timestep, BUFSIZE, multi_mass, SWAPBYTES;
  float         w[7];
  float        *x, *y, *z, *vx, *vy, *vz, *m;
  double        v_mean;
  double        no_vpart;
  char          outdata[MAXSTRING], header[HEADERSTRING];
  FILE          *fpin, *fpout;
  float         weight;
  int           machine_sizeof_long;
  int           ino_part;
  long          lno_part;
  
  if(argc<3)
    {
      fprintf(stderr,"Use: %s MLAPM_file multi_mass\n",*argv);
      exit(1);
    }

  printf("=================================================\n");
  printf("  Read MLAPM output and convert to AMIGA binary\n");
  printf("=================================================\n");

  multi_mass = atoi(argv[2]);
  
  strcpy(outdata,argv[1]);
  strcat(outdata,".amiga");
  if(multi_mass)
     fprintf(stderr,"\n -> writing multi-mass AMIGA binary: %s\n\n",outdata);
  else
     fprintf(stderr,"\n -> writing single-mass AMIGA binary: %s\n\n",outdata);


  if((fpin=fopen(argv[1],"rb"))==NULL)
    {
      printf("I cannot open %s\n", argv[1]);
      exit(1);
    }

  if((fpout=fopen(outdata,"w"))==NULL)
    {
      printf("I cannot open %s\n", outdata);
      exit(1);
    }


  /* write sizeof(long) to file (also used for BYTESWAP testing) */
  machine_sizeof_long = sizeof(long);
  //machine_sizeof_long = 1;
  fwrite(&machine_sizeof_long, sizeof(int), 1, fpout);

  
  /* read in the CONTROL data */
#ifdef BYTESWAP
  
  SWAPBYTES = TRUE;
  
  /* read in IO header */
  ReadChars(fpin,mlapm_header.header,MLAPM_HEADERSTRING);
#ifdef LONG4
  ReadInt(fpin,&ino_part,SWAPBYTES);
  mlapm_header.no_part = (long unsigned) ino_part;
#else
  ReadLong(fpin,&lno_part,SWAPBYTES);
  mlapm_header.no_part = (long unsigned) lno_part;
#endif
  ReadDouble(fpin,&(mlapm_header.boxsize),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.omega0),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.lambda0),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.a_initial),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.a_current),SWAPBYTES);
  ReadInt(fpin,&(mlapm_header.no_timestep),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.K_initial),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.U_initial),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.K_current),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.U_current),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.Eintegral),SWAPBYTES);
  ReadDouble(fpin,&(mlapm_header.Econst),SWAPBYTES);
  for (i=0;i<20;i++)
     ReadFloat(fpin,&(mlapm_header.numerics[i]),SWAPBYTES);
#ifdef LONG4
  ReadChars(fpin,mlapm_header.dummy,MLAPM_FILLHEADER+4);
#else
  ReadChars(fpin,mlapm_header.dummy,MLAPM_FILLHEADER);
#endif
  
#else  /* BYTESWAP */
  
  SWAPBYTES = FALSE;
  
  if(fread(&(mlapm_header), sizeof(mlapm_header), 1, fpin) != 1)
    {
      perror("\n\ncould not read IO header\n");
      exit(1);
    }
#endif
  
  /* allocate arrays */
  no_part = mlapm_header.no_part;
  x  = (float *) calloc(no_part, sizeof(float));
  y  = (float *) calloc(no_part, sizeof(float));
  z  = (float *) calloc(no_part, sizeof(float));
  vx = (float *) calloc(no_part, sizeof(float));
  vy = (float *) calloc(no_part, sizeof(float));
  vz = (float *) calloc(no_part, sizeof(float));
  m  = (float *) calloc(no_part, sizeof(float));

  
  if(multi_mass)
     BUFSIZE = 7;
  else
     BUFSIZE = 6;
  
  /* convert particle information */
  fprintf(stderr," o reading %ld particles (%d) ... ",mlapm_header.no_part,BUFSIZE);
  no_vpart = 0.0;
  for(i=0;i<mlapm_header.no_part;i++)
    {
     
     /* read x,vx, y,vy, z,vz */
     for(j=X; j<=Z; j++)
       {
        ReadFloat(fpin,&w[2*j],SWAPBYTES);
        ReadFloat(fpin,&w[2*j+1],SWAPBYTES);
       }
     
     x[i]  = w[0];
     y[i]  = w[2];
     z[i]  = w[4];
     vx[i] = w[1];
     vy[i] = w[3];
     vz[i] = w[5];
     
     /* read mass */
     if(multi_mass)
       {
        ReadFloat(fpin,&w[6],SWAPBYTES);
        m[i]      = w[6];
        no_vpart += w[6];
       }
     else
        no_vpart += 1.0;
     }
  fprintf(stderr,"done\n");
  
  fclose(fpin);

  /* print some information */
  printf("some information about input file:\n");
  printf("==================================\n");
  printf("%s\n\n",mlapm_header.header);
  printf("no_part     = %ld\n",mlapm_header.no_part);
  printf("boxsize     = %g\n",mlapm_header.boxsize);
  printf("Omega0      = %g\n",mlapm_header.omega0);
  printf("Lambda0     = %g\n",mlapm_header.lambda0);
  printf("z_initial   = %g (a=%lf)\n",
         1.0/mlapm_header.a_initial-1.0,mlapm_header.a_initial);
  printf("z_current   = %g (a=%lf)\n",
         1.0/mlapm_header.a_current-1.0,mlapm_header.a_current);
  printf("no_timestep = %d\n",mlapm_header.no_timestep);
  printf("NGRID_DOM   = %g\n",mlapm_header.numerics[0]);
  printf("Nth_dom     = %g\n",mlapm_header.numerics[1]);
  printf("Nth_ref     = %g\n",mlapm_header.numerics[2]);
  printf("CELLFRAC    = %g\n",mlapm_header.numerics[3]);
  printf("timestep    = %g\n",mlapm_header.numerics[4]);
  printf("DOMSWEEPS   = %g\n",mlapm_header.numerics[5]);
  printf("REFSWEEPS   = %g\n",mlapm_header.numerics[6]);
  printf("ref level   = %g\n",mlapm_header.numerics[7]);
  printf("frc resol   = %g\n",mlapm_header.numerics[8]);
  printf("pmass       = %g\n",mlapm_header.numerics[9]);
  
  
  /* set header info for AMIGA binary */
  /* write IO header */
  strcpy(io.header.header,mlapm_header.header);
  io.header.multi_mass       = multi_mass;
  io.header.double_precision = 0;
  io.header.no_part          = mlapm_header.no_part;
  io.header.no_vpart         = no_vpart;
  io.header.boxsize          = mlapm_header.boxsize;
  io.header.omega0           = mlapm_header.omega0;
  io.header.lambda0          = mlapm_header.lambda0;
  io.header.a_initial        = mlapm_header.a_initial;
  io.header.a_current        = mlapm_header.a_current;
  io.header.no_timestep      = mlapm_header.no_timestep;
  io.header.K_initial        = mlapm_header.K_initial;
  io.header.U_initial        = mlapm_header.U_initial;
  io.header.K_current        = mlapm_header.K_current;
  io.header.U_current        = mlapm_header.U_current;
  io.header.Eintegral        = mlapm_header.Eintegral;
  io.header.Econst           = mlapm_header.Econst;
  io.header.paramNGRID_DOM   = mlapm_header.numerics[0];
  io.header.paramNth_dom     = mlapm_header.numerics[1];
  io.header.paramNth_ref     = mlapm_header.numerics[2];
  io.header.paramCELLFRAC_MAX= mlapm_header.numerics[3];
  io.header.timestep         = mlapm_header.numerics[4];
  io.header.paramDOMSWEEPS   = mlapm_header.numerics[5];
  io.header.paramREFSWEEPS   = mlapm_header.numerics[6];
  io.header.cur_reflevel     = mlapm_header.numerics[7];
  io.header.cur_frcres       = mlapm_header.numerics[8];
  io.header.pmass            = mlapm_header.numerics[9];
  io.header.version          = VERSION;
  io.header.built            = BUILT;
  
  
  fprintf(stderr,"\n o writing sizeof(io.header) = %d to file\n",sizeof(io.header));
  if(fwrite(&(io.header), sizeof(io.header), 1, fpout) != 1)
    {
	  perror("\n\ncould not write IO header\n");
	  exit(1);
    }
  
  fprintf(stderr," o writing %ld particles (%d) ... ",mlapm_header.no_part,BUFSIZE);
  for(i=0;i<mlapm_header.no_part;i++)
    {
     w[0] = x[i];
     w[2] = y[i];
     w[4] = z[i];
     w[1] = vx[i];
     w[3] = vy[i];
     w[5] = vz[i];
     
     if(multi_mass)
        w[6] = m[i];
     
     fwrite((void*)w,sizeof(float),BUFSIZE,fpout);
    }
  fprintf(stderr,"done\n");  
  
  fclose(fpout);
}

