Index: trunk/psLib/src/fileUtils/psFits.c
===================================================================
--- trunk/psLib/src/fileUtils/psFits.c	(revision 2681)
+++ trunk/psLib/src/fileUtils/psFits.c	(revision 2806)
@@ -7,6 +7,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-12-10 02:50:15 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-12-23 19:13:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -22,6 +22,48 @@
 #include "psString.h"
 #include "psLogMsg.h"
+#include "psTrace.h"
 
 #define MAX_STRING_LENGTH 256  // maximum length string for FITS routines
+
+static psElemType convertFitsToPsType(int datatype)
+{
+    switch (datatype) {
+    case TBYTE:
+        return PS_TYPE_U8;
+    case TSBYTE:
+        return PS_TYPE_S8;
+    case TSHORT:
+        return PS_TYPE_S16;
+    case TUSHORT:
+        return PS_TYPE_U16;
+    case TLONG:
+        if (sizeof(long) == 8) {
+            return PS_TYPE_S64;
+        }
+        // no break
+    case TINT:
+        return PS_TYPE_S32;
+    case TULONG:
+        if (sizeof(unsigned long) == 8) {
+            return PS_TYPE_U64;
+        }
+        // no break
+    case TUINT:
+        return PS_TYPE_U32;
+    case TLONGLONG:
+        return PS_TYPE_S64;
+    case TFLOAT:
+        return PS_TYPE_F32;
+    case TDOUBLE:
+        return PS_TYPE_F64;
+    case TCOMPLEX:
+        return PS_TYPE_C32;
+    case TDBLCOMPLEX:
+        return PS_TYPE_C64;
+    default:
+        return PS_TYPE_PTR;
+    }
+}
+
 
 static bool convertPsTypeToFits(psElemType type, int* bitPix, double* bZero, int* dataType)
@@ -103,17 +145,17 @@
 }
 
-static bool convertPsMetadataTypeToBinaryTForm(psMetadataType type, char** fitsType)
+static bool convertPsTypeToBinaryTForm(psElemType type, char** fitsType)
 {
     switch (type) {
-    case PS_META_BOOL:
+    case PS_TYPE_BOOL:
         *fitsType = "1L";
         break;
-    case PS_META_S32:
+    case PS_TYPE_S32:
         *fitsType = "1J";
         break;
-    case PS_META_F32:
+    case PS_TYPE_F32:
         *fitsType = "1E";
         break;
-    case PS_META_F64:
+    case PS_TYPE_F64:
         *fitsType = "1D";
         break;
@@ -380,5 +422,4 @@
     char keyValue[MAX_STRING_LENGTH];
     char keyComment[MAX_STRING_LENGTH];
-    psMetadataType metadataItemType;
     psBool tempBool;
     psBool success;
@@ -393,19 +434,39 @@
         switch (keyType) {
         case 'I':
-            metadataItemType = PS_META_S32;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, atoi(keyValue));
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_S32,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    atoi(keyValue));
             break;
         case 'F':
-            metadataItemType = PS_META_F64;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, atof(keyValue));
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_F64,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    atof(keyValue));
             break;
         case 'C':
-            metadataItemType = PS_META_STR;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, keyValue);
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_U8,
+                                    PS_META_STR,
+                                    keyComment,
+                                    keyValue);
             break;
         case 'L':
-            metadataItemType = PS_META_BOOL;
             tempBool = (keyValue[0] == 'T') ? 1 : 0;
-            success = psMetadataAdd(out, PS_LIST_TAIL, keyName, metadataItemType, keyComment, tempBool);
+            success = psMetadataAdd(out,
+                                    PS_LIST_TAIL,
+                                    keyName,
+                                    PS_TYPE_BOOL,
+                                    PS_META_PRIMITIVE,
+                                    keyComment,
+                                    tempBool);
             break;
         case 'U':
@@ -530,5 +591,5 @@
     // write the header, if any.
     if (header != NULL) {
-        psFitsWriteHeader(fits, header);
+        psFitsWriteHeader(header, fits);
     }
 
@@ -567,5 +628,5 @@
 }
 
