/*******************************************************************************
*
* McXtrace, x-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: Shadow_output
*
* %Identification
* Written by: Andrea Prodi
* Date: November 21, 2011
* Origin: Risoe/ILL
* Release: McXtrace 0.1
*
* Write x-ray state parameters to SHADOW x-ray event file.
*
* %Description
* Detector-like component writing x-ray state parameters to a
* SHADOW x-ray file. Used to interface McXtrace components or
* simulations into SHADOW. Each photon is 104 bytes.
*
* Note that when standard output is used, as is the default, no
* monitors or other components that produce terminal output must be
* used, or the x-ray output from this component will become
* corrupted.
*
* Example: Shadow_output(file="MySource.vit", bufsize = 10000, progress = 1)
*
* %Parameters
* INPUT PARAMETERS
*
* file:     [string]  Filename of x-ray file to write. Default is standard output
* bufsize:  [records] Size of x-ray output buffer
* progress: [flag]    If not zero, output dots as progress indicator
*
* %End
*******************************************************************************/


DEFINE COMPONENT Shadow_output

SETTING PARAMETERS (string file="", int bufsize=1000, int progress=0)

/*STATE PARAMETERS (x,y,z,kx,ky,kz,phi,t,Ex,Ey,Ez,p)*/

SHARE
%{
%include "shadow-lib"
%}

DECLARE
%{
  char* filename; /* path + filename             */
  FILE* hfile;    /* X-ray output file handle    */
  Ray* obuf;      /* X-ray output buffer         */
  int pos;        /* Current position in buffer  */
  int reclen;     /* Fortran binary unformatted sequential record head/tail */
  int ncol;
  int i;
  int iflag;
  double p_out;  /* sum of output weight        */
  double p2_out; /* square sum of output weight */
%}

INITIALIZE
%{
  ncol = 18; /* num column fixed at 18 for McXtrace->Shadow */
  iflag = 0; /* Shadow flag must be set to zero !!! */
  /* Open x-ray output file. */
  if (file == NULL) {
    hfile = stdout;
  } else if (!strcmp (file, "no_file")) {
    hfile = NULL;
  } else {
    hfile = fopen ((filename = FullParName (file)), "wb");
    if (!hfile) {
      fprintf (stderr, "Shadow_output: Error: Cannot open output file %s.\n", filename);
      exit (1);
    }
  }
  #ifdef WIN32
  if (hfile == stdout) {
    if (_setmode (_fileno (stdout), _O_BINARY) == -1) {
      fprintf (stderr, "Can't set stdout to binary mode\n");
      exit (1);
    }
  }
  #endif
  /* Write header for Shadow data file. */
  reclen = 3 * sizeof (int);
  fwrite (&reclen, sizeof (int), 1, hfile);
  fwrite (&ncol, sizeof (int), 1, hfile);
  fwrite (&bufsize, sizeof (int), 1, hfile);
  fwrite (&iflag, sizeof (int), 1, hfile);
  fwrite (&reclen, sizeof (int), 1, hfile);

  /* Allocate x-ray output buffer. */
  reclen = ncol * sizeof (double);
  obuf = calloc (bufsize, reclen + 2 * sizeof (int));

  if (!obuf) {
    fprintf (stderr, "Shadow_output: Error: Cannot allocate x-ray buffer.\n");
    exit (1);
  }
  /* Initialize buffer. */
  pos = 0;
%}

TRACE
%{
  int count;

  /* Flush output buffer if full. */
  if (hfile && pos >= bufsize) {
    count = fwrite (obuf, sizeof (Ray), bufsize, hfile);
    if (progress) {
      fputc ('.', stderr); /* Output progress indicator. */
      fflush (stderr);
    }
    if (count != bufsize) {
      fprintf (stderr, "Shadow_output: Error during write of x-ray file.\n");
      exit (1);
    } else {
      pos = 0; /* Reposition at start of buffer */
    }
  }
  /* the variable mcrun_num is used as ray index for Shadow */
  obuf[pos] = mcxtrace2shadow (x, y, z, kx, ky, kz, phi, t, Ex, Ey, Ez, p, mcrun_num); /*pos instead of mcrun_num?*/

  p_out += p;
  p2_out += p * p;

  ++pos;
%}
FINALLY
%{
  int count, dum;

  /* Flush output buffer if necessary. */
  if (hfile && pos > 0) {

    /*  count = fwrite(obuf, sizeof(Ray), pos, hfile); */
    for (i = 0; i < pos; i++) {
      fwrite (&reclen, sizeof (int), 1, hfile);
      dum = fwrite (&obuf[i], sizeof (Ray), 1, hfile);
      fwrite (&reclen, sizeof (int), 1, hfile);
      count += dum;
    }

    if (count != pos) {
      fprintf (stderr, "Shadow_output: Error during write of x-ray event file.\n");
      exit (1);
    }
  }
  if (progress)
    fprintf (stderr, ".\n"); /* Output final progress indicator. */
  if (obuf)
    free (obuf);
  if (hfile && file)
    fclose (hfile);
%}
MCDISPLAY
%{
  /* Invisible component. */
%}

END
