
#include <stdio.h>
#include <string.h>
#include "mmio.h"
#include "hbio.h"
#include "lusolio.h"
#include <R.h>

/* Utility routines to read matrix files in the Coordinate Text File format*/

MYBOOL ctf_read_A(char *filename, int maxm, int maxn, int maxnz,
                  int *m, int *n, int *nnzero, int *iA, int *jA, REAL *Aij)
{
  FILE *iofile;
  int  eof;
  char buffer[100];
  int  k, i, j;
  REAL Ak;
  MYBOOL filldata;

  *nnzero = 0;
  *m      = 0;
  *n      = 0;

  iofile = fopen(filename, "r" );
  if(iofile == NULL) {
    Rprintf("A file %s does not exist\n", filename);
    return( FALSE );
  }

  filldata = (MYBOOL) !((iA == NULL) && (jA == NULL) && (Aij == NULL));
  eof = TRUE;
  for (k = 1; k <= maxnz; k++) {
    eof = feof(iofile);
    if(eof)
      break;
    eof = fscanf(iofile, "%d %d %s", &i, &j, buffer);
    if(eof == 0 || eof == EOF || i <= 0 || j <= 0 || strlen(buffer) == 0)
      break;
    Ak = atof(buffer);
    (*nnzero)++;
    if (filldata) {
      iA[k]  = i;
      jA[k]  = j;
      Aij[k] = Ak;
    }
    if (i > *m) *m = i;
    if (j > *n) *n = j;
  }
  fclose( iofile );
  if(!eof) {
    Rprintf("Too much data in A file.  Increase maxnz\n");
    Rprintf("Current maxnz = %d\n", maxnz);
    return( FALSE );
  }
  Rprintf("A  read successfully\n");
  Rprintf("m      = %d   n      = %d   nnzero = %d\n",
          *m, *n, *nnzero);
  if (*m > maxm  ||  *n > maxn) {
    Rprintf("However, matrix dimensions exceed maxm or maxn\n");
    return( FALSE );
  }
  return( TRUE );
}

MYBOOL ctf_size_A(char *filename, int *m, int *n, int *nnzero)
{
  int maxint = 200000000;

  return( ctf_read_A(filename, maxint, maxint, maxint,
                     m, n, nnzero, NULL, NULL, NULL) );
}

MYBOOL ctf_read_b(char *filename, int m, REAL *b)
{
  FILE *iofile;
  int  eof;
  char buffer[100];
  int  i;

  iofile = fopen(filename, "r");
  if(iofile == NULL) {
    Rprintf("b file %s does not exist\n", filename);
    return( FALSE );
  }

  for (i = 1; i <= m; i++) {
    if(feof(iofile))
      goto x350;
    eof = fscanf(iofile, "%s", buffer);
    if(eof == 0 || eof == EOF)
      goto x350;
    b[i] = atof(buffer);
  }

  fclose( iofile );
  Rprintf("b  read successfully\n");
  return( TRUE );

x350:
  fclose( iofile );
  Rprintf("Not enough data in b file.\n");
  return( FALSE );
}