-bool psFitsWriteHeader(psMetadata* header,
+bool psFitsWriteHeader(const psMetadata* header,
                        psFits* fits)
 {
@@ -583,4 +644,71 @@
     }
 
+    int status = 0;
+
+    //transverse the metadata list and add each key.
+
+    psListIterator* iter = psListIteratorAlloc(header->list,PS_LIST_HEAD);
+    psMetadataItem* item;
+    while ( (item=psListGetNext(iter)) != NULL ) {
+        if (item->type == PS_META_PRIMITIVE) { // we only write primitive data types.
+            switch (item->pType) {
+            case PS_TYPE_BOOL: {
+                    int value = item->data.B;
+                    fits_update_key(fits->p_fd,
+                                    TLOGICAL,
+                                    item->name,
+                                    &value,
+                                    item->comment,
+                                    &status);
+                    break;
+                }
+            case PS_TYPE_S32:
+                fits_update_key(fits->p_fd,
+                                TINT,
+                                item->name,
+                                &item->data.S32,
+                                item->comment,
+                                &status);
+                break;
+            case PS_TYPE_F32:
+                fits_update_key(fits->p_fd,
+                                TFLOAT,
+                                item->name,
+                                &item->data.F32,
+                                item->comment,
+                                &status);
+                break;
+            case PS_TYPE_F64:
+                fits_update_key(fits->p_fd,
+                                TDOUBLE,
+                                item->name,
+                                &item->data.F64,
+                                item->comment,
+                                &status);
+                break;
+            default:
+                psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                        PS_ERRORTEXT_psFits_METADATA_PTYPE_UNSUPPORTED,
+                        item->pType);
+                break;
+            }
+        } else if (item->type == PS_META_STR) {
+            fits_update_key(fits->p_fd,
+                            TSTRING,
+                            item->name,
+                            item->data.V,
+                            item->comment,
+                            &status);
+        }
+
+        if ( status != 0) {
+            char fitsErr[MAX_STRING_LENGTH];
+            (void)fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psFits_WRITE_FAILED,
+                    fits->filename, fitsErr);
+            return false;
+        }
+    }
 
     return true;
@@ -589,19 +717,456 @@
 psMetadata* psFitsReadTableRow(psFits* fits,
                                int row)
-{}
+{
+    long numRows;
+    int numCols;
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    // check to see if we even are positioned on a table HDU
+    int hdutype;
+    fits_get_hdu_type(fits->p_fd,&hdutype, &status);
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
+        return NULL;
+    }
+
+    // get the size of the FITS table
+    fits_get_num_rows(fits->p_fd, &numRows, &status);
+    fits_get_num_cols(fits->p_fd, &numCols, &status);
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+
+    // the row parameter in the proper range?
+    if (row < 1 || row > numRows) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                PS_ERRORTEXT_psFits_ROW_INVALID,
+                row,numRows);
+        return NULL;
+    }
+
+    psMetadata* data = psMetadataAlloc();
+
+    int typecode;
+    long repeat;
+    long width;
+    char name[60];
+    for (int col = 1; col <= numCols; col++) {
+        // get the column name
+        if (hdutype == BINARY_TBL) {
+            fits_get_bcolparms(fits->p_fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
+        } else {
+            fits_get_acolparms(fits->p_fd, col, name,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
+        }
+
+        // get the column type
+        fits_get_coltype(fits->p_fd, col, &typecode, &repeat, &width, &status);
+
+        if (status == 0) {
+
+            #define READ_TABLE_ROW_CASE(FITSTYPE, TYPE) \
+        case FITSTYPE: { \
+                ps##TYPE value; \
+                int anynul = 0; \
+                fits_read_col(fits->p_fd, FITSTYPE, col,row+1, \
+                              1, 1, NULL, &value, &anynul, &status); \
+                if (anynul == 0) { \
+                    psMetadataAdd(data,PS_LIST_TAIL, name, \
+                                  PS_TYPE_S32, PS_META_PRIMITIVE, \
+                                  "", value); \
+                } \
+            } \
+            break;
+
+            switch (typecode) {
+            case TBYTE:
+            case TSHORT:
+                READ_TABLE_ROW_CASE(TLONG, S32)
+                READ_TABLE_ROW_CASE(TFLOAT, F32)
+                READ_TABLE_ROW_CASE(TDOUBLE, F64)
+            default:
+                psTrace("psFits.psFitsReadTableRow", 2,
+                        "Column %d or row %d was of a non primitive type, %d",
+                        col, row, typecode);
+            }
+        }
+
+        if ( status != 0) {
+            char fitsErr[MAX_STRING_LENGTH];
+            (void)fits_get_errstatus(status, fitsErr);
+            psError(PS_ERR_IO, true,
+                    PS_ERRORTEXT_psFits_GET_TABLE_ELEMENT,
+                    col,row,fitsErr);
+            psFree(data);
+            return NULL;
+        }
+
+    }
+
+    return data;
+}
 
 psArray* psFitsReadTableColumn(psFits* fits,
                                const char* colname)
-{}
+{
+    int colnum = 0;
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    // check to see if we even are positioned on a table HDU
+    int hdutype;
+    if ( fits_get_hdu_type(fits->p_fd,&hdutype, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
+        return NULL;
+    }
+
+    // find the column by name
+    if ( fits_get_colnum(fits->p_fd, CASESEN, (char*)colname, &colnum, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_FIND_COLUMN,
+                colname, fitsErr);
+        return NULL;
+    }
+
+    // get the number of rows
+    long numRows = 0;
+    fits_get_num_rows(fits->p_fd, &numRows, &status);
+
+    psArray* result = psArrayAlloc(numRows);
+
+    fits_read_col_str(fits->p_fd,
+                      colnum,
+                      1, // firstrow
+                      1, // firestelem
+                      numRows,
+                      "", // nulstr
+                      (char**)result->data,
+                      NULL,
+                      &status);
+
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_TABLE_READ_COL,
+                fitsErr);
+        return NULL;
+    }
+
+    return result;
+}
 
 psVector* psFitsReadTableColumnNum(psFits* fits,
                                    const char* colname)
