# include <stdio.h>
# include <strings.h>
# include <math.h>
# include "pslib.h"

int parseFile (psFits *fits, char *file);

int main (int argc, char **argv) {

    unsigned int nFail;

    if (argc != 3) {
        fprintf (stderr, "USAGE: icd-demo (input) (output)\n");
        exit (2);
    }

    // construct a sample FITS table based on the given descriptive metadata file
    psMetadata *fd      = psMetadataConfigRead(NULL, &nFail, argv[1], false);

    psFits *fits = psFitsOpen (argv[2], "w");

    psMetadata *header  = psMetadataLookupPtr (NULL, fd, "HEADER");
    psFitsWriteBlank (fits, header, "");

    // get the list pointers for the PSF_MODEL entries
    psList *list = NULL;
    psMetadataItem *mdi = psMetadataLookup (fd, "TABLE");
    if (mdi->type == PS_DATA_STRING) {
        list = psListAlloc(NULL);
        psListAdd (list, PS_LIST_HEAD, mdi);
    } else {
        list = psMemIncrRefCounter(mdi->data.list);
    }

    // try each model option listed in config
    psMetadataItem *item = NULL;
    psListIterator *iter = psListIteratorAlloc (list, PS_LIST_HEAD, FALSE);
    while ((item = psListGetAndIncrement (iter)) != NULL) {
        char *file = item->data.V;
        parseFile (fits, file);
    }
    psFitsClose (fits);
}

