#include <stdio.h>
#include "cdf.h"
#include "cdffits.h"
/* #include "cdfdist.h" */
#include "fitsio.h"

#define ROWMAJOR(rowMajor,val1,val2) ((rowMajor == ROW_MAJOR)? val1 : val2) 
void PrintData(void *, long, long, char *);

/****************************************************************************
 * Dump data from input buffer, based on its record number, row/column 
 * majority, dimensionality and data type. The dimensional size is limited 
 * to 5-D, for now.
 ****************************************************************************/
void DumpData(long recNum, long majority, long numDims, long *dimSizes, 
              long dataType, long numElems, void *buffer) {

   int j0, j1, j2, j3, j4, j5, phyValues; 
   long numBytes;
   size_t offset;

   numBytes = CDFelemSize(dataType);
   if (numDims == 0) {
     for (j0 = 0; j0 < recNum; j0++ ) {
       printf ("{");
       PrintData((char *)buffer+(j0 * numBytes * numElems), 
                 dataType, numElems, NULL);
       printf ("}\n");
     }
   } else if (numDims == 1) {
     phyValues = dimSizes[0];
     for (j0 = 0; j0 < recNum; j0++ ) {
       printf ("{[");
       for (j1 = 0; j1 < dimSizes[0]; j1++ ) {
         offset = (phyValues * j0 + j1) * numBytes * numElems;
         PrintData((char *)buffer+offset, dataType, numElems, NULL);
         if (j1 != (dimSizes[0] - 1)) printf(",");
       }
       printf ("]}\n");
     }
   } else if (numDims == 2) {
     phyValues = dimSizes[0] * dimSizes[1];
     for (j0 = 0; j0 < recNum; j0++ ) {
       printf ("{");
         for (j1 = 0; j1 < ROWMAJOR(majority,dimSizes[0],dimSizes[1]); j1++ ) {
	 if (j1 == 0) printf("[");
	 else         printf(" [");
         for (j2 = 0; j2 < ROWMAJOR(majority,dimSizes[1],dimSizes[0]); j2++ ) {
            offset = (phyValues * j0 + 
                      j1 * ROWMAJOR(majority,dimSizes[1],dimSizes[0]) + 
                      j2) * numBytes * numElems;
            PrintData((char *)buffer+offset, dataType, numElems, NULL);
            if (j2 != (ROWMAJOR(majority,dimSizes[1],dimSizes[0]) - 1)) 
              printf(",");
         }
         printf("]");
	 if (j1 != (ROWMAJOR(majority,dimSizes[0],dimSizes[1]) - 1)) 
           printf("\n");
       }
       printf ("}\n");
     }
   } else if (numDims == 3) {
     phyValues = dimSizes[0] * dimSizes[1] * dimSizes[2];
     for (j0 = 0; j0 < recNum; j0++ ) {
       printf ("{");
       for (j1 = 0; j1 < ROWMAJOR(majority,dimSizes[0],dimSizes[2]); j1++ ) {
         if (j1 == 0) printf("[");
         else         printf(" [");
         for (j2 = 0; j2 < dimSizes[1]; j2++ ) {
	   if (j2 == 0) printf("[");
	   else         printf("  [");
           for (j3 = 0; j3 < ROWMAJOR(majority,dimSizes[2],dimSizes[0]); j3++ ) {
             offset = (phyValues * j0 + 
                       j1 * ROWMAJOR(majority,dimSizes[1],dimSizes[1]) * 
                            ROWMAJOR(majority,dimSizes[2],dimSizes[0]) + 
                       j2 * ROWMAJOR(majority,dimSizes[2],dimSizes[0]) + 
                       j3) * numBytes * numElems;
             PrintData((char *)buffer+offset, dataType, numElems, NULL);
             if (j3 != (ROWMAJOR(majority,dimSizes[2],dimSizes[0]) - 1)) 
               printf(",");
           }
	   printf("]");
	   if (j2 != (ROWMAJOR(majority,dimSizes[1],dimSizes[1]) - 1)) 
             printf("\n");
         }
         printf("]");
         if (j1 != (ROWMAJOR(majority,dimSizes[0],dimSizes[2]) - 1)) 
           printf("\n");
       }
       printf ("}\n");
     }
   } else if (numDims == 4) {
     phyValues = dimSizes[0] * dimSizes[1] * dimSizes[2] * dimSizes[3];
     for (j0 = 0; j0 < recNum; j0++ ) {
       printf ("{");
       for (j1 = 0; j1 < ROWMAJOR(majority,dimSizes[0],dimSizes[3]); j1++ ) {
         if (j1 == 0) printf("[");
         else         printf(" [");
         for (j2 = 0; j2 < ROWMAJOR(majority,dimSizes[1],dimSizes[2]); j2++ ) {
	   if (j2 == 0) printf("[");
	   else         printf("  [");
           for (j3 = 0; j3 < ROWMAJOR(majority,dimSizes[2],dimSizes[1]); j3++ ) {
	     if (j3 == 0) printf("[");
	     else         printf("   [");
	     for (j4 = 0; j4 < ROWMAJOR(majority,dimSizes[3],dimSizes[0]); j4++ ) {
               offset = (phyValues * j0 + 
                         j1 * ROWMAJOR(majority,dimSizes[1],dimSizes[2]) * 
                              ROWMAJOR(majority,dimSizes[2],dimSizes[1]) * 
                              ROWMAJOR(majority,dimSizes[3],dimSizes[0]) + 
                         j2 * ROWMAJOR(majority,dimSizes[2],dimSizes[1]) * 
                              ROWMAJOR(majority,dimSizes[3],dimSizes[0]) +
                         j3 * ROWMAJOR(majority,dimSizes[3],dimSizes[0]) +
                         j4) * numBytes * numElems;
               PrintData((char *)buffer+offset, dataType, numElems, NULL);
               if (j4 != (ROWMAJOR(majority,dimSizes[3],dimSizes[0]) - 1)) 
                 printf(",");
	     }
	     printf("]");
	     if (j3 != (ROWMAJOR(majority,dimSizes[2],dimSizes[1]) - 1)) 
               printf("\n");
           }
           printf("]");
           if (j2 != (ROWMAJOR(majority,dimSizes[1],dimSizes[2]) - 1)) 
             printf("\n");
         }
         printf("]");
         if (j1 != (ROWMAJOR(majority,dimSizes[0],dimSizes[3]) - 1)) 
           printf("\n");
       }
       printf ("}\n");
     }
   } else if (numDims == 5) {
     phyValues = dimSizes[0] * dimSizes[1] * dimSizes[2] * dimSizes[3] *
                 dimSizes[4];
     for (j0 = 0; j0 < recNum; j0++ ) {
       printf ("{");
       for (j1 = 0; j1 < ROWMAJOR(majority,dimSizes[0],dimSizes[4]); j1++ ) {
         if (j1 == 0) printf("[");
         else         printf(" [");
         for (j2 = 0; j2 < ROWMAJOR(majority,dimSizes[1],dimSizes[3]); j2++ ) {
           if (j2 == 0) printf("[");
           else         printf("  [");
           for (j3 = 0; j3 < ROWMAJOR(majority,dimSizes[2],dimSizes[2]); j3++ ) {
             if (j3 == 0) printf("[");
             else         printf("   [");
             for (j4 = 0; j4 < ROWMAJOR(majority,dimSizes[3],dimSizes[1]); j4++ ) {
               if (j4 == 0) printf("[");
               else         printf("    [");
               for (j5 = 0; j5 < ROWMAJOR(majority,dimSizes[4],dimSizes[0]); j5++ ) {
                 offset = (phyValues * j0 +
                           j1 * ROWMAJOR(majority,dimSizes[1],dimSizes[3]) * 
                                ROWMAJOR(majority,dimSizes[2],dimSizes[2]) * 
                                ROWMAJOR(majority,dimSizes[3],dimSizes[1]) * 
                                ROWMAJOR(majority,dimSizes[4],dimSizes[0]) +
                           j2 * ROWMAJOR(majority,dimSizes[2],dimSizes[2]) * 
                                ROWMAJOR(majority,dimSizes[3],dimSizes[1]) * 
                                ROWMAJOR(majority,dimSizes[4],dimSizes[0]) +
                           j3 * ROWMAJOR(majority,dimSizes[3],dimSizes[1]) * 
                                ROWMAJOR(majority,dimSizes[4],dimSizes[0]) +
			   j4 * ROWMAJOR(majority,dimSizes[4],dimSizes[0]) +
                           j5) * numBytes * numElems;
                 PrintData((char *)buffer+offset, dataType, numElems, NULL);
		 if (j5 != (ROWMAJOR(majority,dimSizes[4],dimSizes[0]) - 1)) 
                   printf(",");
	       }
	       printf("]");
               if (j4 != (ROWMAJOR(majority,dimSizes[3],dimSizes[1]) - 1)) 
                 printf("\n");
             }
             printf("]");
             if (j3 != (ROWMAJOR(majority,dimSizes[2],dimSizes[2]) - 1)) 
               printf("\n");
           }
           printf("]");
           if (j2 != (ROWMAJOR(majority,dimSizes[1],dimSizes[3]) - 1)) 
             printf("\n");
         }
         printf("]");
         if (j1 != (ROWMAJOR(majority,dimSizes[0],dimSizes[4]) - 1)) 
           printf("\n");
       }
       printf ("}\n");
     }
   }
}

