#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <math.h> /* for fabs */
#include <float.h> /* for FLT_EPSILON and DBL_EPSILON */

#include "rt_api.h"
#include "check.h"

static rt_band addBand(rt_context ctx, rt_raster raster, rt_pixtype pixtype);
static void deepRelease(rt_context ctx, rt_raster raster);
static void testBand1BB(rt_context ctx, rt_band band);

static rt_band
addBand(rt_context ctx, rt_raster raster, rt_pixtype pixtype)
{
    void* mem;
    int32_t bandNum;
    size_t datasize;
    uint16_t width = rt_raster_get_width(ctx, raster);
    uint16_t height = rt_raster_get_height(ctx, raster);

    datasize = rt_pixtype_size(ctx, pixtype)*width*height;
    mem = malloc(datasize);

    rt_band band = rt_band_new_inline(ctx, width, height,
                                      pixtype, 0, mem);
    assert(band);
    bandNum = rt_raster_add_band(ctx, raster, band);
    assert(bandNum>=0);
    return band;
}

static void
deepRelease(rt_context ctx, rt_raster raster)
{
    uint16_t i, nbands=rt_raster_get_num_bands(ctx, raster);
    for (i=0; i<nbands; ++i)
    {
        rt_band band = rt_raster_get_band(ctx, raster, i);
        void* mem = rt_band_get_data(ctx, band);
        if ( mem ) free(mem);
        rt_band_destroy(ctx, band);
    }
    rt_raster_destroy(ctx, raster);
}

static void testBand1BB(rt_context ctx, rt_band band)
{
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    //printf("1BB nodata is %g\n", rt_band_get_nodata(ctx, band));
    CHECK_EQUALS(rt_band_get_nodata(ctx, band), 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    CHECK(!failure);
    //printf("1BB nodata is %g\n", rt_band_get_nodata(ctx, band));
    CHECK_EQUALS(rt_band_get_nodata(ctx, band), 0);

    failure = rt_band_set_nodata(ctx, band, 2);
    CHECK(failure); /* out of range value */

    failure = rt_band_set_nodata(ctx, band, 3);
    CHECK(failure); /* out of range value */

    failure = rt_band_set_pixel(ctx, band, 0, 0, 2);
    CHECK(failure); /* out of range value */

    failure = rt_band_set_pixel(ctx, band, 0, 0, 3);
    CHECK(failure); /* out of range value */

    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 1);
    CHECK(!failure);
    CHECK_EQUALS(rt_band_get_pixel(ctx, band, x, y), 1);

    failure = rt_band_set_pixel(ctx, band, x, y, 0);
    CHECK(!failure);
    CHECK_EQUALS(rt_band_get_pixel(ctx, band, x, y), 0);

            }
        }
    }

}

static void testBand2BUI(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);
    CHECK(!failure);

    failure = rt_band_set_nodata(ctx, band, 0);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0);
    CHECK(!failure);

    failure = rt_band_set_nodata(ctx, band, 2);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 2);
    CHECK(!failure);

    failure = rt_band_set_nodata(ctx, band, 3);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 3);
    CHECK(!failure);

    failure = rt_band_set_nodata(ctx, band, 4); /* invalid: out of range */
    CHECK(failure);

    failure = rt_band_set_nodata(ctx, band, 5); /* invalid: out of range */
    CHECK(failure);

    failure = rt_band_set_pixel(ctx, band, 0, 0, 4); /* out of range */
    CHECK(failure);

    failure = rt_band_set_pixel(ctx, band, 0, 0, 5); /* out of range */
    CHECK(failure);


    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 1);
    val =  rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 1);
    CHECK(!failure);

    failure = rt_band_set_pixel(ctx, band, x, y, 2);
    val =  rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 2);
    CHECK(!failure);

    failure = rt_band_set_pixel(ctx, band, x, y, 3);
    val =  rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 3);
    CHECK(!failure);

            }
        }
    }

}

