/***************************************************************************/
/* readmatrix - extracts the sparse matrix from a pack file                */
/*                                                                         */
/* David O'Hallaron, February, 1998, Carnegie Mellon University.           */
/*                                                                         */
/* usage: readmatrix packfile > matrix                                     */
/*                                                                         */  
/* The program extracts a matrix from an Archimedes packfile and saves     */
/* to stdout as a series of (i,j) pairs, one pair per line.                */
/*                                                                         */
/* Distributed as part of the Spark98 Kernels                              */
/* Copyright (c) David O'Hallaron 1998                                     */
/*                                                                         */
/* You are free to use this software without restriction. If you find that */
/* the Spark kernels are helpful to you, it would be very helpful if you   */
/* sent me at droh@cs.cmu.edu letting me know how you are using them.      */
/***************************************************************************/ 

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

/* 
 * program wide constants 
 */
#define STRLEN 128        /* default string length */
#define DOF 3             /* degrees of freedom in underlying simulation */

/*
 * global variables
 */
struct gi { 
  /* misc */
  char progname[STRLEN];     /* program name */
  FILE *packfp;              /* file descriptor for packfile */

  /* command line options */
  int quiet;
  char packfilename[STRLEN];/* packfile name */

  /* packfile problem parameters */
  int globalnodes;          /* number of global nodes */
  int globalelems;          /* number of global elements */
  int mesh_dim;             /* mesh dimension */
  int corners;              /* nodes per element */
  int subdomains;           /* number of partition sets */ 
  int processors;           /* not used */

} gi, *gip=&gi;


/* end globals */

/* 
 * function prototypes 
 */
/* initialization and exit routines */
void parsecommandline(int argc, char **argv, struct gi *gip);
void bail(struct gi *gip);
void finalize(struct gi *gip);

/* routines that read and parse the packfile */
void validate(struct gi *gip);
void readpackfile(struct gi *gip); 

/* misc routines */
void info(struct gi *gip);
void usage(struct gi *gip);


/*
 * main program 
 */
void main(int argc, char **argv) {
  
  parsecommandline(argc, argv, gip);

  /* check the packfile */
  if (!(gip->packfp = fopen(gip->packfilename, "r"))) {
    fprintf(stderr, "%s: Can't open %s\n", gip->progname, gip->packfilename);
    bail(gip);
  }
  validate(gip);
  
  /* extract the matrix from the packfile */
  if (!gip->quiet) 
    fprintf(stderr, "%s: Reading %s.\n", argv[0], gip->packfilename);
  readpackfile(gip);

  fclose(gip->packfp);
  finalize(gip);
}

void parsecommandline(int argc, char **argv, struct gi *gip) {
  int i,j;
  char *sp;    

  /* no need to see the entire executable path name, the base will do. */
  for (sp = argv[0]+strlen(argv[0]); (sp != argv[0]) && *sp != '/'; sp--)
    ;
  if (*sp == '/')
    strcpy(gip->progname, sp+1);
  else    
    strcpy(gip->progname, sp);
  

  /* must have an input packfile as an argument */
  if ((argc < 2) || (argc > 3)) {
    usage(gip);
    exit(0);
  }

  /* first set up the defaults */
  gip->quiet = 0;

  /* now see if the user wants to change any of these */
  for (i=1; i<argc; i++) {
    if (argv[i][0] == '-') {
      for (j = 1; argv[i][j] != '\0'; j++) {
	if (argv[i][j] == 'Q') {
	  gip->quiet = 1;
	}
	else if (argv[i][j] == 'h') {
	  usage(gip);
	  exit(0);
	}
	else {
	  usage(gip);
	  exit(0);
	}
      }
    }
    else {
      strcpy(gip->packfilename, &argv[i][0]);
    }
  }
}

/*
 * validate - make sure the packfile is OK
 */
void validate(struct gi *gip) {

  fscanf(gip->packfp, "%d %d\n", &gip->globalnodes, &gip->mesh_dim);
  fscanf(gip->packfp, "%d %d\n", &gip->globalelems, &gip->corners);
  fscanf(gip->packfp, "%d %d\n", &gip->subdomains, &gip->processors);

  /* first, make sure that it is indeed a packfile */
  if ((gip->subdomains < 1) || (gip->subdomains > 1024) ||
      ((gip->mesh_dim != 2) && (gip->mesh_dim != 3)) ||
      ((gip->corners != 3) && (gip->corners != 4)) ||
      gip->processors != gip->subdomains) {
    fprintf(stderr, "%s: the input file %s doesn't appear to be a packfile\n",
	    gip->progname, gip->packfilename);
    bail(gip);
  }

  /* the ackfile should have exactly 1 subdomain */
  if (gip->subdomains != 1) {
    fprintf(stderr, "%s: the packfile must have exactly 1 subdomain\n", 
	    gip->progname);
    bail(gip);
  }
}

/*
 * readpackfile - extract the sparse matrix from a packfile 
 */
void readpackfile(struct gi *gip) {
  int row, col;
  int i, j;
  int matrixlen;


  /* read nodes */
  if (!gip->quiet) {
    fprintf(stderr, "%s: Reading nodes.", gip->progname);
  }
  fscanf(gip->packfp, "%*d %*d %*d");
  for (i=0; i<gip->globalnodes; i++) {
    fscanf(gip->packfp, "%*d");
    for (j=0; j<gip->mesh_dim; j++) {
      fscanf(gip->packfp, "%*lf");
    }
  }
  if (!gip->quiet) {
    fprintf(stderr, " Done.\n");
    fflush(stderr);
  }

  /* read elements */
  if (!gip->quiet)
    fprintf(stderr, "%s: Reading elements.", gip->progname);
  fscanf(gip->packfp, "%*d");
  for (i=0; i<gip->globalelems; i++) {
    fscanf(gip->packfp, "%*d");	
    for (j=0; j<gip->corners; j++) {
      fscanf(gip->packfp, "%*d");
    }
  }
  if (!gip->quiet) {
    fprintf(stderr, " Done.\n");
    fflush(stderr);
  }

  /* read and write sparse matrix structure */
  if (!gip->quiet)
    fprintf(stderr, "%s: Reading and writing sparse matrix structure.", 
	    gip->progname);
  fscanf(gip->packfp, "%d %*d", &matrixlen);
  for (i = 0; i < matrixlen; i++) {
    fscanf(gip->packfp, "%d %d", &row, &col);
    printf("%d %d\n", row, col);
  }
  if (!gip->quiet) {
    fprintf(stderr, " Done.\n");
    fflush(stderr);
  }
}


void usage(struct gi *gip) {
  fprintf(stderr, "\n");
  fprintf(stderr, "Usage: %s [-Q] <packfile> > <matrix>\n", gip->progname);
  fprintf(stderr, "\n");
  fprintf(stderr, "Command line arguments:\n");
  fprintf(stderr, "  -Q           run quietly\n");
  fprintf(stderr, "  <packfile>   input packfile\n");
  fprintf(stderr, "  <matrix>     output sparse matrix\n");
  exit(0);
}


/* orderly exit */
void finalize(struct gi *gip) {
  if (!gip->quiet) {
    fprintf(stderr, "%s: Terminating normally.\n", gip->progname);
    fflush(stderr);
  }

  exit(0);
}

/* emergency exit */
void bail(struct gi *gip) {
  exit(0);
}



