/********************************************************************************************
 * transfers an ASCII file to AMIGA binary (just like ascii2amiga)
 * however, coordinates need not be in-between [0,box] but can be any value
 * the code calculates xmin/xmax, ymin/ymax, zmin/zmax and shifts the
 * data to the right place....
 ********************************************************************************************/

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

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

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

/* make simulation box larger than maximum extent of object */
#define BOXFACTOR 2.0

int main()
{
    long unsigned int  i, np, nx, multi_mass, double_precision, BUFSIZE;
    int                j, no_timestep, OVERREAD;
    double             box, omega0, lambda0, inv_mean_dens;
    double             z_initial, z_current, a_initial, a_current;
    double             x_fac, v_fac, m_fac, mmin;
    char               infile[MAXSTRING], outfile[MAXSTRING], header[HEADERSTRING], dummyline[MAXSTRING];
    double             r[3], v[3], mass, vmean;
    double             *x, *y, *z, *vx, *vy, *vz, *m;
    double             xmin,xmax,ymin,ymax,zmin,zmax;
    double	           dw[7];
    float              fw[7];
    int                machine_sizeof_long;
    
    FILE *fpin, *fpout;
    
    printf("===============================================\n");
    printf("  Read ASCII file and convert to AMIGA binary\n");
    printf("===============================================\n");
    printf("Please give name of input file:            ");
    scanf("%s",infile);
    printf("%s\n",infile);
    printf("\nPlease give no. of lines to ignore:        ");
    scanf("%d",&OVERREAD);
    printf("%d\n",OVERREAD);
    printf("Multi-Mass Simulation?      (1=yes/0=no):  ");
    scanf("%d",&multi_mass);
    printf("%d\n",multi_mass);
    printf("Double-Precison Simulation? (1=yes/0=no):  ");
    scanf("%d",&double_precision);
    printf("%d\n",double_precision);
    printf("Please give npart:                         ");
    scanf("%ld",&np);
    printf("%ld\n",np);
    printf("Please give min. particle mass [Msun/h]:   ");
    scanf("%lf",&m_fac);
    printf("%g",m_fac);
#ifdef ISOLATED
    omega0  = 1.0;
    lambda0 = 0.0;
#else
    printf("Please give omega0:                        ");
    scanf("%lf",&omega0);
    printf("%g\n",omega0);
    printf("Please give lambda0:                       ");
    scanf("%lf",&lambda0);
    printf("%g\n",lambda0);
#endif
    printf("Please give initial redshift:              ");
    scanf("%lf",&z_initial);
    printf("%g\n",z_initial);
    printf("Please give current redshift:              ");
    scanf("%lf",&z_current);
    printf("%g\n",z_current);
    printf("Please give current timestep no:           ");
    scanf("%d", &no_timestep);
    printf("%d\n",no_timestep);
    printf("\nPlease give name of output file:           ");
    scanf("%s",outfile);
    printf("%s\n",outfile);
    printf("\nPlease give descriptive header not longer than %d char's:\n",HEADERSTRING);
    scanf("%s",header);
    printf("%s\n",header);
    printf("\n");
    
    a_initial = 1.0/(1.0+z_initial);
    a_current = 1.0/(1.0+z_current);
    
    if((fpin=fopen(infile,"r"))==NULL)
      {
        printf("I cannot open %s\n", infile);
        exit(1);
      }
    
    if((fpout=fopen(outfile,"wb"))==NULL)
      {
        printf("I cannot open %s\n", outfile);
        exit(1);
      }
    
    /* write sizeof(long) to file (also used for BYTESWAP testing) */
    machine_sizeof_long = sizeof(long);
    fwrite(&machine_sizeof_long, sizeof(int), 1, fpout);
    
    /* write IO header */
    strcpy(io.header.header,header);
    io.header.multi_mass       = multi_mass;
    io.header.double_precision = double_precision;
    io.header.no_part          = np;
    io.header.omega0           = omega0;
    io.header.lambda0          = lambda0;
    io.header.a_initial        = a_initial;
    io.header.a_current        = a_current;
    io.header.no_timestep      = no_timestep;
    io.header.K_initial        = 0.0;
    io.header.U_initial        = 0.0;
    io.header.K_current        = 0.0;
    io.header.U_current        = 0.0;
    io.header.Eintegral        = 0.0;
    io.header.Econst           = 0.0;
    io.header.pmass            = m_fac;
    io.header.version          = VERSION;
    io.header.built            = BUILT;
    
    /* read in ASCII and write out AMIGA data */
    for(i=0; i<OVERREAD; i++)
      {
        fgets(dummyline,MAXSTRING,fpin);
      }
    if(OVERREAD > 0)
      {
        printf("\nlast line overread in ASCII input file:\n");
        printf("%s\n",dummyline);
      }
    

    x  = (double *) calloc(np, sizeof(double));
    y  = (double *) calloc(np, sizeof(double));
    z  = (double *) calloc(np, sizeof(double));
    vx = (double *) calloc(np, sizeof(double));
    vy = (double *) calloc(np, sizeof(double));
    vz = (double *) calloc(np, sizeof(double));
    if(multi_mass == 1)
      {
        BUFSIZE = 7;
        m       = (double *) calloc(np, sizeof(double));
      }
    else
      {
        BUFSIZE = 6;
      }
    
    vmean = 0.0;
    mmin  = 10000.;
    xmin  =  1000.;
    xmax  = -1000.;
    ymin  =  1000.;
    ymax  = -1000.;
    zmin  =  1000.;
    zmax  = -1000.;
    for(i=0; i<np; i++)
      {
        fgets(dummyline,MAXSTRING,fpin);
        
        if(multi_mass == 1)
          {
            sscanf(dummyline,"%lf %lf %lf %lf %lf %lf %lf",r,r+1,r+2,v,v+1,v+2,&mass);
            m[i] = mass;
            
            if(mass < mmin)
               mmin = mass;
          }
        else
          {
            sscanf(dummyline,"%lf %lf %lf %lf %lf %lf %lf",r,r+1,r+2,v,v+1,v+2);
          }
        
        vmean += sqrt(pow2(v[0]) + pow2(v[1]) + pow2(v[2]));
        
        r[0] /= 1000.;
        r[1] /= 1000.;  /* convert to Mpc */
        r[2] /= 1000.;

        x[i]  = r[0];
        y[i]  = r[1];
        z[i]  = r[2];
        vx[i] = v[0];
        vy[i] = v[1];
        vz[i] = v[2];
        
        if(r[0] > xmax) xmax = r[0];
        if(r[0] < xmin) xmin = r[0];
        if(r[1] > ymax) ymax = r[1];
        if(r[1] < ymin) ymin = r[1];
        if(r[2] > zmax) zmax = r[2];
        if(r[2] < zmin) zmin = r[2];

      }

    printf("mean velocity = %g\n", vmean/(double)np);

    xmax -= xmin;
    ymax -= ymin;
    zmax -= zmin;

    box               = MAX(xmax,ymax);
    box               = MAX(zmax,box);
    box              *= BOXFACTOR;
    io.header.boxsize = box;
    
    printf("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);
      }
    

    x_fac     = 1.0 / box;
    v_fac     = a_current / (box*H0);
#ifdef XDOT
    v_fac     = a_current*a_current / (box * H0);
#endif
#ifdef ISOLATED
    v_fac     = 1.0 / (box * H0);
#endif
    for(i=0; i<np; i++)
      {
        /* shift to left edge */
        x[i] -= xmin;
        y[i] -= ymin;
        z[i] -= zmin;
        
        /* add offset */
        x[i] += box/(2.*BOXFACTOR);
        y[i] += box/(2.*BOXFACTOR);
        z[i] += box/(2.*BOXFACTOR);

        /* scale coordinates to [0,1] */
        dw[0] = fmod(x[i] * x_fac + 1.0, 1.0);
        dw[2] = fmod(y[i] * x_fac + 1.0, 1.0);
        dw[4] = fmod(z[i] * x_fac + 1.0, 1.0);
        
        /* scale velocities */
        dw[1] = (vx[i] * v_fac);
        dw[3] = (vy[i] * v_fac);
        dw[5] = (vz[i] * v_fac);
        
        if(io.header.multi_mass)
            dw[6] = m[i]/mmin;
        
        if(double_precision == 1)
          {
            fwrite((void*)dw,sizeof(double),BUFSIZE,fpout);
          }
        else
          {
            for(j=0; j<BUFSIZE; j++)
                fw[j] = (float)dw[j];
            fwrite((void*)fw,sizeof(float),BUFSIZE,fpout);
          }
        
      }
    
    
    fclose(fpin);
    fclose(fpout);
}

