/*
*===============================================================================
*
* d/wilson_d520/io.c
*
*-------------------------------------------------------------------------------
*
* Copyright (C) 2010 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 "globals.h"
#include "lattice_testing.h"
#include "memory.h"
#include "neighb.h"

#include <stdio.h>
#include <errno.h>
#include <mpi.h>
#include <string.h>
#include <stdarg.h>

void die(char* msg, ...)
{
  va_list v;
  va_start(v, msg);
  fprintf(stderr, "[%3i] ", my_rank);
  vfprintf(stderr, msg, v);
  va_end(v);
  fprintf(stderr, "\n");
  exit(1);
}

// r: re-order indices

static void read_whatever(char* fname, double* v, int sz, unsigned r)
{
  MPI_Barrier(MPI_COMM_WORLD);
  unsigned io_order = position[0] + grid[0]*(
    position[1] + grid[1] * (position[2] + grid[2] * position[3]));
  double* tmp=(double*) malloc(sz * volume * sizeof(double));
  for (unsigned i=0; i<num_procs; ++i)
  {
    if (io_order == i)
    {
      errno = 0;
      FILE* f = fopen(fname, "r");
      if (errno)
	die("Cannot open file %s:\n%s", fname, strerror(errno));
      fseek(f, i*sz*volume*sizeof(double), SEEK_SET);
      fread(tmp, sizeof(double), sz*volume, f);
      if (errno)
	die("Cannot read file %s\n%s", fname, strerror(errno));
      fclose(f);   
      if (errno)
	die("Cannot close file %s", fname);
    }
    MPI_Barrier(MPI_COMM_WORLD);
  }
  for (int x=0; x<volume; ++x)
  {
    int y = r ? reorder(x, 1) : x;
    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, 1);
}

void read_gc(char* fname, double* U)
{
  read_whatever(fname, U, 72, 0);
  double* U_tmp = new_gc_dbl();
  double_conf(U, U_tmp);
  const unsigned d = 8 * sizeof(uint16_t) / sizeof(double);
  for (unsigned x=0; x<volume; ++x)
  {
    int y = reorder(x, 1);
    for (int i=0; i<144+d; ++i)
      U[(144 + d) * y + i] = U_tmp[(144 + d) * x + i];
  }
  free(U_tmp);
}

static void write_whatever(char* fname, double* v, int sz)
{
  errno=0;
  double* tmp=(double*) malloc(sz*volume*sizeof(double));
  for (int x=0; x<volume; x++)
  {
    int y = reorder(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]));
  for (int i=0; i<num_procs; i++)
  {
    if (io_order==i)
    {
      FILE* f=fopen(fname, i==0? "w" : "a");
      if (errno)
	die("Cannot open file %s", fname);
      size_t n_written=fwrite(tmp, sizeof(double), sz*volume, f);
      if (errno || (n_written!=sz*volume))
	die("Cannot write file %s", fname);
      fclose(f);
      if (errno)
	die("Cannot close file %s", fname);
    }
    MPI_Barrier(MPI_COMM_WORLD);
  }
  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);
}