static void testBand4BUI(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    val = rt_band_get_nodata(ctx, band);
    CHECK(!failure);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_nodata(ctx, band, 2);
    val = rt_band_get_nodata(ctx, band);
    CHECK(!failure);
    CHECK_EQUALS(val, 2);

    failure = rt_band_set_nodata(ctx, band, 4); 
    val = rt_band_get_nodata(ctx, band);
    CHECK(!failure);
    CHECK_EQUALS(val, 4);

    failure = rt_band_set_nodata(ctx, band, 8); 
    val = rt_band_get_nodata(ctx, band);
    CHECK(!failure);
    CHECK_EQUALS(val, 8);

    failure = rt_band_set_nodata(ctx, band, 15); 
    val = rt_band_get_nodata(ctx, band);
    CHECK(!failure);
    CHECK_EQUALS(val, 15);

    failure = rt_band_set_nodata(ctx, band, 16);  /* out of value range */
    CHECK(failure);

    failure = rt_band_set_nodata(ctx, band, 17);  /* out of value range */
    CHECK(failure);

    failure = rt_band_set_pixel(ctx, band, 0, 0, 35); /* out of value range */
    CHECK(failure);


    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 1);
    CHECK(!failure);
    val =  rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_pixel(ctx, band, x, y, 3);
    CHECK(!failure);
    val =  rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 3);

    failure = rt_band_set_pixel(ctx, band, x, y, 7);
    CHECK(!failure);
    val =  rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 7);

    failure = rt_band_set_pixel(ctx, band, x, y, 15);
    CHECK(!failure);
    val =  rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 15);

            }
        }
    }

}

static void testBand8BUI(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_nodata(ctx, band, 2);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 2);

    failure = rt_band_set_nodata(ctx, band, 4); 
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 4);

    failure = rt_band_set_nodata(ctx, band, 8); 
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 8);

    failure = rt_band_set_nodata(ctx, band, 15); 
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 15);

    failure = rt_band_set_nodata(ctx, band, 31);  
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 31);

    failure = rt_band_set_nodata(ctx, band, 255);  
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 255);

    failure = rt_band_set_nodata(ctx, band, 256); /* out of value range */
    CHECK(failure);

    failure = rt_band_set_pixel(ctx, band, 0, 0, 256); /* out of value range */
    CHECK(failure);

    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 31);  
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 31);

    failure = rt_band_set_pixel(ctx, band, x, y, 255);  
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 255);

    failure = rt_band_set_pixel(ctx, band, x, y, 1);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 1);

            }
        }
    }
}

static void testBand8BSI(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_nodata(ctx, band, 2);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 2);

    failure = rt_band_set_nodata(ctx, band, 4); 
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 4);

    failure = rt_band_set_nodata(ctx, band, 8); 
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 8);

    failure = rt_band_set_nodata(ctx, band, 15); 
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 15);

    failure = rt_band_set_nodata(ctx, band, 31);  
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 31);

    failure = rt_band_set_nodata(ctx, band, -127);  
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, -127);

    failure = rt_band_set_nodata(ctx, band, 127);  
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 127);

    /* out of range (-127..127) */
    failure = rt_band_set_nodata(ctx, band, -129);  
    CHECK(failure);

    /* out of range (-127..127) */
    failure = rt_band_set_nodata(ctx, band, 129);  
    CHECK(failure);

    /* out of range (-127..127) */
    failure = rt_band_set_pixel(ctx, band, 0, 0, -129);  
    CHECK(failure);

    /* out of range (-127..127) */
    failure = rt_band_set_pixel(ctx, band, 0, 0, 129);  
    CHECK(failure);


    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 31);  
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 31);

    failure = rt_band_set_pixel(ctx, band, x, y, 1);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_pixel(ctx, band, x, y, -127);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, -127);

    failure = rt_band_set_pixel(ctx, band, x, y, 127);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 127);

            }
        }
    }
}

