/*******************************************************************************
*
* McStas, the neutron ray-tracing package: Vitess_input.comp
*         Copyright 1997-2001 Risoe National Laboratory, Roskilde, Denmark
*
* Component: Vitess_input
*
* %I
* Written by: Kristian Nielsen
* Date: June 6, 2000
* Origin: Risoe/ILL
* Modified by: E. Farhi, Sep 28th, 2001: added spin
*
* Read neutron state parameters from VITESS neutron filename.
*
* %D
* Source-like component reading neutron state parameters from a
* VITESS neutron filename. Used to interface McStas components or
* simulations into VITESS. Each neutron is 104 bytes.
*
* Example: Vitess_input(filename="MySource.vit", bufsize = 10000, repeat_count = 2)
*
* %BUGS
* We recommend NOT to use parallel execution (MPI) with this component.
*
* %P
* INPUT PARAMETERS
*
* filename: [string]  Filename of neutron file to read. Default (NULL) is standard input. Empty string "" unactivates component 
* bufsize: [records]  Size of neutron input buffer 
* repeat_count: [1]   Number of times to repeat each neutron read 
*
* OUTPUT PARAMETERS
*
* finished: [int]     Set to 1 when the last neutron has been read 
*
* %E
*******************************************************************************/


DEFINE COMPONENT Vitess_input
DEFINITION PARAMETERS ()
SETTING PARAMETERS (string filename = 0, int bufsize = 10000, repeat_count = 1)
OUTPUT PARAMETERS ()
/* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */
SHARE
%{
%include "general"
%include "vitess-lib"
%}

DECLARE
%{
char *file;		/* path + filename */
FILE *hfile;		/* Neutron input filename handle */
Neutron *ibuf;	/* Neutron input buffer */
int size;		/* Number of neutrons currently in buffer */
int pos;		/* Current position in buffer */
int rep;		/* Neutron repeat count */
int finished;		/* Set to 1 when last neutron read */
%}

INITIALIZE
%{
file=NULL;
hfile=NULL;
ibuf=NULL;
size=0;
pos=0;
rep=0;
finished=0;

/* Open neutron input filename. */
if (!filename || !strcmp(filename,"NULL") || !strcmp(filename,"0") || !strcmp(filename,"stdin")) {
    hfile = stdin;
  } else if (!strlen(filename)) {
    hfile = NULL;
  } else {
    hfile = fopen((file=FullParName(filename)), "rb");
    if(!hfile) {
      fprintf(stderr, "Vitess_input: Error: Cannot open input file %s.\n", file);
      exit(1);
    }
  }
#ifdef WIN32
  if(hfile==stdin)
  { if( _setmode(_fileno( stdin ), _O_BINARY ) == -1)
    { fprintf(stderr,"Can't set stdin to binary mode\n");
      exit(1);
    }
  }
#endif
  if (hfile) {
    /* Allocate neutron input buffer. */
    ibuf = calloc(bufsize, sizeof(Neutron));
    if(!ibuf)
    {
      fprintf(stderr, "Vitess_input: Error: Cannot allocate neutron buffer.\n");
      exit(1);
    }
  }
%}

TRACE
%{
  if (hfile && ibuf) {
    if(pos >= size) {
      /* Buffer is empty. */
      size = fread(ibuf, sizeof(Neutron), bufsize, hfile);
      if(size <= 0) {
        if(ferror(hfile))
          fprintf(stderr, "Vitess_input: Error during read of neutron file %s.\n", file);
        if(feof(hfile) || ferror(hfile))
          finished = 1;		/* End of filename or error reached */
      } else {
        pos = 0;			/* Reposition at start of buffer */
      }
    }
    /* When no more neutron records are available in the neutron filename,
      any remaining iterations are skipped by immediately ABSORB'ing
      the neutron. */
    if(finished)
      ABSORB;
    vitess2mcstas(ibuf[pos], &x, &y, &z, &vx, &vy, &vz, &t, &sx, &sy, &sz, &p);
    /* The following three lines have references to things that are no longer
      in the McStas vitess libs */
    /*  vitess_col       =      ibuf[pos].Color;
        vitess_ID.IDNo   =      ibuf[pos].ID.IDNo;
        memcpy(vitess_ID.IDGrp, ibuf[pos].ID.IDGrp, 2); */

    /* Repeat the same neutron state parameters the required number of
      times. */
    ++rep;
    if(rep >= repeat_count) {
      rep = 0;
      ++pos;
    }
  }
%}
FINALLY
%{
  if(hfile && ibuf)
    free(ibuf);
  if(hfile && filename)
    fclose(hfile);
%}
MCDISPLAY
%{
  /* Invisible component. */
%}

END
