/* $Id: cpl_propertylist-test.c,v 1.6 2012-01-17 07:53:20 amodigli Exp $
 *
 * This file is part of the ESO Common Pipeline Library
 * Copyright (C) 2001-2005 European Southern Observatory
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * $Author: amodigli $
 * $Date: 2012-01-17 07:53:20 $
 * $Revision: 1.6 $
 * $Name: not supported by cvs2svn $
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#undef CX_DISABLE_ASSERT
#undef CX_LOG_DOMAIN


#include <uves_propertylist.h>

//#include "cpl_init.h"
//#include "cpl_error.h"
//#include "cpl_propertylist_impl.h"
#include <uves_error.h>
#include <cpl.h>
#include <cxmemory.h>
#include <cxmessages.h>
#include <cxdeque.h>
#include <qfits.h>
#include <fitsio.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <uves_propertylist.h>
#define FLT_EPS  1.0e-6
#define DBL_EPS  1.0e-14


static void
test_property_dump(cpl_property *property)
{

    const cxchar *name = cpl_property_get_name(property);
    const cxchar *comment = cpl_property_get_comment(property);

    cxchar c;

    long size = cpl_property_get_size(property);

    cpl_type type = cpl_property_get_type(property);


    fprintf(stderr, "Property at address %p\n", (void *)property);
    fprintf(stderr, "\tname   : %p '%s'\n", (void *)name, name);
    fprintf(stderr, "\tcomment: %p '%s'\n", (void *)comment, comment);
    fprintf(stderr, "\ttype   : %#09x\n", type);
    fprintf(stderr, "\tsize   : %ld\n", size);
    fprintf(stderr, "\tvalue  : ");


    switch (type) {
    case CPL_TYPE_CHAR:
        c = cpl_property_get_char(property);
        if (!c)
            fprintf(stderr, "''");
        else
            fprintf(stderr, "'%c'", c);
        break;

    case CPL_TYPE_BOOL:
        fprintf(stderr, "%d", cpl_property_get_bool(property));
        break;

    case CPL_TYPE_INT:
        fprintf(stderr, "%d", cpl_property_get_int(property));
        break;

    case CPL_TYPE_LONG:
        fprintf(stderr, "%ld", cpl_property_get_long(property));
        break;

    case CPL_TYPE_FLOAT:
        fprintf(stderr, "%.7g", cpl_property_get_float(property));
        break;

    case CPL_TYPE_DOUBLE:
        fprintf(stderr, "%.15g", cpl_property_get_double(property));
        break;

    case CPL_TYPE_STRING:
        fprintf(stderr, "'%s'", cpl_property_get_string(property));
        break;

    default:
        fprintf(stderr, "unknown.");
        break;

    }

    fprintf(stderr, "\n");

    return;

}


static void
test_plist_dump(cpl_propertylist *plist)
{

    cxlong i;
    cxlong sz = cpl_propertylist_get_size(plist);


    fprintf(stderr, "Property list at address %p:\n", (void *) plist);

    for (i = 0; i < sz; i++) {
        cpl_property *p = cpl_propertylist_get(plist, i);
        test_property_dump(p);
    }

    return;

}

static int test_main(void)
{

    const cxchar *keys[] = {
        "a", "b", "c", "d", "e", "f", "g",
        "A", "B", "C", "D", "E", "F", "G"
    };

    const cxchar *comments[] = {
        "A character value",
        "A boolean value",
        "A integer value",
        "A long integer value",
        "A floating point number",
        "A double precision number",
        "A string value",
    };

    cpl_type types[] = {
        CPL_TYPE_CHAR,
        CPL_TYPE_BOOL,
        CPL_TYPE_INT,
        CPL_TYPE_LONG,
        CPL_TYPE_FLOAT,
        CPL_TYPE_DOUBLE,
        CPL_TYPE_STRING
    };

    cxlong i;

    cxfloat fval[] = {-1.23456789, 0.};
    cxdouble dval[] = {-1.23456789, 0.};

    cpl_propertylist *plist=NULL;
    cpl_propertylist *_plist=NULL;

    cpl_propertylist *header=NULL;
    //cpl_propertylist *_header=NULL;
    cpl_property* p=NULL;

    struct fcard {
        const cxchar *key;
        const cxchar *val;
        const cxchar *com;
        cpl_type type;
    };

    struct fcard hdr[] = {
        {"SIMPLE", "T",
	 //         "Standard FITS format (NOST-100.0)",
         //"Fits format",
         "file does conform to FITS standard",
         CPL_TYPE_BOOL},
        {"BITPIX", "16",
	 //         "# of bits storing pix values",
         //"Bits per pixel",
         "number of bits per data pixel",
         CPL_TYPE_INT},
        {"NAXIS", "2",
	 //         "# of axes in frame",
         "number of data axes",
         CPL_TYPE_INT},
        {"NAXIS1", "2148",
	 //         "# pixels/axis",
         "length of data axis 1",
         CPL_TYPE_INT},
        {"NAXIS2", "2340",
	 //         "# pixels/axis",
         "length of data axis 2",
         CPL_TYPE_INT},
        {"EXTEND", "T",
	 //         "# pixels/axis",
         "FITS dataset may contain extensions",
         CPL_TYPE_BOOL},
        {"ORIGIN", "ESO",
         "European Southern Observatory",
         CPL_TYPE_STRING},
        {"DATE", "2002-03-08T04:27:21.420",
         "Date this file was written (dd/mm/yyyy)",
         CPL_TYPE_STRING},
        {"MJD-OBS", "52341.17813019",
         "Obs start 2002-03-08T04:16:30.448",
         CPL_TYPE_DOUBLE},
        {"DATE-OBS", "2002-03-08T04:16:30.448",
         "Date of observation",
         CPL_TYPE_STRING},
        {"EXPTIME", "600.000",
         "Total integration time. 00:10:00.000",
         CPL_TYPE_DOUBLE},
        {"TELESCOP", "VLT",
         "ESO <TEL>",
         CPL_TYPE_STRING},
        {"RA", "181.41734",
         "12:05:40.1 RA (J2000) pointing",
         CPL_TYPE_DOUBLE},
        {"DEC", "-7.65555",
         "-07:39:19.9  DEC (J2000) pointing",
         CPL_TYPE_DOUBLE},
        {"EQUINOX", "2000.",
         "Standard FK5 (years)",
         CPL_TYPE_DOUBLE},
        {"RADECSYS", "FK5",
         "Coordinate reference frame",
         CPL_TYPE_STRING},
        {"LST", "38309.370",
         "10:38:29.370 LST at start",
         CPL_TYPE_DOUBLE},
        {"UTC", "15438.000",
         "04:17:18.000 UT at start",
         CPL_TYPE_DOUBLE},
        {"OBSERVER", "UNKNOWN",
         "Name of observer",
         CPL_TYPE_STRING},
        {"INSTRUME", "UNKNOWN",
         "Instrument used",
         CPL_TYPE_STRING},
        {"PI-COI", "'555555555'",
         "Name of PI and COI",
         CPL_TYPE_STRING},
        {"OBJECT", "None",
         "Original target",
         CPL_TYPE_STRING},
        {"PCOUNT", "0",
         "Number of parameters per group",
         CPL_TYPE_INT},
        {"GCOUNT", "1",
         "Number of groups",
         CPL_TYPE_INT},
        {"CRVAL1", "181.41734",
         "12:05:40.1, RA at ref pixel",
         CPL_TYPE_DOUBLE},
        {"CRPIX1", "2341.8585366",
         "Reference pixel in X",
         CPL_TYPE_DOUBLE},
        {"CDELT1", "0.20500000",
         "SS arcsec per pixel in RA",
         CPL_TYPE_DOUBLE},
        {"CTYPE1", "RA---TAN",
         "pixel coordinate system",
         CPL_TYPE_STRING},
        {"CRVAL2", "-7.65555",
         "-07:39:19.9, DEC at ref pixel",
         CPL_TYPE_DOUBLE},
        {"CRPIX2", "2487.8585366",
         "Reference pixel in Y",
         CPL_TYPE_DOUBLE},
        {"CDELT2", "0.20500000",
         "SS arcsec per pixel in DEC",
         CPL_TYPE_DOUBLE},
        {"CTYPE2", "DEC--TAN",
         "pixel coordinate system",
         CPL_TYPE_STRING},
        {"BSCALE", "1.0",
         "pixel=FITS*BSCALE+BZERO",
         CPL_TYPE_DOUBLE},
        {"BZERO", "32768.0",
         "pixel=FITS*BSCALE+BZERO",
         CPL_TYPE_DOUBLE},
        {"CD1_1", "0.000057",
         "Translation matrix element",
         CPL_TYPE_DOUBLE},
        {"CD1_2", "0.000000",
         "Translation matrix element",
         CPL_TYPE_DOUBLE},
        {"CD2_1", "0.000000",
         "Translation matrix element",
         CPL_TYPE_DOUBLE},
        {"CD2_2", "0.000057",
         "Translation matrix element",
         CPL_TYPE_DOUBLE},
        {"HIERARCH ESO OBS DID", "ESO-VLT-DIC.OBS-1.7",
         "OBS Dictionary",
         CPL_TYPE_STRING},
        {"HIERARCH ESO OBS OBSERVER", "UNKNOWN",
         "Observer Name",
         CPL_TYPE_STRING},
        {"HIERARCH ESO OBS PI-COI NAME", "UNKNOWN",
         "PI-COI name",
         CPL_TYPE_STRING},
        {"HIERARCH ESO INS GRAT NAME", "HR",
         "Grating name",
         CPL_TYPE_STRING},
        {"HIERARCH ESO PRO CATG", "X",
         "Product category",
         CPL_TYPE_STRING},
        {"HIERARCH ESO TPL NEXP", "5",
         "Number of exposures",
         CPL_TYPE_INT},
        {"HISTORY", "1st history record", NULL, CPL_TYPE_STRING},
        {"COMMENT", "1st comment record", NULL, CPL_TYPE_STRING},
        {"HISTORY", "2st history record", NULL, CPL_TYPE_STRING},
        {"COMMENT", "2st comment record", NULL, CPL_TYPE_STRING},
        {"COMMENT", "3st comment record", NULL, CPL_TYPE_STRING},
        {"HISTORY", "3st history record", NULL, CPL_TYPE_STRING},
        {"END", NULL, NULL, CPL_TYPE_STRING}
    };
    cpl_image* ima;

    FILE *file;
    /*
    const cxchar *longname = "0123456789012345678901234567890123456789"
        "0123456789012345678901234567890123456789";

    */
    /*
     * Test 1: Create a property list and check its validity.
     */
    plist = cpl_propertylist_new();

    cx_assert(plist != NULL);
    cx_assert(cpl_propertylist_is_empty(plist));
    cx_assert(cpl_propertylist_get_size(plist) == 0);
    check_nomsg( cpl_error_get_code()   );

    /*
     * Test 2: Append properties to the list created in the previous test
     *         and verify the data.
     */
    cpl_propertylist_append_char(plist, keys[0], 'a');
    cpl_propertylist_set_comment(plist, keys[0], comments[0]);

    cpl_propertylist_append_bool(plist, keys[1], 1);
    cpl_propertylist_set_comment(plist, keys[1], comments[1]);

    cpl_propertylist_append_int(plist, keys[2], -1);
    cpl_propertylist_set_comment(plist, keys[2], comments[2]);

    cpl_propertylist_append_long(plist, keys[3], 32768);
    cpl_propertylist_set_comment(plist, keys[3], comments[3]);

    cpl_propertylist_append_float(plist, keys[4], fval[0]);
    cpl_propertylist_set_comment(plist, keys[4], comments[4]);

    cpl_propertylist_append_double(plist, keys[5], dval[0]);
    cpl_propertylist_set_comment(plist, keys[5], comments[5]);

    cpl_propertylist_append_string(plist, keys[6], comments[6]);
    cpl_propertylist_set_comment(plist, keys[6], comments[6]);

    cx_assert(!cpl_propertylist_is_empty(plist));
    cx_assert(cpl_propertylist_get_size(plist) == 7);


    for (i = 0; i < cpl_propertylist_get_size(plist); i++) {
        cpl_property *prop = cpl_propertylist_get(plist, i);

        cx_assert(!strcmp(cpl_property_get_name(prop), keys[i]));
        cx_assert(!strcmp(cpl_property_get_comment(prop), comments[i]));
        cx_assert(cpl_property_get_type(prop) == types[i]);

        cx_assert(my_uves_propertylist_contains(plist, keys[i]));
        cx_assert(!strcmp(cpl_propertylist_get_comment(plist, keys[i]),
                          comments[i]));
        cx_assert(cpl_propertylist_get_type(plist, keys[i]) == types[i]);
    }

    cx_assert(cpl_propertylist_get_char(plist, keys[0]) == 'a');
    cx_assert(cpl_propertylist_get_bool(plist, keys[1]) == 1);
    cx_assert(cpl_propertylist_get_int(plist, keys[2]) == -1);
    cx_assert(cpl_propertylist_get_long(plist, keys[3]) == 32768);

    fval[1] = cpl_propertylist_get_float(plist, keys[4]);
    cx_assert(!memcmp(&fval[0], &fval[1], sizeof(float)));

    dval[1] = cpl_propertylist_get_double(plist, keys[5]);
    cx_assert(!memcmp(&dval[0], &dval[1], sizeof(double)));

    cx_assert(!strcmp(cpl_propertylist_get_string(plist, keys[6]),
                      comments[6]));
    check_nomsg( cpl_error_get_code() );

    /*
     * Test 3: Modify the values of the property list entries
     *         and verify the data.
     */

    cx_assert(cpl_propertylist_set_char(plist, keys[0], 'b') == 0);
    cx_assert(cpl_propertylist_get_char(plist, keys[0]) == 'b');

    cx_assert(cpl_propertylist_set_bool(plist, keys[1], 0) == 0);
    cx_assert(cpl_propertylist_get_bool(plist, keys[1]) == 0);

    cx_assert(cpl_propertylist_set_int(plist, keys[2], -1) == 0);
    cx_assert(cpl_propertylist_get_int(plist, keys[2]) == -1);

    cx_assert(cpl_propertylist_set_long(plist, keys[3], 1) == 0);
    cx_assert(cpl_propertylist_get_long(plist, keys[3]) == 1);

    fval[0] = 9.87654321;
    cx_assert(cpl_propertylist_set_float(plist, keys[4], fval[0]) == 0);
    fval[1] = cpl_propertylist_get_float(plist, keys[4]);
    cx_assert(!memcmp(&fval[0], &fval[1], sizeof(float)));

    dval[0] = -9.87654321;
    cx_assert(cpl_propertylist_set_double(plist, keys[5], dval[0]) == 0);
    dval[1] = cpl_propertylist_get_double(plist, keys[5]);
    cx_assert(!memcmp(&dval[0], &dval[1], sizeof(double)));

    cx_assert(cpl_propertylist_set_string(plist, keys[6], comments[0]) == 0);
    cx_assert(!strcmp(cpl_propertylist_get_string(plist, keys[6]),
                      comments[0]));
    check_nomsg(  cpl_error_get_code()   );


    /*
     * Test 4: Check that trying to modify an entry with a different
     *         type is properly failing.
     */
 
    check_nomsg(  cpl_error_get_code()  );
    if (0) test_plist_dump(plist);
    check_nomsg(  cpl_error_get_code()  );

    if(cpl_propertylist_set_char(plist, keys[1], 'a') ==
       CPL_ERROR_TYPE_MISMATCH) { cpl_error_reset(); }

    check_nomsg(  cpl_error_get_code()  );
    if (0) test_plist_dump(plist);


    check_nomsg(  cpl_error_get_code()  );
    if(cpl_propertylist_set_bool(plist, keys[2], 1) ==
       CPL_ERROR_TYPE_MISMATCH) { cpl_error_reset(); }

    check_nomsg(  cpl_error_get_code()  );
    if(cpl_propertylist_set_int(plist, keys[3], 1) ==
       CPL_ERROR_TYPE_MISMATCH){ cpl_error_reset(); }

    check_nomsg(  cpl_error_get_code()  );
    if(cpl_propertylist_set_long(plist, keys[4], 1) ==
       CPL_ERROR_TYPE_MISMATCH){ cpl_error_reset(); }
    check_nomsg(  cpl_error_get_code()  );
    if(cpl_propertylist_set_float(plist, keys[5], 1.) ==
       CPL_ERROR_TYPE_MISMATCH){ cpl_error_reset(); }
    check_nomsg(  cpl_error_get_code()  );
    if(cpl_propertylist_set_double(plist, keys[6], 1.) ==
       CPL_ERROR_TYPE_MISMATCH){ cpl_error_reset(); }

    check_nomsg(  cpl_error_get_code()  );
    if(cpl_propertylist_set_string(plist, keys[0], comments[0]) ==
       CPL_ERROR_TYPE_MISMATCH){ cpl_error_reset(); }
    check_nomsg(  cpl_error_get_code()  );



    /*
     * Test 5: Verify that values are inserted correctly into the property
     *         list.
     */


    cx_assert(cpl_propertylist_insert_char(plist, keys[0],
                                           keys[7], 'a') == 0);
    cx_assert(cpl_propertylist_insert_after_char(plist, keys[0],
                                                 keys[7], 'c') == 0);

    cx_assert(cpl_propertylist_insert_bool(plist, keys[1],
                                           keys[8], 0) == 0);
    cx_assert(cpl_propertylist_insert_after_bool(plist, keys[1],
                                                 keys[8], 1) == 0);

    cx_assert(cpl_propertylist_insert_int(plist, keys[2],
                                          keys[9], 0) == 0);
    cx_assert(cpl_propertylist_insert_after_int(plist, keys[2],
                                                keys[9], 1) == 0);

    cx_assert(cpl_propertylist_insert_long(plist, keys[3], keys[10],
                                           123456789) == 0);
    cx_assert(cpl_propertylist_insert_after_long(plist, keys[3], keys[10],
                                                 123456789) == 0);

    cx_assert(cpl_propertylist_insert_float(plist, keys[4], keys[11],
                                            fval[0]) == 0);
    cx_assert(cpl_propertylist_insert_after_float(plist, keys[4], keys[11],
                                                  -fval[0]) == 0);

    cx_assert(cpl_propertylist_insert_double(plist, keys[5], keys[12],
                                             dval[0]) == 0);
    cx_assert(cpl_propertylist_insert_after_double(plist, keys[5], keys[12],
                                                   -dval[0]) == 0);

    cx_assert(cpl_propertylist_insert_string(plist, keys[6],
                                             keys[13], "") == 0);
    cx_assert(cpl_propertylist_insert_after_string(plist, keys[6],
                                                   keys[13], "") == 0);
    for (i = 0; i < 7; i++) {
        cpl_property *p0 = cpl_propertylist_get(plist, 3 * i);
        cpl_property *p1 = cpl_propertylist_get(plist, 3 * i + 1);
        cpl_property *p2 = cpl_propertylist_get(plist, 3 * i + 2);

        cx_assert(!strcmp(cpl_property_get_name(p0), keys[i + 7]));
        cx_assert(!strcmp(cpl_property_get_name(p1), keys[i]));
        cx_assert(!strcmp(cpl_property_get_name(p2), keys[i + 7]));

        switch (cpl_property_get_type(p0)) {
        case CPL_TYPE_CHAR:
            cx_assert(cpl_property_get_char(p0) == 'a');
            cx_assert(cpl_property_get_char(p2) == 'c');
            break;

        case CPL_TYPE_BOOL:
            cx_assert(cpl_property_get_bool(p0) == 0);
            cx_assert(cpl_property_get_bool(p2) == 1);
            break;

        case CPL_TYPE_INT:
            cx_assert(cpl_property_get_int(p0) == 0);
            cx_assert(cpl_property_get_int(p2) == 1);
            break;

        case CPL_TYPE_LONG:
            cx_assert(cpl_property_get_long(p0) == 123456789);
            cx_assert(cpl_property_get_long(p2) == 123456789);
            break;

        case CPL_TYPE_FLOAT:
            fval[1] = cpl_property_get_float(p0);
            cx_assert(!memcmp(&fval[0], &fval[1], sizeof(float)));

            fval[1] = -cpl_property_get_float(p2);
            cx_assert(!memcmp(&fval[0], &fval[1], sizeof(float)));
            break;

        case CPL_TYPE_DOUBLE:
            dval[1] = cpl_property_get_double(p0);
            cx_assert(!memcmp(&dval[0], &dval[1], sizeof(double)));

            dval[1] = -cpl_property_get_double(p2);
            cx_assert(!memcmp(&dval[0], &dval[1], sizeof(double)));
            break;

        case CPL_TYPE_STRING:
            cx_assert(!strcmp(cpl_property_get_string(p0), ""));
            cx_assert(!strcmp(cpl_property_get_string(p2), ""));
            break;

        default:
            /* This point should never be reached */
            cx_log("cpl_propertylist-test", CX_LOG_LEVEL_ERROR, "file %s: "
                   "line %d: Invalid value type encountered", __FILE__,
                   __LINE__);
            break;
        }
    }

    check_nomsg(  cpl_error_get_code()   );


    /*
     * Test 6: Verify that modification of or insertion at/after a non
     *         existing elements is reported correctly.
     */

    cx_assert(my_uves_propertylist_contains(plist, "Non-existing key") == 0);
   check_nomsg(  cpl_error_get_code()   );

    if(cpl_propertylist_set_char(plist, "Non-existing key", 'a') ==
       CPL_ERROR_DATA_NOT_FOUND){ cpl_error_reset(); }

   check_nomsg(  cpl_error_get_code()   );
    if(cpl_propertylist_set_bool(plist, "Non-existing key", 1) ==
              CPL_ERROR_DATA_NOT_FOUND) { cpl_error_reset(); }
   check_nomsg(  cpl_error_get_code()   );
   if(cpl_propertylist_set_int(plist, "Non-existing key", 1) ==
              CPL_ERROR_DATA_NOT_FOUND){ cpl_error_reset(); }
   check_nomsg(  cpl_error_get_code()   );
   if(cpl_propertylist_set_long(plist, "Non-existing key", 1) ==
              CPL_ERROR_DATA_NOT_FOUND){ cpl_error_reset(); }
   check_nomsg(  cpl_error_get_code()   );
   if(cpl_propertylist_set_float(plist, "Non-existing key", 1) ==
              CPL_ERROR_DATA_NOT_FOUND){ cpl_error_reset(); }
   check_nomsg(  cpl_error_get_code()   );
   if(cpl_propertylist_set_double(plist, "Non-existing key", 1) ==
              CPL_ERROR_DATA_NOT_FOUND){ cpl_error_reset(); }
   check_nomsg(  cpl_error_get_code()   );
   if(cpl_propertylist_set_string(plist, "Non-existing key", "") ==
              CPL_ERROR_DATA_NOT_FOUND){ cpl_error_reset(); }

   if(cpl_propertylist_insert_char(plist, "Non-existing key",
				   "h", 'a') == 1){ cpl_error_reset(); }

   if(cpl_propertylist_insert_bool(plist, "Non-existing key",
                                           "h", 1) == 1){ cpl_error_reset(); }

   if(cpl_propertylist_insert_int(plist, "Non-existing key",
				  "h", 1) == 1) { cpl_error_reset(); }

   if(cpl_propertylist_insert_long(plist, "Non-existing key",
				   "h", 1) == 1) { cpl_error_reset(); }
   if(cpl_propertylist_insert_float(plist, "Non-existing key",
				    "h", 1) == 1){ cpl_error_reset(); }

   if(cpl_propertylist_insert_double(plist, "Non-existing key",
				     "h", 1) == 1){ cpl_error_reset(); }
   if(cpl_propertylist_insert_string(plist, "Non-existing key",
				     "h", "") == 1){ cpl_error_reset(); }
   check_nomsg(  cpl_error_get_code()   );

   if(cpl_propertylist_insert_after_char(plist, "Non-existing key",
					 "h", 'a') == 1){ cpl_error_reset(); }
   if(cpl_propertylist_insert_after_bool(plist, "Non-existing key",
					 "h", 1) == 1){ cpl_error_reset(); }
   if(cpl_propertylist_insert_after_int(plist, "Non-existing key",
					"h", 1) == 1){ cpl_error_reset(); }
   if(cpl_propertylist_insert_after_long(plist, "Non-existing key",
					 "h", 1) == 1){ cpl_error_reset(); }
   if(cpl_propertylist_insert_after_float(plist, "Non-existing key",
					  "h", 1) == 1){ cpl_error_reset(); }
   if(cpl_propertylist_insert_after_double(plist, "Non-existing key",
					   "h", 1) == 1){ cpl_error_reset(); }
   if(cpl_propertylist_insert_after_string(plist, "Non-existing key",
					   "h", "") == 1){ cpl_error_reset(); }

  

    /*
     * Test 7: Create a copy of the property list and verify that original
     *         and copy are identical but do not share any resources.
     */

    cpl_propertylist_delete(_plist);
 
    _plist = cpl_propertylist_duplicate(plist);


    cx_assert(_plist != NULL);
    cx_assert(_plist != plist);


    for (i = 0; i < cpl_propertylist_get_size(plist); i++) {
        cpl_property *prop = cpl_propertylist_get(plist, i);
        cpl_property *_prop = cpl_propertylist_get(_plist, i);


        cx_assert(cpl_property_get_name(prop) != cpl_property_get_name(_prop));
        cx_assert(!strcmp(cpl_property_get_name(prop),
                          cpl_property_get_name(_prop)));
        cx_assert(cpl_property_get_comment(prop) == NULL ||
                  (cpl_property_get_comment(prop) !=
                   cpl_property_get_comment(_prop)));
        cx_assert(cpl_property_get_comment(prop) == NULL ||
                  !strcmp(cpl_property_get_comment(prop),
                          cpl_property_get_comment(_prop)));

        switch (cpl_property_get_type(prop)) {
        case CPL_TYPE_CHAR:
            cx_assert(cpl_property_get_char(prop) ==
                      cpl_property_get_char(_prop));
            break;

        case CPL_TYPE_BOOL:
            cx_assert(cpl_property_get_bool(prop) ==
                      cpl_property_get_bool(_prop));
            break;

        case CPL_TYPE_INT:
            cx_assert(cpl_property_get_int(prop) ==
                      cpl_property_get_int(_prop));
            break;

        case CPL_TYPE_LONG:
            cx_assert(cpl_property_get_long(prop) ==
                      cpl_property_get_long(_prop));
            break;

        case CPL_TYPE_FLOAT:
            fval[0] = cpl_property_get_float(prop);
            fval[1] = cpl_property_get_float(_prop);
            cx_assert(!memcmp(&fval[0], &fval[1], sizeof(float)));
            break;

        case CPL_TYPE_DOUBLE:
            dval[0] = cpl_property_get_double(prop);
            dval[1] = cpl_property_get_double(_prop);
            cx_assert(!memcmp(&dval[0], &dval[1], sizeof(double)));
            break;

        case CPL_TYPE_STRING:
            cx_assert(!strcmp(cpl_property_get_string(prop),
                              cpl_property_get_string(_prop)));
            break;

        default:
            /* This point should never be reached */
            cx_log("cpl_propertylist-test", CX_LOG_LEVEL_ERROR, "file %s: "
                   "line %d: Invalid value type encountered", __FILE__,
                   __LINE__);
            break;
        }


    }

    cpl_propertylist_delete(_plist);
    check_nomsg(   cpl_error_get_code()  );
 

   /*
     * Test 8: Erase elements from the property list and verify the list
     *         structure and the data.
     */

    for (i = 0; i < 7; i++) {
        cpl_propertylist_erase(plist, keys[i + 7]);
        cx_assert(my_uves_propertylist_contains(plist, keys[i + 7]) == 1);

        cpl_propertylist_erase(plist, keys[i + 7]);
        cx_assert(my_uves_propertylist_contains(plist, keys[i + 7]) == 0);
    }
    cx_assert(cpl_propertylist_get_size(plist) == 7);

    for (i = 0; i < 7; i++) {
        cpl_property *prop = cpl_propertylist_get(plist, i);
        cx_assert(!strcmp(cpl_property_get_name(prop), keys[i]));
    }

    if (0) test_plist_dump(plist);
    
    cx_assert(cpl_propertylist_get_char(plist, keys[0]) == 'b');
    cx_assert(cpl_propertylist_get_bool(plist, keys[1]) == 0);
    cx_assert(cpl_propertylist_get_int(plist, keys[2]) == -1);
    cx_assert(cpl_propertylist_get_long(plist, keys[3]) == 1);

    fval[0] = 9.87654321;
    fval[1] = cpl_propertylist_get_float(plist, keys[4]);
    cx_assert(!memcmp(&fval[0], &fval[1], sizeof(float)));

    dval[0] = -9.87654321;
    dval[1] = cpl_propertylist_get_double(plist, keys[5]);
    cx_assert(!memcmp(&dval[0], &dval[1], sizeof(double)));

    cx_assert(!strcmp(cpl_propertylist_get_string(plist, keys[6]),
                      comments[0]));

    check_nomsg(  cpl_error_get_code()   );
 

    /*
     * Test 9: Erase all elements from the property list and verify that
     *         the list is empty.
     */


    cpl_propertylist_empty(plist);

    cx_assert(cpl_propertylist_is_empty(plist));
    cx_assert(cpl_propertylist_get_size(plist) == 0);

    cpl_propertylist_delete(plist);

    check_nomsg(  cpl_error_get_code()   );


    /*
     * Test 10: Create a property list from an input (FITS) file. Verify the
     *          loaded data.
     */

    /* Create a sample FITS header and save it to a file */


    header = cpl_propertylist_new();
 
    check_nomsg(  cpl_error_get_code()   );
    for (i = 0; (cxsize)i < sizeof hdr / sizeof(struct fcard); i++) {
      cpl_msg_info(cpl_func,"iter=%d",(int)i);
        cpl_msg_info(cpl_func,"key=%s",hdr[i].key);
        cpl_msg_info(cpl_func,"com=%s",hdr[i].com);
         cpl_msg_info(cpl_func,"typ=%d",hdr[i].type);
 

     switch (hdr[i].type) {
        case CPL_TYPE_CHAR:
	  cpl_propertylist_append_char(header,hdr[i].key,atoi(hdr[i].val));
          p=cpl_propertylist_get_property(header,hdr[i].key);
	  cpl_propertylist_set_comment(header,hdr[i].key,hdr[i].com);
          cpl_msg_info(cpl_func,"val=%d",atoi(hdr[i].val));
 
           break;

        case CPL_TYPE_BOOL:
	  cpl_propertylist_append_bool(header,hdr[i].key,atoi(hdr[i].val));
          p=cpl_propertylist_get_property(header,hdr[i].key);
	  cpl_propertylist_set_comment(header,hdr[i].key,hdr[i].com);
          cpl_msg_info(cpl_func,"val=%d",atoi(hdr[i].val));
 
            break;

        case CPL_TYPE_INT:
	  cpl_propertylist_append_int(header,hdr[i].key,atoi(hdr[i].val));
          p=cpl_propertylist_get_property(header,hdr[i].key);
	  cpl_propertylist_set_comment(header,hdr[i].key,hdr[i].com);
          cpl_msg_info(cpl_func,"val=%d",atoi(hdr[i].val));
 
            break;

        case CPL_TYPE_LONG:
	  cpl_propertylist_append_long(header,hdr[i].key,atol(hdr[i].val));
          p=cpl_propertylist_get_property(header,hdr[i].key);
	  cpl_propertylist_set_comment(header,hdr[i].key,hdr[i].com);
          cpl_msg_info(cpl_func,"val=%ld",atol(hdr[i].val));
 
            break;

        case CPL_TYPE_FLOAT:
	  cpl_propertylist_append_long(header,hdr[i].key,atof(hdr[i].val));
          p=cpl_propertylist_get_property(header,hdr[i].key);
	  cpl_propertylist_set_comment(header,hdr[i].key,hdr[i].com);
          cpl_msg_info(cpl_func,"val=%f",atof(hdr[i].val));
 
            break;

        case CPL_TYPE_DOUBLE:
	  cpl_propertylist_append_double(header,hdr[i].key,atof(hdr[i].val));
          p=cpl_propertylist_get_property(header,hdr[i].key);
	  cpl_propertylist_set_comment(header,hdr[i].key,hdr[i].com);
          cpl_msg_info(cpl_func,"val=%f",atof(hdr[i].val));

             break;

        case CPL_TYPE_STRING:
	  if(strcmp(hdr[i].key,"END") != 0) {
	  cpl_propertylist_append_string(header,hdr[i].key,hdr[i].val);
          p=cpl_propertylist_get_property(header,hdr[i].key);
	  cpl_propertylist_set_comment(header,hdr[i].key,hdr[i].com);
          cpl_msg_info(cpl_func,"val=%s",hdr[i].val);
	  }
 
           break;

        default:
            /* This point should never be reached */
            cx_log("uves_propertylist-test", CX_LOG_LEVEL_ERROR, "file %s: "
                   "line %d: Invalid value type encountered", __FILE__,
                   __LINE__);
            break;
        }

    }
    check_nomsg(  cpl_error_get_code()   );

 
    file = fopen("cpltest1.fits", "w");
    cpl_propertylist_save(header,"cpltest1.fits",CPL_IO_CREATE);
 

    ima=cpl_image_new(2148,2340,CPL_TYPE_FLOAT);
    check_nomsg(  cpl_error_get_code()   );
    cpl_image_save(ima,"cpltest1.fits",CPL_BPP_16_SIGNED,header,CPL_IO_DEFAULT);

    cpl_image_delete(ima);
    fclose(file);


    /* Load the 1st FITS header into a property list */
    cpl_propertylist_delete(plist);
    plist = cpl_propertylist_load("cpltest1.fits", 0);



    cx_assert(plist != NULL);

 
    cx_assert(my_uves_propertylist_contains(plist, "END") == 0);

 
    cpl_msg_info(cpl_func,"size plist=%" CPL_SIZE_FORMAT "",cpl_propertylist_get_size(plist));
    cpl_msg_info(cpl_func,"size hdr=%ld",sizeof hdr);
    cpl_msg_info(cpl_func,"size fcard=%ld",sizeof(struct fcard));

    check_nomsg(  cpl_error_get_code()   );
    //cx_assert(cpl_propertylist_get_size(plist) ==
    //          (sizeof hdr / sizeof(struct fcard) - 1));
    /*
    for (i = 0; i < cpl_propertylist_get_size(plist); i++) {
        const cxchar *s = hdr[i].key;
        cpl_property *p = cpl_propertylist_get(plist, i);

       
	// Strip HIERARCH from the keyword if it is present. HIERARCH
        // is not carried over to the property name.
         
        cpl_msg_info(cpl_func,"key=%s",hdr[i].key);
        cpl_msg_info(cpl_func,"com=%s",hdr[i].com);
        cpl_msg_info(cpl_func,"typ=%ld",hdr[i].type);

        cpl_msg_info(cpl_func,"p name=%s",cpl_property_get_name(p));
        cpl_msg_info(cpl_func,"p comm=%s",cpl_property_get_comment(p));

        if(strcmp(cpl_property_get_name(p),"COMMENT") == 0) {
	  i++;
        }
        if (strstr(hdr[i].key, "HIERARCH"))
            s = hdr[i].key + strlen("HIERARCH") + 1;

        cx_assert(!strcmp(cpl_property_get_name(p), s));
        cx_assert(hdr[i].com == NULL ||
                  !strcmp(cpl_property_get_comment(p), hdr[i].com));
        cx_assert(cpl_property_get_type(p) == hdr[i].type);

        switch (hdr[i].type) {
        case CPL_TYPE_BOOL:
            cx_assert(cpl_property_get_bool(p) ==
                      (*hdr[i].val == 'T' ? 1 : 0));
            break;

        case CPL_TYPE_INT:
	  cpl_msg_info(cpl_func,"prop name=%s",cpl_property_get_name(p));
	  cpl_msg_info(cpl_func,"prop value=%d",cpl_property_get_int(p));
	  cpl_msg_info(cpl_func,"check value=%d",atoi(hdr[i].val));

            cx_assert(cpl_property_get_int(p) == atoi(hdr[i].val));
            break;

        case CPL_TYPE_DOUBLE:
            dval[0] = cpl_property_get_double(p);
            dval[1] = atof(hdr[i].val);
            cx_assert(!memcmp(&dval[0], &dval[1], sizeof(double)));
            break;

        case CPL_TYPE_STRING:
            cx_assert(!strcmp(cpl_property_get_string(p),
                              qfits_pretty_string(hdr[i].val)));
            break;

        default:
            cx_log("cpl_propertylist-test", CX_LOG_LEVEL_ERROR, "file %s: "
                   "line %d: Invalid value type encountered", __FILE__,
                   __LINE__);
            break;
	}
    }
    */
    check_nomsg(  cpl_error_get_code()   );

    /*
     * Test 11: Convert the qfits FITS header back into a property list and
     *          verify that the original property list and the one created
     *          from the FITS header are identical.
     */

    /* AMO: Suppressed unit test as cpl_propertylist_from_fitsfile is a CPL
            internal function that should not be accessed.
            Still leave the code.

    fitsfile* fits_file=NULL; 
    cxint status = 0;


    fits_open_diskfile(&fits_file,(cxchar*)"cpltest1.fits", READONLY, &status);
    _plist = cpl_propertylist_from_fitsfile(fits_file) ;
    cx_assert(_plist != NULL);
    cx_assert(cpl_propertylist_get_size(plist) ==
              cpl_propertylist_get_size(_plist));


 
    for (i = 0; i < cpl_propertylist_get_size(plist); i++) {
        cpl_property *p = cpl_propertylist_get(plist, i);
        cpl_property *_p = cpl_propertylist_get(_plist, i);

        cx_assert(strcmp(cpl_property_get_name(p),
                         cpl_property_get_name(_p)) == 0);
        cx_assert(strcmp(cpl_property_get_comment(p),
                         cpl_property_get_comment(_p)) == 0);
        cx_assert(cpl_property_get_type(p) == cpl_property_get_type(_p));

        switch (cpl_property_get_type(p)) {
        case CPL_TYPE_BOOL:
            cx_assert(cpl_property_get_bool(p) == cpl_property_get_bool(_p));
            break;

        case CPL_TYPE_INT:
            cx_assert(cpl_property_get_int(p) == cpl_property_get_int(_p));
            break;

        case CPL_TYPE_DOUBLE:
            cx_assert(cpl_property_get_double(p) ==
                      cpl_property_get_double(_p));
            break;

        case CPL_TYPE_STRING:
            cx_assert(strcmp(cpl_property_get_string(p),
                             cpl_property_get_string(_p)) == 0);
            break;

        default:
            cx_log("cpl_propertylist-test", CX_LOG_LEVEL_ERROR,
                   "file %s: line %d: Invalid value type encountered",
                   __FILE__, __LINE__);
            break;
        }
    }

    fits_close_file(fits_file, &status);
    cpl_propertylist_delete(_plist);

    check_nomsg(  cpl_error_get_code()   );

    */


    /*
     * Test 12: Create a qfits header from the property list and verify
     *          the header data. Note that cpl_propertylist_to_fits establishes
     *          the DICB sorting order.
     */
    /*
    cx_deque_compare _compare = (cx_deque_compare)compare;
    cpl_propertylist_sort(header,_compare);

    fits_open_diskfile(&fits_file,(cxchar*)"cpltest1.fits", READONLY, &status);
    cpl_propertylist_save(header,"cpltest1.fits",CPL_IO_CREATE);
    fits_close_file(fits_file, &status);


    _header = cpl_propertylist_to_fits(plist);
    cx_assert(_header != NULL);

    file = fopen("cpltest2.fits", "w");
    qfits_header_dump(_header, file);
    fclose(file);


    for (i = 0; i < header->n; i++) {
        cxchar key[FITS_LINESZ + 1];
        cxchar val[FITS_LINESZ + 1];
        cxchar com[FITS_LINESZ + 1];

        cxchar _key[FITS_LINESZ + 1];
        cxchar _val[FITS_LINESZ + 1];
        cxchar _com[FITS_LINESZ + 1];


        qfits_header_getitem(header, i, key, val, com, NULL);
        cx_assert(qfits_header_getitem(_header, i, _key, _val,
                                       _com, NULL) == 0);

        cx_assert(!strcmp(key, _key));
        cx_assert(_com == NULL || !strcmp(com, _com));

        switch (qfits_get_type(val)) {
        case QFITS_FLOAT:
            fval[0] = atof(val);
            fval[1] = atof(_val);

            cx_assert(fabs(fval[0] - fval[1]) < FLT_EPS);
            break;

        default:
            cx_assert(strlen(val) == 0 ||
                      !strcmp(qfits_pretty_string(val),
                              qfits_pretty_string(_val)));
            break;
        }

    }

    qfits_header_destroy(header);
    qfits_header_destroy(_header);
    */


 

    /*
     * Test 13: Copy all propertys matching a given pattern from one
     *          property list to another.
     */

     _plist = cpl_propertylist_new();



    cpl_propertylist_copy_property_regexp(_plist, plist, "^ESO .*", 0);




    cx_assert(cpl_propertylist_get_size(_plist) == 6);
    cx_assert(my_uves_propertylist_contains(_plist, "ESO OBS DID") != 0);
    cx_assert(my_uves_propertylist_contains(_plist, "ESO OBS OBSERVER") != 0);
    cx_assert(my_uves_propertylist_contains(_plist, "ESO OBS PI-COI NAME") != 0);
    cx_assert(my_uves_propertylist_contains(_plist, "ESO INS GRAT NAME") != 0);
    cx_assert(my_uves_propertylist_contains(_plist, "ESO PRO CATG") != 0);
    cx_assert(my_uves_propertylist_contains(_plist, "ESO TPL NEXP") != 0);
 


    cpl_propertylist_empty(_plist);
    cx_assert(cpl_propertylist_is_empty(_plist) != 0);

    cpl_propertylist_copy_property_regexp(_plist, plist, "^ESO .*", 1);
    cx_assert(cpl_propertylist_get_size(_plist) ==
              (cpl_propertylist_get_size(plist) - 6));

    check_nomsg(  cpl_error_get_code()   );



    /*
     * Test 14: Erase all properties matching the given pattern from the
     *          property list.
     */

    cpl_propertylist_empty(_plist);
    cx_assert(cpl_propertylist_is_empty(_plist) != 0);

    cpl_propertylist_copy_property_regexp(_plist, plist, "^ESO .*", 0);
    cx_assert(cpl_propertylist_get_size(_plist) == 6);

    cpl_propertylist_erase_regexp(_plist, "^ESO OBS .*", 0);
    cx_assert(cpl_propertylist_get_size(_plist) == 3);

    cpl_propertylist_erase_regexp(_plist, "ESO TPL NEXP", 0);
    cx_assert(cpl_propertylist_get_size(_plist) == 2);

    cpl_propertylist_delete(_plist);
    cpl_propertylist_delete(plist);
    check_nomsg(  cpl_error_get_code()   );



    /*
     * Test 15: Create a property list from a file. Only properties matching
     *          the given pattern are loaded.
     */

    plist = NULL;

    plist = cpl_propertylist_load_regexp("cpltest1.fits", 0,
                                         "^ESO .*", 0);
    cx_assert(plist != NULL);
    cx_assert(cpl_propertylist_is_empty(plist) == 0);
    cx_assert(cpl_propertylist_get_size(plist) == 6);
    cx_assert(my_uves_propertylist_contains(plist, "ESO OBS DID") != 0);
    cx_assert(my_uves_propertylist_contains(plist, "ESO OBS OBSERVER") != 0);
    cx_assert(my_uves_propertylist_contains(plist, "ESO OBS PI-COI NAME") != 0);
    cx_assert(my_uves_propertylist_contains(plist, "ESO INS GRAT NAME") != 0);
    cx_assert(my_uves_propertylist_contains(plist, "ESO PRO CATG") != 0);
    cx_assert(my_uves_propertylist_contains(plist, "ESO TPL NEXP") != 0);

    cpl_propertylist_delete(plist);
    check_nomsg(  cpl_error_get_code()   );




    /*
     * Test 16: Append a property list to another.
     */

    plist = cpl_propertylist_new();
    _plist = cpl_propertylist_new();

    cpl_propertylist_append_char(plist, keys[0], 'a');
    cpl_propertylist_set_comment(plist, keys[0], comments[0]);

    cpl_propertylist_append_bool(plist, keys[1], 1);
    cpl_propertylist_set_comment(plist, keys[1], comments[1]);

    cpl_propertylist_append_int(plist, keys[2], -1);
    cpl_propertylist_set_comment(plist, keys[2], comments[2]);

    cpl_propertylist_append_long(plist, keys[3], 32768);
    cpl_propertylist_set_comment(plist, keys[3], comments[3]);

    cpl_propertylist_append_float(_plist, keys[4], fval[0]);
    cpl_propertylist_set_comment(_plist, keys[4], comments[4]);

    cpl_propertylist_append_double(_plist, keys[5], dval[0]);
    cpl_propertylist_set_comment(_plist, keys[5], comments[5]);

    cpl_propertylist_append_string(_plist, keys[6], comments[6]);
    cpl_propertylist_set_comment(_plist, keys[6], comments[6]);

    cx_assert(!cpl_propertylist_is_empty(plist));
    cx_assert(cpl_propertylist_get_size(plist) == 4);

    cx_assert(!cpl_propertylist_is_empty(_plist));
    cx_assert(cpl_propertylist_get_size(_plist) == 3);

    cpl_propertylist_append(plist, _plist);

    cx_assert(!cpl_propertylist_is_empty(plist));
    cx_assert(cpl_propertylist_get_size(plist) == 7);

    cx_assert(!cpl_propertylist_is_empty(_plist));
    cx_assert(cpl_propertylist_get_size(_plist) == 3);

    for (i = 0; i < cpl_propertylist_get_size(plist); i++) {
        cpl_property *prop = cpl_propertylist_get(plist, i);

        cx_assert(!strcmp(cpl_property_get_name(prop), keys[i]));
        cx_assert(!strcmp(cpl_property_get_comment(prop), comments[i]));
        cx_assert(cpl_property_get_type(prop) == types[i]);

        cx_assert(my_uves_propertylist_contains(plist, keys[i]));
        cx_assert(!strcmp(cpl_propertylist_get_comment(plist, keys[i]),
                          comments[i]));
        cx_assert(cpl_propertylist_get_type(plist, keys[i]) == types[i]);
    }

    check_nomsg(  cpl_error_get_code()   );

    cpl_propertylist_delete(_plist);
    cpl_propertylist_delete(plist);



    /*
     * Test 17: Create a FITS header using a list containing a property with
     *          a name of length 80 characters (the length of a FITS card)
     */

    /*
    cpl_propertylist_empty(plist);

    cpl_propertylist_append_string(plist, longname, comments[6]);

    qfits_header_destroy(cpl_propertylist_to_fits(plist));


    cpl_propertylist_delete(_plist);
    _plist = NULL;

    cpl_propertylist_delete(plist);
    plist = NULL;

    cx_assert( cpl_error_get_code() == CPL_ERROR_UNSPECIFIED );
    cpl_error_reset();
    */
    /*
     * All tests succeeded
     */
 cleanup:

   return 0;

}

int main(void)
{

  cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_WARNING);
    //cpl_msg_set_level(CPL_MSG_DEBUG);
    test_main();

     return cpl_test_end(0);
}