static void testBand16BUI(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_nodata(ctx, band, 31);  
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 31);

    failure = rt_band_set_nodata(ctx, band, 255);  
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 255);

    failure = rt_band_set_nodata(ctx, band, 65535);   
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    //printf("set 65535 on %s band gets %g back\n", pixtypeName, val);
    CHECK_EQUALS(val, 65535);

    failure = rt_band_set_nodata(ctx, band, 65536); /* out of range */
    CHECK(failure);

    /* out of value range */
    failure = rt_band_set_pixel(ctx, band, 0, 0, 65536);
    CHECK(failure);

    /* out of dimensions range */
    failure = rt_band_set_pixel(ctx, band, rt_band_get_width(ctx, band), 0, 0);
    CHECK(failure);

    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 255);  
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 255);

    failure = rt_band_set_pixel(ctx, band, x, y, 65535);   
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 65535);

            }
        }
    }
}

static void testBand16BSI(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_nodata(ctx, band, 31);  
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 31);

    failure = rt_band_set_nodata(ctx, band, 255);  
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 255);

    failure = rt_band_set_nodata(ctx, band, -32767);   
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    //printf("set 65535 on %s band gets %g back\n", pixtypeName, val);
    CHECK_EQUALS(val, -32767);

    failure = rt_band_set_nodata(ctx, band, 32767);   
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    //printf("set 65535 on %s band gets %g back\n", pixtypeName, val);
    CHECK_EQUALS(val, 32767);

    /* out of range (-32767..32767) */
    failure = rt_band_set_nodata(ctx, band, -32769);
    CHECK(failure);

    /* out of range (-32767..32767) */
    failure = rt_band_set_nodata(ctx, band, 32769);
    CHECK(failure);

    /* out of range (-32767..32767) */
    failure = rt_band_set_pixel(ctx, band, 0, 0, -32769); 
    CHECK(failure);

    /* out of range (-32767..32767) */
    failure = rt_band_set_pixel(ctx, band, 0, 0, 32769); 
    CHECK(failure);

    /* out of dimensions range */
    failure = rt_band_set_pixel(ctx, band, rt_band_get_width(ctx, band), 0, 0); 
    CHECK(failure);

    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 255);  
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 255);

    failure = rt_band_set_pixel(ctx, band, x, y, -32767);   
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, -32767);

    failure = rt_band_set_pixel(ctx, band, x, y, 32767);   
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 32767);

            }
        }
    }
}

static void testBand32BUI(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_nodata(ctx, band, 65535);   
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 65535);

    failure = rt_band_set_nodata(ctx, band, 4294967295); 
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 4294967295);

    /* out of range */
    failure = rt_band_set_nodata(ctx, band, 4294967296);
    CHECK(failure);

    /* out of value range */
    failure = rt_band_set_pixel(ctx, band, 0, 0, 4294967296);
    CHECK(failure);

    /* out of dimensions range */
    failure = rt_band_set_pixel(ctx, band, rt_band_get_width(ctx, band),
        0, 4294967296);
    CHECK(failure);

    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 1);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_pixel(ctx, band, x, y, 0);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_pixel(ctx, band, x, y, 65535);   
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 65535);

    failure = rt_band_set_pixel(ctx, band, x, y, 4294967295); 
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 4294967295);

            }
        }
    }
}

static void testBand32BSI(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_nodata(ctx, band, 65535);   
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 65535);

    failure = rt_band_set_nodata(ctx, band, 2147483647);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    /*printf("32BSI pix is %ld\n", (long int)val);*/
    CHECK_EQUALS(val, 2147483647);

    failure = rt_band_set_nodata(ctx, band, 2147483648);
    /* out of range */
    CHECK(failure);

    /* out of value range */
    failure = rt_band_set_pixel(ctx, band, 0, 0, 2147483648);  
    CHECK(failure);

    /* out of dimensions range */
    failure = rt_band_set_pixel(ctx, band, rt_band_get_width(ctx, band), 0, 0);
    CHECK(failure);


    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 1);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_pixel(ctx, band, x, y, 0);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_pixel(ctx, band, x, y, 65535);   
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 65535);

    failure = rt_band_set_pixel(ctx, band, x, y, 2147483647); 
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 2147483647);

            }
        }
    }
}

static void testBand16BF(rt_context ctx, rt_band band)
{
    printf(" 16BF type not implemented yet\n");
}

