/****************************************************************************
**  SIONLIB     http://www.fz-juelich.de/jsc/sionlib                       **
*****************************************************************************
**  Copyright (c) 2008-2009                                                **
**  Forschungszentrum Juelich, Juelich Supercomputing Centre               **
**                                                                         **
**  See the file COPYRIGHT in the package base directory for details       **
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "sion.h"
#include "sion_fd.h"

#define FILENAME_LENGTH 1024

void usage(char *name)
{
  fprintf(stderr, "Usage: %s options <sionfn> \n\nwith the following optional options (default values in parathesis):\n\n", name);

  fprintf(stderr, "  [-a]                   print all information about all blocks \n");
  fprintf(stderr, "  [-m]                   print all mapping information \n");
  fprintf(stderr, "  [-v]                   verbose mode \n");
  exit(1);
}


int main(int argc, char **argv)
{
  FILE     *fp;
  char      infilename[FILENAME_LENGTH], fname[FILENAME_LENGTH];
  int       i, rank, blknum;

  /* options */
  int       printall = 0;
  int       printmap = 0;
  int       verbose = 0;

  /* for file infomation */
  int       sid, size, blocks, gblknum, ntasks;
  sion_int32 fsblksize;
  sion_int64 globalskip;
  sion_int64 start_of_varheader;
  sion_int64 *sion_localsizes;
  sion_int64 *sion_globalranks;
  sion_int64 *sion_blockcount;
  sion_int64 *sion_blocksizes;
  sion_int64 *sion_currentpos;
  sion_int64 *sion_currentblocknr;
  sion_int64 *siondump_sum_bytes_per_task;
  sion_int64 siondump_sum_bytes;
  sion_int64 siondump_filesize;
  _sion_filedesc *sion_filedesc;
  int         mapping_size, nfiles;
  sion_int32 *mapping;

  /* parse command line */
  i = 1;
  if (argc < 2)
    usage(argv[0]);

  while (i < argc) {
    if (argv[i][0] == '-') {
      switch (argv[i][1]) {
      case 'a':
        printall = 1;
        break;
      case 'm':
        printmap = 1;
        break;
      case 'v':
        verbose++;
        break;
      case 'h':
        usage(argv[0]);
        break;
      default:
        usage(argv[0]);
      }
    }
    i++;
  }

  strcpy(infilename, argv[argc - 1]);

  sid = sion_open(infilename, "rb", &ntasks, &nfiles, NULL, &fsblksize, NULL, &fp);

  // get the sion file structure
  if ((_sion_vcdtype(sid) != SION_FILEDESCRIPTOR) || !(sion_filedesc = _sion_vcdtovcon(sid))) {
    return(_sion_errorprint(-1,_SION_ERROR_RETURN,"invalid sion_filedesc, aborting %d ...\n", sid));

  }

  printf("siondump: sid:                       %d\n", sid);
  //  printf("siondump: filename:                  %-30s\n",infilename);
  printf("siondump: filename:                  %-30s\n", sion_filedesc->fname);
  printf("siondump: prefix:                    %-30s\n", sion_filedesc->prefix);
  printf("siondump: number of tasks:           %d\n", ntasks);
  printf("siondump: current endianness:        %s\n", (sion_get_endianness())? "big" : "little");
  printf("siondump: file endianness:           %s\n", (sion_get_file_endianness(sid)) ? "big" : "little");
  printf("siondump: filesystem blocksize:      %lu bytes (%6.2f MB)\n", (unsigned long) fsblksize, fsblksize / 1024.0 / 1024.0);
  printf("siondump: file set:                  %s\n", (nfiles > 1) ? "Yes" : "No");
  printf("siondump: file number:               %d\n", sion_filedesc->filenumber);
  printf("siondump: flag1:                     %lld\n", sion_filedesc->flag1);
  printf("siondump: flag2:                     %lld\n", sion_filedesc->flag2);
  printf("siondump: file format version:       %d\n", sion_filedesc->fileversion);

  sion_get_locations(sid, &size, &blocks, &globalskip, &start_of_varheader, &sion_localsizes, &sion_globalranks,
                     &sion_blockcount, &sion_blocksizes);
  printf("siondump: number of blocks:           %d\n", blocks);

  /* analysis */
  siondump_sum_bytes_per_task = (sion_int64 *) malloc(ntasks * sizeof(sion_int64));
  for (rank = 0; rank < size; rank++)
    siondump_sum_bytes_per_task[rank] = 0;
  for (rank = 0; rank < size; rank++) {
    for (blknum = 0; blknum < blocks; blknum++) {
      siondump_sum_bytes_per_task[rank] += sion_blocksizes[size * blknum + rank];
    }
  }
  siondump_sum_bytes = 0;
  for (rank = 0; rank < size; rank++)
    siondump_sum_bytes += siondump_sum_bytes_per_task[rank];

  printf("siondump: datasize in file (aggr.):  %lld bytes  (%6.2f MB)\n", siondump_sum_bytes, siondump_sum_bytes / 1024.0 / 1024.0);

  siondump_filesize = start_of_varheader + (blocks + 1) * rank * sizeof(sion_int64);
  printf("siondump: start_of_varheader:        %lld bytes  (%6.2f MB)\n", start_of_varheader, start_of_varheader / 1024.0 / 1024.0);
  printf("siondump: size of file:              %lld bytes  (%6.2f MB)\n", siondump_filesize, siondump_filesize / 1024.0 / 1024.0);
  if (siondump_filesize > 0) {
    printf("siondump: file usage:                %8.6f%%\n", (double) siondump_sum_bytes / (double) siondump_filesize * 100.0);
  }

  /* detailed print of block sizes */
  if (printall) {

    printf("\n");
    printf
      ("-----------------------------------------------------------------------------------------------------------------------------------------------------------\n");
    for (gblknum = 0; gblknum < blocks; gblknum += 10) {
      printf("%62s", " ");
      for (blknum = gblknum + 0; ((blknum < gblknum + 10) && (blknum < blocks)); blknum++) {
        printf("BLK%03d     ", blknum);
      }
      printf("\n");
      for (rank = 0; rank < size; rank++) {
        printf("Task %02d: size=%6.2f MB glblrnk=%4lld #blks=%2lld lsz=%6.2f MB", rank, siondump_sum_bytes_per_task[rank] / 1024.0 / 1024.0,
               sion_globalranks[rank], sion_blockcount[rank], sion_localsizes[rank] / 1024.0 / 1024.0);
        for (blknum = gblknum + 0; ((blknum < gblknum + 10) && (blknum < blocks)); blknum++) {
          printf("%10ld ", (long) sion_blocksizes[size * blknum + rank]);
        }
        printf("\n");
      }
      printf("\n");
    }
    printf
      ("-----------------------------------------------------------------------------------------------------------------------------------------------------------\n");
  }

  if (sion_filedesc->nfiles > 1) {
    printf("------------------------------------------------------------\n");
    printf("siondump: number of files:           %d\n", sion_filedesc->nfiles);
    for (i = 0; i < sion_filedesc->nfiles; ++i) {
      if(i>0) sprintf(fname, "%s.%06d", sion_filedesc->prefix, i);
      else    sprintf(fname, "%s", sion_filedesc->prefix);
      printf("siondump: file %d:                    %s \n", i + 1, fname);
    }
    printf("------------------------------------------------------------\n");

    if(printmap) {
      sion_get_mapping(sid,&mapping_size,&mapping,&nfiles);
      printf("  mapping: ");
      for (i = 0; i < mapping_size; ++i) {
	printf("[%05d -> (f%03d,t%03d)] ", i, mapping[i*2+0],mapping[i*2+1]);
	if(i%16==15) printf("\n        ");
      }
      printf("\n");
      printf("------------------------------------------------------------\n");
    }
  }

  sion_get_current_locations(sid, &size, &sion_currentpos, &sion_currentblocknr);

  sion_close(sid);

  return (0);
}