-{}
+{
+    int colnum = 0;
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    // check to see if we even are positioned on a table HDU
+    int hdutype;
+    if ( fits_get_hdu_type(fits->p_fd,&hdutype, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
+        return NULL;
+    }
+
+    // find the column by name
+    if ( fits_get_colnum(fits->p_fd, CASESEN, (char*)colname, &colnum, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_FIND_COLUMN,
+                colname, fitsErr);
+        return NULL;
+    }
+
+    // get the number of rows
+    long numRows = 0;
+    fits_get_num_rows(fits->p_fd, &numRows, &status);
+
+    // get the column datatype.
+    int typecode;
+    long repeat;
+    long width;
+    if ( fits_get_eqcoltype(fits->p_fd, colnum, &typecode, &repeat, &width, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_COLTYPE,
+                fitsErr);
+        return NULL;
+    }
+
+    psVector* result = psVectorAlloc(numRows, convertFitsToPsType(typecode));
+
+    fits_read_col(fits->p_fd, typecode, colnum, 1 /* firstrow */,
+                  1 /* firstelem */, numRows, NULL, result->data.V,
+                  NULL, &status);
+
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_TABLE_READ_COL,
+                fitsErr);
+        return NULL;
+    }
+
+    return result;
+}
 
 
 psArray* psFitsReadTable(psFits* fits)