static void testBand32BF(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_nodata(ctx, band, 65535.5);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    //printf("set 65535.56 on %s band gets %g back\n", pixtypeName, val);
    CHECK_EQUALS_DOUBLE(val, 65535.5);

    failure = rt_band_set_nodata(ctx, band, 0.006); 
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS_DOUBLE(val, 0.006);

    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 1);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_pixel(ctx, band, x, y, 0);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_pixel(ctx, band, x, y, 65535.5);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS_DOUBLE(val, 65535.5);

    failure = rt_band_set_pixel(ctx, band, x, y, 0.006); 
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS_DOUBLE(val, 0.006);

            }
        }
    }
}

static void testBand64BF(rt_context ctx, rt_band band)
{
    double val;
    int failure;

    failure = rt_band_set_nodata(ctx, band, 1);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_nodata(ctx, band, 0);
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_nodata(ctx, band, 65535.56);   
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 65535.56);

    failure = rt_band_set_nodata(ctx, band, 0.006); 
    CHECK(!failure);
    val = rt_band_get_nodata(ctx, band);
    CHECK_EQUALS(val, 0.006);

    {
        int x, y;
        for (x=0; x<rt_band_get_width(ctx, band); ++x)
        {
            for (y=0; y<rt_band_get_height(ctx, band); ++y)
            {
    failure = rt_band_set_pixel(ctx, band, x, y, 1);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 1);

    failure = rt_band_set_pixel(ctx, band, x, y, 0);
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 0);

    failure = rt_band_set_pixel(ctx, band, x, y, 65535.56);   
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 65535.56);

    failure = rt_band_set_pixel(ctx, band, x, y, 0.006); 
    CHECK(!failure);
    val = rt_band_get_pixel(ctx, band, x, y);
    CHECK_EQUALS(val, 0.006);

            }
        }
    }
}