int parseFile (psFits *fits, char *file) {

    unsigned int nFail;
    char unitWord[64];
    double min, max, rvalue, range;

    fprintf (stderr, "reading %s\n", file);
    psMetadataItem *col;
    psRandom *rnd = psRandomAlloc (PS_RANDOM_TAUS, 0);

    // construct a sample FITS table based on the given descriptive metadata file
    psMetadata *fd      = psMetadataConfigRead(NULL, &nFail, file, false);

    psMetadata *blank  = psMetadataLookupPtr (NULL, fd, "BLANK");
    if (blank) {
        fprintf (stderr, "adding BLANK\n");
        psFitsWriteBlank (fits, blank, "");
    }

    psMetadata *fitstable  = psMetadataLookupPtr (NULL, fd, "FITSTABLE");
    if (fitstable) {
        fprintf (stderr, "adding TABLE\n");
        psMetadata *header  = psMetadataLookupPtr (NULL, fitstable, "HEADER");
        psMetadata *columns = psMetadataLookupPtr (NULL, fitstable, "COLUMNS");
        psMetadataIterator *iter = psMetadataIteratorAlloc (columns, PS_LIST_HEAD, NULL);
        char *extname       = psMetadataLookupStr (NULL, header, "EXTNAME");

        psArray *table = psArrayAllocEmpty (10);

        // XXX insert unit values: we need a method to do this in psFitsWriteTable
        int nCol = 1;
        while ((col = psMetadataGetAndIncrement (iter)) != NULL) {
            psMetadata *md = col->data.V;
            char *unit = psMetadataLookupStr (NULL, md, "TUNIT");
            if (strcasecmp (unit, "NONE")) {
                sprintf (unitWord, "TUNIT%d", nCol);
                psMetadataAddStr (header, PS_LIST_TAIL, unitWord, 0, "", unit);
            }
            nCol ++;
        }
        psMetadataIteratorSet (iter, PS_LIST_HEAD);

        // make a total of NN fake data columns
        for (int i = 0; i < 10; i++) {

            int nCol = 1;

            psMetadata *row = psMetadataAlloc ();

            while ((col = psMetadataGetAndIncrement (iter)) != NULL) {

                psMetadata *md = col->data.V;

                char *format = psMetadataLookupStr (NULL, md, "TFORM");
                char *comment = psMetadataLookupStr (NULL, md, "COMMENT");
                char *unit = psMetadataLookupStr (NULL, md, "TUNIT");
                if (strcasecmp (unit, "NONE")) {
                    sprintf (unitWord, "TUNIT%d", nCol);
                    psMetadataAddStr (header, PS_LIST_TAIL, unitWord, 0, "", unit);
                }

                if (!strcasecmp (format, "I")) {
                    int value;

                    char *minWord = psMetadataLookupStr (NULL, md, "TMIN");
                    char *maxWord = psMetadataLookupStr (NULL, md, "TMAX");

                    min = atoi (minWord);
                    if (!strcasecmp (minWord, "NONE")) min = 0;
                    max = atoi (maxWord);
                    if (!strcasecmp (maxWord, "NONE")) max = 100;
                    range = max - min;

                    rvalue = psRandomUniform (rnd);
                    value = range * rvalue + min;

                    psMetadataAdd (row, PS_LIST_TAIL, col->name, PS_DATA_S16, comment, value);
                }

                if (!strcasecmp (format, "J")) {
                    int value;

                    char *minWord = psMetadataLookupStr (NULL, md, "TMIN");
                    char *maxWord = psMetadataLookupStr (NULL, md, "TMAX");

                    min = atoi (minWord);
                    if (!strcasecmp (minWord, "NONE")) min = 0;
                    max = atoi (maxWord);
                    if (!strcasecmp (maxWord, "NONE")) max = 100;
                    range = max - min;

                    rvalue = psRandomUniform (rnd);
                    value = range * rvalue + min;

                    psMetadataAdd (row, PS_LIST_TAIL, col->name, PS_DATA_S32, comment, value);
                }

                if (!strcasecmp (format, "K")) {
                    long int value;

                    char *minWord = psMetadataLookupStr (NULL, md, "TMIN");
                    char *maxWord = psMetadataLookupStr (NULL, md, "TMAX");

                    min = atoi (minWord);
                    if (!strcasecmp (minWord, "NONE")) min = 0;
                    max = atoi (maxWord);
                    if (!strcasecmp (maxWord, "NONE")) max = 100;
                    range = max - min;

                    rvalue = psRandomUniform (rnd);
                    value = range * rvalue + min;

                    psMetadataAdd (row, PS_LIST_TAIL, col->name, PS_DATA_S64, comment, value);
                }

                if (!strcasecmp (format, "E")) {
                    float value;

                    char *minWord = psMetadataLookupStr (NULL, md, "TMIN");
                    char *maxWord = psMetadataLookupStr (NULL, md, "TMAX");

                    min = atoi (minWord);
                    if (!strcasecmp (minWord, "NONE")) min = 0;
                    max = atoi (maxWord);
                    if (!strcasecmp (maxWord, "NONE")) max = 100;
                    range = max - min;

                    rvalue = psRandomUniform (rnd);
                    value = range * rvalue + min;

                    psMetadataAdd (row, PS_LIST_TAIL, col->name, PS_DATA_F32, comment, value);
                }

                if (!strcasecmp (format, "D")) {
                    double value;

                    char *minWord = psMetadataLookupStr (NULL, md, "TMIN");
                    char *maxWord = psMetadataLookupStr (NULL, md, "TMAX");

                    min = atoi (minWord);
                    if (!strcasecmp (minWord, "NONE")) min = 0;
                    max = atoi (maxWord);
                    if (!strcasecmp (maxWord, "NONE")) max = 100;
                    range = max - min;

                    rvalue = psRandomUniform (rnd);
                    value = range * rvalue + min;

                    psMetadataAdd (row, PS_LIST_TAIL, col->name, PS_DATA_F64, comment, value);
                }

                if (!strcasecmp (format, "A")) {
                    char *value = NULL;
                    psStringAppend (&value, "word %03d", i);
                    psMetadataAdd (row, PS_LIST_TAIL, col->name, PS_DATA_STRING, "", value);
                }
            }
            psArrayAdd (table, 100, row);
            psFree (row);
            psMetadataIteratorSet (iter, PS_LIST_HEAD);
        }
        psFitsInsertTable (fits, header, table, extname, true);
    }
    return 1;
}