-{}
+{
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    // check to see if we even are positioned on a table HDU
+    int hdutype;
+    if ( fits_get_hdu_type(fits->p_fd,&hdutype, &status) != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+    if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
+        return NULL;
+    }
+
+    // get the size of the FITS table
+    long numRows = 0;
+    int numCols = 0;
+    fits_get_num_rows(fits->p_fd, &numRows, &status);
+    fits_get_num_cols(fits->p_fd, &numCols, &status);
+    if ( status != 0) {
+        char fitsErr[MAX_STRING_LENGTH];
+        (void)fits_get_errstatus(status, fitsErr);
+        psError(PS_ERR_IO, true,
+                PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED,
+                fitsErr);
+        return NULL;
+    }
+
+    psArray* table = psArrayAlloc(numCols);
+
+    for (int row = 0; row < numRows; row++) {
+        table->data[row] = psFitsReadTableRow(fits,row);
+    }
+
+    return table;
+}
 
 bool psFitsWriteTable(psFits* fits,
-                      psArray* table)
-{}
+                      psMetadata* header,
+                      psArray* table,
+                      char* extname)
+{
+    int status = 0;
+
+    if (fits == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_NULL);
+        return NULL;
+    }
+
+    if (table == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                PS_ERRORTEXT_psFits_IMAGE_NULL);
+        return false;
+    }
+
+    int rows = table->n;
+
+    // find all the columns needed
+    psArray* columns = psArrayAlloc(16);
+    columns->n=0;
+
+    // find the unique items in the array of metadata 'rows'
+    psMetadataItem* item;
+    for (int row=0; row < rows; row++) {
+        psMetadata* rowMeta = table->data[row];
+        if (rowMeta != NULL) {
+            psListIterator* iter = psListIteratorAlloc(rowMeta->list,
+                                   PS_LIST_HEAD);
+            while ( (item=psListGetNext(iter)) != NULL) {
+                if (item->type == PS_META_PRIMITIVE) {
+                    bool found = false;
+                    for (int n=0; n < columns->n && ! found; n++) {
+                        if (strcmp(item->name,
+                                   ((psMetadataItem*)(columns->data[n]))->name) == 0) {
+                            found = true;
+                        }
+                    }
+                    if (! found) {
+                        psArrayAdd(columns, columns->nalloc, item);
+                    }
+                }
+            }
+            psFree(iter);
+        }
+    }
+
+    if (columns->n == 0) { // no table columns found
+        // XXX: Error?
+        return false;
+    }
+
+    //create list of column names and types.
+    psArray* columnNames = psArrayAlloc(columns->n);
+    psArray* columnTypes = psArrayAlloc(columns->n);
+    for (int n=0; n < columns->n; n++) {
+        char* fitsType;
+        columnNames->data[n] = ((psMetadataItem*)columns->data[n])->name;
+        if ( ! convertPsTypeToBinaryTForm(((psMetadataItem*)columns->data[n])->pType,
+                                          &fitsType)) {
+            // XXX: error message
+            return false;
+        }
+        columnTypes->data[n] = fitsType;
+    }
+
+    fits_create_tbl(fits->p_fd,
+                    BINARY_TBL,
+                    table->n, // number of rows in table
+                    columns->n, // number of columns in table
+                    (char**)columnNames->data, // names of the columns
+                    (char**)columnTypes->data, // format of the columns
+                    NULL, // physical unit of columns
+                    extname, // extension name
+                    &status);
+
+    // fill in the table elements with data
+    for (int n = 0; n < columns->n; n++) {
+        int row;
+        item = columns->data[n];
+        psArray* columnItems = psArrayAlloc(table->n);
+        for (row = 0; row < table->n; row++) {
+            columnItems->data[row] = psMetadataLookup(table->data[row],item->name);
+        }
+
+        if (item->type == PS_META_PRIMITIVE) {
+            psVector* col = psVectorAlloc(table->n, item->pType);
+            switch (item->pType) {
+            case PS_TYPE_S32:
+                for (row = 0; row < table->n; row++) {
+                    col->data.S32[row] = item->data.S32;
+                }
+                fits_write_col_int(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.S32,
+                                   &status);
+                break;
+            case PS_TYPE_F32:
+                for (row = 0; row < table->n; row++) {
+                    col->data.F32[row] = item->data.F32;
+                }
+                fits_write_col_flt(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.F32,
+                                   &status);
+                break;
+            case PS_TYPE_S64:
+                for (row = 0; row < table->n; row++) {
+                    col->data.F64[row] = item->data.F64;
+                }
+                fits_write_col_dbl(fits->p_fd,
+                                   n, // column number
+                                   1, // firstrow
+                                   1, // firstelem
+                                   table->n, // nelements
+                                   col->data.F64,
+                                   &status);
+                break;
+            default:
+                // XXX: error message
+                psFree(col);
+                psFree(columnItems);
+                psFree(columnNames);
+                psFree(columnTypes);
+                psFree(columns);
+                return false;
+            }
+
+        } else if (item->type == PS_META_STR) {
+            psArray* col = psArrayAlloc(table->n);
+            for (row = 0; row < table->n; row++) {
+                col->data[row] = item->data.V;
+            }
+            fits_write_col_str(fits->p_fd,
+                               n, // column number
+                               1, // firstrow
+                               1, // firstelem
+                               table->n, // nelements
+                               (char**)col->data,
+                               &status);
+        }
+    }
+
+    return true;
+}