int
main()
{
    /* will use default allocators and message handlers */
    rt_context ctx;
    rt_raster raster;
    rt_band band_1BB, band_2BUI, band_4BUI,
            band_8BSI, band_8BUI, band_16BSI, band_16BUI,
            band_32BSI, band_32BUI, band_16BF, band_32BF,
            band_64BF;

    ctx = rt_context_new(0, 0, 0);
    raster = rt_raster_new(ctx, 256, 256);
    assert(raster); /* or we're out of virtual memory */

    { /* Check scale */
        float scale;
        scale = rt_raster_get_pixel_width(ctx, raster);
        CHECK_EQUALS(scale, 1);
        scale = rt_raster_get_pixel_height(ctx, raster);
        CHECK_EQUALS(scale, 1);
    }

    { /* Check offsets */
        float off;

        off = rt_raster_get_x_offset(ctx, raster);
        CHECK_EQUALS(off, 0.5);

        off = rt_raster_get_y_offset(ctx, raster);
        CHECK_EQUALS(off, 0.5);

        rt_raster_set_offsets(ctx, raster, 30, 70);

        off = rt_raster_get_x_offset(ctx, raster);
        CHECK_EQUALS(off, 30);

        off = rt_raster_get_y_offset(ctx, raster);
        CHECK_EQUALS(off, 70);

        rt_raster_set_offsets(ctx, raster, 0.5, 0.5);
    }

    { /* Check rotation */
        float off;

        off = rt_raster_get_x_rotation(ctx, raster);
        CHECK_EQUALS(off, 0);

        off = rt_raster_get_y_rotation(ctx, raster);
        CHECK_EQUALS(off, 0);

        rt_raster_set_rotations(ctx, raster, 4, 5);

        off = rt_raster_get_x_rotation(ctx, raster);
        CHECK_EQUALS(off, 4);

        off = rt_raster_get_y_rotation(ctx, raster);
        CHECK_EQUALS(off, 5);

        rt_raster_set_rotations(ctx, raster, 0, 0);
    }

    { /* Check SRID */
        int32_t srid;
        srid = rt_raster_get_srid(ctx, raster);
        CHECK_EQUALS(srid, -1);

        rt_raster_set_srid(ctx, raster, 65546);
        srid = rt_raster_get_srid(ctx, raster);
        CHECK_EQUALS(srid, 65546);
    }

    printf("Raster starts with %d bands\n",
        rt_raster_get_num_bands(ctx, raster));

    { /* Check envelopes, based on offset, scale and rotation */
        LWPOLY *envelope;
        POINTARRAY *ring;
        POINT4D pt;

        envelope = rt_raster_get_envelope(ctx, raster);
        CHECK_EQUALS(envelope->SRID, rt_raster_get_srid(ctx, raster));
        CHECK_EQUALS(envelope->nrings, 1);
        ring = envelope->rings[0];
        CHECK(ring);
        CHECK_EQUALS(ring->npoints, 5);

        getPoint4d_p(ring, 0, &pt);
        printf("First point on envelope ring is %g,%g\n", pt.x, pt.y);
        CHECK_EQUALS(pt.x, 0.0);
        CHECK_EQUALS(pt.y, 0.0);

        getPoint4d_p(ring, 1, &pt);
        printf("Second point on envelope ring is %g,%g\n", pt.x, pt.y);
        CHECK_EQUALS(pt.x, 256);
        CHECK_EQUALS(pt.y, 0.0);

        getPoint4d_p(ring, 2, &pt);
        printf("Third point on envelope ring is %g,%g\n", pt.x, pt.y);
        CHECK_EQUALS(pt.x, 256);
        CHECK_EQUALS(pt.y, 256);

        getPoint4d_p(ring, 3, &pt);
        printf("Fourth point on envelope ring is %g,%g\n", pt.x, pt.y);
        CHECK_EQUALS(pt.x, 0);
        CHECK_EQUALS(pt.y, 256);

        getPoint4d_p(ring, 4, &pt);
        printf("Fifth point on envelope ring is %g,%g\n", pt.x, pt.y);
        CHECK_EQUALS(pt.x, 0.0);
        CHECK_EQUALS(pt.y, 0.0);

        lwpoly_free(envelope);
    }

    printf("Testing 1BB band\n");
    band_1BB = addBand(ctx, raster, PT_1BB);
    testBand1BB(ctx, band_1BB);

    printf("Testing 2BB band\n");
    band_2BUI = addBand(ctx, raster, PT_2BUI);
    testBand2BUI(ctx, band_2BUI);

    printf("Testing 4BUI band\n");
    band_4BUI = addBand(ctx, raster, PT_4BUI);
    testBand4BUI(ctx, band_4BUI);

    printf("Testing 8BUI band\n");
    band_8BUI = addBand(ctx, raster, PT_8BUI);
    testBand8BUI(ctx, band_8BUI);

    printf("Testing 8BSI band\n");
    band_8BSI = addBand(ctx, raster, PT_8BSI);
    testBand8BSI(ctx, band_8BSI);

    printf("Testing 16BSI band\n");
    band_16BSI = addBand(ctx, raster, PT_16BSI);
    testBand16BSI(ctx, band_16BSI);

    printf("Testing 16BUI band\n");
    band_16BUI = addBand(ctx, raster, PT_16BUI);
    testBand16BUI(ctx, band_16BUI);

    printf("Testing 32BUI band\n");
    band_32BUI = addBand(ctx, raster, PT_32BUI);
    testBand32BUI(ctx, band_32BUI);

    printf("Testing 32BSI band\n");
    band_32BSI = addBand(ctx, raster, PT_32BSI);
    testBand32BSI(ctx, band_32BSI);

    printf("Testing 16BF band\n");
    band_16BF = addBand(ctx, raster, PT_16BF);
    testBand16BF(ctx, band_16BF);

    printf("Testing 32BF band\n");
    band_32BF = addBand(ctx, raster, PT_32BF);
    testBand32BF(ctx, band_32BF);

    printf("Testing 64BF band\n");
    band_64BF = addBand(ctx, raster, PT_64BF);
    testBand64BF(ctx, band_64BF);

    deepRelease(ctx, raster);
    rt_context_destroy(ctx);

    return EXIT_SUCCESS;
}

/* This is needed by liblwgeom */
void
lwgeom_init_allocators(void)
{
    lwgeom_install_default_allocators();
}
