/*
*===============================================================================
*
* d/wilson_d500/io.c 
*
*-------------------------------------------------------------------------------
*
* Copyright (C) 2006 Thomas Streuer 
*
* This file is part of BQCD -- Berlin Quantum ChromoDynamics program
*
* BQCD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* BQCD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with BQCD.  If not, see <http:*www.gnu.org/licenses/>.
*
*-------------------------------------------------------------------------------
*/
#include <stdio.h>
#include <errno.h>
#ifndef NO_MPI
#include <mpi.h>
#endif
#include <string.h>
#include <stdarg.h>
#include "defs.h"
#include "neighb.h"

void die(int retval, char* msg, ...)
{
  va_list v;
  va_start(v, msg);
  printf("[%3i] ", my_rank);
  vprintf(msg, v);
  va_end(v);
  printf("\n");
  exit(retval);
}


void read_whatever(char* fname, double* v, int sz)
{
  errno=0;
#ifndef NO_MPI
  MPI_Barrier(MPI_COMM_WORLD);
#endif
  int io_order=position[0]+grid[0]*(
    position[1]+grid[1]*(position[2]+grid[2]*position[3]));
  double* tmp=(double*) malloc(sz*VOL*sizeof(double));
  for (int i=0; i<num_procs; i++)
  {
    if (io_order==i)
    {
      FILE* f=fopen(fname, "r");
      if (errno)
	die(1, "Cannot open file %s:\n%s", fname, strerror(errno));
      fseek(f, i*sz*VOL*sizeof(double), SEEK_SET);
      fread(tmp, sizeof(double), sz*VOL, f);
/*       fread(v, sizeof(double), sz*VOL, f); */
      if (errno)
	die(1, "Cannot read file %s\n%s", fname, strerror(errno));
      fclose(f);   
      if (errno)
	die(1, "Cannot close file %s", fname);
    }
#ifndef NO_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
  }
  for (int x=0; x<VOL; x++)
  {
    int y=sort(x, 1);
    for (int i=0; i<sz; i++)
      v[sz*y+i]=tmp[sz*x+i];
  }
  free(tmp);
}

void read_vec(char* fname, double* U)
{
  read_whatever(fname, U, 24);
}

void read_gc(char* fname, double* U)
{
  read_whatever(fname, U, 72);
}

void write_whatever(char* fname, double* v, int sz)
{
  errno=0;
  double* tmp=(double*) malloc(sz*VOL*sizeof(double));
  for (int x=0; x<VOL; x++)
  {
    int y=sort(x, 0);
    for (int i=0; i<sz; i++)
      tmp[sz*y+i]=v[sz*x+i];
  }
  int io_order=position[0]+grid[0]*(
    position[1]+grid[1]*(position[2]+grid[2]*position[3]));
/*   int* order; */
/*   MPI_Status stat; */

/*   if (my_rank==0) */
/*   { */
/*     order=(int*) malloc(num_procs*sizeof(int)); */
/*     order[0]=0; */
/*     for (int i=1; i<num_procs; i++) */
/*       MPI_Recv(order+i, sizeof(int), MPI_BYTE, i, 0, */
/* 		   MPI_COMM_WORLD, &stat); */
/*   } */
/*   else */
/*     MPI_Send(&io_order, sizeof(int), MPI_BYTE, 0, 0, */
/* 	     MPI_COMM_WORLD); */

/*   if (my_rank==0) */
/*   { */
/*     FILE* f=fopen(fname, "w"); */
/*     if (errno) */
/*       die(1, "Cannot open file %s", fname); */
/*     size_t n_written=fwrite(tmp, sizeof(double), sz*VOL, f); */
/*     if (errno || (n_written!=sz*VOL)) */
/*       die(1, "Cannot write file %s", fname); */
/*     for (int i=1; i<num_procs; i++) */
/*     { */
/*       int j; */
/*       for (int k=0; k<num_procs; k++) */
/* 	if (order[k]==i) */
/* 	  j=k; */
/*       MPI_Recv(tmp, sizeof(double)*sz*VOL, MPI_BYTE, j, 0, */
/* 		   MPI_COMM_WORLD, &stat); */
/*       n_written=fwrite(tmp, sizeof(double), sz*VOL, f); */
/*       if (errno || (n_written!=sz*VOL)) */
/* 	die(1, "Cannot write file %s", fname); */
/*       printf("[%i/%i] written %i\n", j, num_procs, n_written*sizeof(double)); */
/*     } */
/*     fclose(f); */
/*   } */
/*   else */
/*     MPI_Send(tmp, sizeof(double)*sz*VOL, MPI_BYTE, 0, 0, */
/* 	     MPI_COMM_WORLD); */
/*   MPI_Barrier(MPI_COMM_WORLD); */
/*   return; */
  for (int i=0; i<num_procs; i++)
  {
    if (io_order==i)
    {
      FILE* f=fopen(fname, i==0? "w" : "a");
      if (errno)
	die(1, "Cannot open file %s", fname);
      size_t n_written=fwrite(tmp, sizeof(double), sz*VOL, f);
      if (errno || (n_written!=sz*VOL))
	die(1, "Cannot write file %s", fname);
      printf("[%i/%i] written %i\n", my_rank, num_procs, n_written*sizeof(double));
      fclose(f);
      if (errno)
	die(1, "Cannot close file %s", fname);
    }
#ifndef NO_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
  }
  free(tmp);
}

void write_vec(char* fname, double* U)
{
  write_whatever(fname, U, 24);
}

void write_gc(char* fname, double* U)
{
  write_whatever(fname, U, 72);
}