/* Utility routines to read matrix files in the MatrixMarket format*/
#define mmf_recsize 255
MYBOOL mmf_read_A(char *filename, int maxM, int maxN, int maxnz,
                  int *M, int *N, int *nz, int *iA, int *jA, REAL *Aij)
{
  MM_typecode matcode;
  FILE   *f;
  int    i, k, ret_code, ival, jval;
  REAL   Aval;
  MYBOOL status = FALSE, ispat, filldata;
  char   buf[mmf_recsize];

  f = fopen(filename, "r");
  if(f == NULL) 
    return( status );

  if(mm_read_banner(f, &matcode) != 0) {
    Rprintf("Could not process Matrix Market banner.\n");
    goto x900;
  }

  /*  Screen matrix types since LUSOL only supports a 
      subset of the Matrix Market data types. */
  if(mm_is_complex(matcode) || mm_is_pattern(matcode)) {
    Rprintf("Sorry, this application does not support ");
    Rprintf("Market Market type: [%s]\n", mm_typecode_to_str(matcode));
    goto x900;
  }

  /* Verify that we have sufficient array storage */
  filldata = (MYBOOL) !((iA == NULL) && (jA == NULL) && (Aij == NULL));
  if(filldata && maxN > 1 && jA == NULL) {
    Rprintf("Market Market insufficient array storage specified\n");
    goto x900;
  }

  /* Find out size of sparse matrix .... */
  ret_code = mm_read_mtx_crd_size(f, M, N, nz);
  if(ret_code != 0 || !filldata || (*M > maxM) || (*N > maxN) || (*nz > maxnz)) {
    status = !filldata;
    goto x900;
  }


  /* NOTE: when reading in doubles, ANSI C requires the use of the "l"  */
  /* specifier as in "%lg", "%lf", "%le", otherwise errors will occur   */
  /*  (ANSI C X3.159-1989, Sec. 4.9.6.2, p. 136 lines 13-15)            */

  /* Read dense matrix in column order */
  ispat = (MYBOOL) mm_is_pattern(matcode);
  k = 1;
  if(mm_is_dense(matcode)) {
    maxN = MIN(maxN, *N);
    for (jval = 1; jval <= maxN; jval++) {
      for (i = 1; i <= *M; i++) {
        if(fgets(buf, mmf_recsize-1, f) == NULL)
          break;
        if(sscanf(buf, "%lg\n", &Aval) == 0)
          break;
        if(Aval != 0) {
          if(iA != NULL)
            iA[k] = i;
          if(jA != NULL)
            jA[k] = jval;

          /* Make sure we handle dense vector reading properly */
          if(iA == NULL && jA == NULL)
            Aij[i] = Aval;
          else
            Aij[k] = Aval;
          k++;
        }
      }
    }
  }
  /* Read sparse matrix by coordinate */
  else {
    for (i = 1; i <= *nz; i++) {
      if(fgets(buf, mmf_recsize-1, f) == NULL)
        break;
      if(buf[0] == '%')
        continue;
      if(ispat) {
        if(sscanf(buf, "%d %d\n", &ival, &jval) == 0)
          continue;
        Aij[k] = 1.0;
      }
      else
        if(sscanf(buf, "%d %d %lg\n", &ival, &jval, &Aval) == 0)
          continue;

      /* Check if it is a nonzero and we are within column dimension */
      if(Aval != 0 && jval <= maxN) {
        Aij[k] = Aval;
        if(iA != NULL)
          iA[k] = ival;
        if(jA != NULL)
          jA[k] = jval;
        k++;
      }
    }
  }
  *nz = k - 1;

  /* Handle case where only the lower triangular parts are given */
  if(!mm_is_general(matcode)) {
    if((M != N) || (maxN != maxM) || (2*(*nz) > maxnz)) {
      Rprintf("Market Market cannot fill in symmetry data\n");
      goto x900;
    }
    ispat = mm_is_skew(matcode);
    for(i = 1; i <= *nz; i++) {
      iA[k] = jA[i];
      jA[k] = iA[i];
      if(ispat)
        Aij[k] = -Aij[i];
      else
        Aij[k] = Aij[i];
      k++;
    }
    *nz = k - 1;
  }
  status = TRUE;

  /* Finish up */
x900:
  fclose( f );
  return( status );
}

MYBOOL mmf_size_A(char *filename, int *M, int *N, int *nz)
{
  int maxint = 200000000;

  return( mmf_read_A(filename, maxint, maxint, maxint,
                     M, N, nz, NULL, NULL, NULL) );
}

MYBOOL mmf_read_b(char *filename, int m, REAL *b)
{
  int im, jn, nnzero;

  return( mmf_read_A(filename, m, 1, m,
                     &im, &jn, &nnzero, NULL, NULL, b));
}


/* Utility routines to read matrix files in Harwell-Boeing format*/

MYBOOL hbf_read_A(char *filename, int maxM, int maxN, int maxnz,
                  int *M, int *N, int *nz, int *iA, int *jA, REAL *Aij)
{
  MYBOOL success;

  success = hbf_size_A(filename, M, N, nz);
  if(!success)
    return( success );

  Aij[1] = 0;
  success = (MYBOOL) readHB_mat_double(filename, jA, iA-1, Aij-1);

  /* Test if we have a pattern matrix and fill it with all zeros */
  if(Aij[1] == 0) {
    int i;
    for(i = 1; i <= *nz; i++)
      Aij[i] = 1;
  }

  /* Expand the column nz counts to triplet format */
  if(success) {
    int i, j, ii, k;
    k = *nz;
    for(j = *N; j > 0; j--) {
      ii = jA[j];
      for(i = jA[j-1]; i < ii; i++, k--)
        jA[k] = j;
    }
  }
  return( success );
}

MYBOOL hbf_size_A(char *filename, int *M, int *N, int *nz)
{
  int  Nrhs;
  char *Type;

  return( (MYBOOL) readHB_info(filename, M, N, nz, &Type, &Nrhs) );
}

MYBOOL hbf_read_b(char *filename, int m, REAL *b)
{
  return( (MYBOOL) readHB_aux_double(filename, 'F', b) ); /* Same format as matrix */
}