/****************************************************************************
 * Print one data value, based on its data type.
 ****************************************************************************/
void PrintData(void *binary, long dataType, long numElems, char *outString) {

  int ii;
  size_t len;
  char *tmp, *ePtr, tText[80+1];

  switch (dataType) {
    case CDF_BYTE:
    case CDF_INT1:
      for (ii = 0; ii < numElems; ii++) {
        if (outString == NULL) {
	  printf ("%d", (int) *((sChar *) binary+ii));
	  if (numElems > 1 && ii != (numElems - 1)) printf(",");
	} else {
	  if (ii == 0) 
            sprintf (outString, "%d", (int) *((sChar *) binary+ii));
	  else
            sprintf (EofS(outString), "%d", (int) *((sChar *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) sprintf(EofS(outString), 
                                                            ",");
	}
      }
      break;
    case CDF_INT2:
      for (ii = 0; ii < numElems; ii++) {
        if (outString == NULL) {
          printf ("%d", (int) *((Int16 *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) printf(",");
        } else {
	  if (ii == 0)
            sprintf (outString, "%d", (int) *((Int16 *) binary+ii));
	  else
            sprintf (EofS(outString), "%d", (int) *((Int16 *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) sprintf(EofS(outString), 
                                                            ",");
	}
      }
      break;
    case CDF_INT4:
      for (ii = 0; ii < numElems; ii++) {
        if (outString == NULL) {
          printf (Int32FORMAT, *((Int32 *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) printf(",");
        } else {
	  if (ii == 0)
            sprintf (outString, Int32FORMAT, *((Int32 *) binary+ii));
	  else
            sprintf (EofS(outString), Int32FORMAT, *((Int32 *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) sprintf(EofS(outString), 
                                                            ",");
	}
      }
      break;
    case CDF_UINT1:
      for (ii = 0; ii < numElems; ii++) {
        if (outString == NULL) {
          printf ("%u", (uInt) *((uChar *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) printf(",");
        } else {
	  if (ii == 0)
            sprintf (outString, "%u", (uInt) *((uChar *) binary+ii));
	  else
            sprintf (EofS(outString), "%u", (uInt) *((uChar *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) sprintf(EofS(outString), 
                                                            ",");
	}
      }
      break;
    case CDF_UINT2:
      for (ii = 0; ii < numElems; ii++) {
        if (outString == NULL) {
          printf ("%u", (uInt) *((uInt16 *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) printf(",");
        } else {
	  if (ii == 0)
            sprintf (outString, "%u", (uInt) *((uInt16 *) binary+ii));
	  else
            sprintf (EofS(outString), "%u", (uInt) *((uInt16 *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) sprintf(EofS(outString), 
                                                            ",");
	}
      }
      break;
    case CDF_UINT4:
      for (ii = 0; ii < numElems; ii++) {
        if (outString == NULL) {
          printf (Int32uFORMAT, *((uInt32 *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) printf(",");
        } else {
	  if (ii == 0)
            sprintf (outString, Int32uFORMAT, *((uInt32 *) binary+ii));
	  else
            sprintf (EofS(outString), Int32uFORMAT, *((uInt32 *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) printf(EofS(outString), 
                                                           ",");
	}
      }
      break;
    case CDF_REAL4:
    case CDF_FLOAT: 
      for (ii = 0; ii < numElems; ii++) {
        if (outString == NULL) {
          printf ("%g", *((float *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) printf(",");
        } else {
	  if (ii == 0)
            sprintf (outString, "%g", *((float *) binary+ii));
	  else
            sprintf (EofS(outString), "%g", *((float *) binary+ii));
          if ((ePtr = (char *) strchr(outString,'e')) == NULL) {  /* eg., 0 */
            if ((char *) strchr(outString,'.') == NULL) 
              strcatX (outString,".0", 0);
          }
          else {
            if ((char *) strchr(outString,'.') == NULL) {  /* eg., 1e+07 */
              len = (size_t) (ePtr - outString);
              strcpyX (tText, outString, MINIMUM(len,80));
              strcatX (tText, ".0", 0);
              strcatX (tText, ePtr, 0);
              strcpyX (outString, tText, 0);
            }
          }
          if (numElems > 1 && ii != (numElems - 1)) sprintf(EofS(outString), 
                                                            ",");
	}
      }
      break;
    case CDF_REAL8:
    case CDF_DOUBLE: 
      for (ii = 0; ii < numElems; ii++) {
        if (outString == NULL) {
          printf ("%g", *((double *) binary+ii));
          if (numElems > 1 && ii != (numElems - 1)) printf(",");
        } else {
	  if (ii == 0)
            sprintf(outString, "%g",*((double *) binary+ii));
	  else
	    sprintf(EofS(outString), "%g",*((double *) binary+ii));
          if ((ePtr = (char *) strchr(outString,'e')) == NULL) {  /* eg., 0 */
            if ((char *) strchr(outString,'.') == NULL) 
              strcatX (outString,".0", 0);
          }
          else {
            if ((char *) strchr(outString,'.') == NULL) {  /* eg., 1e+07 */
              len = (size_t) (ePtr - outString);
              strcpyX (tText, outString, MINIMUM(len,80));
              strcatX (tText, ".0", 0);
              strcatX (tText, ePtr, 0);
              strcpyX (outString, tText, 0);
            }
          }
          if (numElems > 1 && ii != (numElems - 1)) sprintf(EofS(outString), 
                                                            ",");
	}
      }
      break;
    case CDF_CHAR:
      tmp = (char *) malloc(numElems + 1); 
      memcpy(tmp, (char *) binary, numElems);
      tmp[numElems] = (char) 0;
      if (outString == NULL) 
        printf ("%s", tmp);
      else 
        sprintf (outString, "%s", tmp);
      break;
    case CDF_UCHAR:
      tmp = (char *) malloc(numElems + 1);
      memcpy(tmp, (uChar *) binary, numElems);
      tmp[numElems] = (char) 0;
      if (outString == NULL)
        printf ("%s", tmp);
      else 
        sprintf (outString, "%s", tmp);
/*      printf ("%s", (uChar *) binary); */
      break;
    case CDF_EPOCH:
      tmp = (char *) malloc(EPOCH3_STRING_LEN + 1);
      for (ii = 0; ii < numElems; ii++) {
        encodeEPOCH3(*((double *)binary+ii), tmp);
        if (outString == NULL) {
          printf("%s",tmp);
          if (numElems > 1 && ii != (numElems - 1)) printf(",");
        } else {
	  if (ii == 0)
            sprintf(outString, "%s",tmp);
	  else
	    sprintf(EofS(outString), "%s",tmp);
          if (numElems > 1 && ii != (numElems - 1)) sprintf(EofS(outString), 
                                                            ",");
	}
      }
      break;
  }

}

/******************************************************************************
* DumpAttributeEntry.
******************************************************************************/

void DumpAttributeEntry(long dataType, long numElems, void *entry) {

  char *tmp;
  if (dataType == CDF_CHAR || dataType == CDF_UCHAR) 
    tmp = malloc((size_t)numElems+1);
  else 
    tmp = malloc((size_t) 25*numElems);
  printf("dataType=%s numElems=%ld ", DataTypeToken(dataType), numElems);
  if (dataType == CDF_CHAR || dataType == CDF_UCHAR) {
    memcpy(tmp, (char *) entry, (size_t)numElems);
    tmp[numElems] = (char ) 0;
    printf("data=%s\n", tmp);
  } else {
    PrintData(entry, dataType, numElems, tmp);
    printf("data= %s\n",tmp);
  }

}

/******************************************************************************
* DumpFITSCard.
******************************************************************************/

void DumpFITSCard(char *keyword, char *keywordValue, char *comment, int keyNum,
                  int keyDataType, void *value, char *floatFormat) {

  int xx;
  printf("   ** Keyword=%s ",keyword);
  if (strlen(keywordValue) > 0)
    printf("KeywordValue=%s ",keywordValue);
  if (strlen(comment) > 0) printf("COMMENT=%s\n",comment);
  else printf("\n");

  for (xx = 0; xx < keyNum; xx++) {
    if (keyDataType == TINT32BIT)
      printf("   ** KeywordValue (FITS) datatype=%d value=%d\n",
             keyDataType, *(int *) value+xx);
    else if (keyDataType == TLONG)
      printf("   ** KeywordValue (FITS) datatype=%d value=%ld\n",
             keyDataType, *(long *) value+xx);
    else if (keyDataType == TLOGICAL)
      printf("   ** KeywordValue (FITS) datatype=%d value=%d\n",
             keyDataType, *(int *) value+xx);
    else if (keyDataType == TFLOAT) {
      printf("   ** KeywordValue (FITS) datatype=%d value=",
             keyDataType);
      printf(floatFormat, *(((float *) value)+xx)); printf("\n");
    } else if (keyDataType == TSTRING) {
      printf("   ** KeywordValue (FITS) datatype=%d value=",
             keyDataType);
      printf("%s\n", value);
    } else if (keyDataType == TDOUBLE) {
      printf("   ** KeywordValue (FITS) datatype=%d value=",
             keyDataType);
      printf(floatFormat, *(((double *) value)+xx)); printf("\n");
    }
  }
}


