#ifndef GRASS_RASTER3D_H
#define GRASS_RASTER3D_H

#include <grass/gis.h>
#include <grass/raster.h>

/* Second version of the raster 3D map layout. Old maps without version
 information are defined as version == 1 when reading the header. */
#define RASTER3D_MAP_VERSION            2

#define RASTER3D_TILE_SAME_AS_FILE      2

#define RASTER3D_NO_COMPRESSION         0
#define RASTER3D_COMPRESSION            1

#define RASTER3D_MAX_PRECISION          -1

#define RASTER3D_NO_CACHE               0
#define RASTER3D_USE_CACHE_DEFAULT      -1
#define RASTER3D_USE_CACHE_X            -2
#define RASTER3D_USE_CACHE_Y            -3
#define RASTER3D_USE_CACHE_Z            -4
#define RASTER3D_USE_CACHE_XY           -5
#define RASTER3D_USE_CACHE_XZ           -6
#define RASTER3D_USE_CACHE_YZ           -7
#define RASTER3D_USE_CACHE_XYZ          -8

/* NULL pointer, now (int)0 because issues with ctypesgen */
#define RASTER3D_DEFAULT_WINDOW         0

#define RASTER3D_DIRECTORY              "grid3"
#define RASTER3D_CELL_ELEMENT           "cell"
#define RASTER3D_CATS_ELEMENT           "cats"
#define RASTER3D_RANGE_ELEMENT          "range"
#define RASTER3D_HEADER_ELEMENT         "cellhd"
#define RASTER3D_HISTORY_ELEMENT        "hist"
#define RASTER3D_COLOR_ELEMENT          "color"
#define RASTER3D_COLOR2_DIRECTORY       "colr2"
#define RASTER3D_MASK_MAP               "RASTER3D_MASK"
#define RASTER3D_WINDOW_ELEMENT         "WIND3"
#define RASTER3D_DEFAULT_WINDOW_ELEMENT "DEFAULT_WIND3"
#define RASTER3D_WINDOW_DATABASE        "windows3d"
#define RASTER3D_PERMANENT_MAPSET       "PERMANENT"

/*---------------------------------------------------------------------------*/

typedef struct {

    double north, south;
    double east, west;
    double top, bottom;

    /* dimension of data in "cells"; rows == #x; cols == #y; depths == #z */
    int rows, cols, depths;

    double ns_res, ew_res, tb_res;

    int proj; /* Projection (see gis.h) */
    int zone; /* Projection zone (see gis.h) */

} RASTER3D_Region;

/*---------------------------------------------------------------------------*/

struct RASTER3D_Map;

typedef void resample_fn(struct RASTER3D_Map *, int, int, int, void *, int);

/*---------------------------------------------------------------------------*/

typedef struct RASTER3D_Map {
    int version; /* The version of the raster 3D map layout */

    char *fileName;
    char *tempName;
    char *mapset;

    /* operation performed on map */
    int operation; /* RASTER3D_WRITE_DATA or RASTER3D_READ_DATA */

    /* region */
    RASTER3D_Region region;

    /* window for map */
    RASTER3D_Region window;

    /* resmapling function used for map. default is nearest neighbor */
    resample_fn *resampleFun;

    /* units */
    char *unit;        /* space (U_METER, ...) */
    int vertical_unit; /* space or time (U_METER, ..., U_YEAR, ...) */

    /* dimension of a single tile in "cells" */
    int tileX, tileY, tileZ;

    /* # of tiles in x, y, and z direction */
    int nx, ny, nz;

    /* data file specific information */

    /* file descriptor */
    int data_fd; /* file descriptor */

    /* type in which data is stored on file */
    int type; /* DCELL_TYPE or FCELL_TYPE */

    /* data concerning the compression */
    int precision;   /* RASTER3D_MAX_PRECISION or, 0 .. 23 for float,
                        0 .. 52 for double */
    int compression; /* RASTER3D_NO_COMPRESSION or RASTER3D_COMPRESSION */
    int useLzw;      /* RASTER3D_USE_LZW or RASTER3D_NO_LZW !!! only kept for
                        backward compatibility */
    int useRle;      /* RASTER3D_USE_RLE or RASTER3D_NO_RLE !!! only kept for
                        backward compatibility */
    int useXdr;      /* RASTER3D_USE_XDR or RASTER3D_NO_XDR !!! only kept for
                        backward compatibility */

    /* pointer to first tile in file */
    int offset;

    /* pointer to the first index entry in file */
    long indexOffset;

    /* sizeof (long) of the system on which the file is/was written */
    int indexLongNbytes;

    /* max # bytes used in the representation of indices; this is equal to */
    /* # bytes used in the representation of "indexOffset" */
    int indexNbytesUsed;

    /* pointer to the last entry in the file */
    int fileEndPtr;

    /* indicates if index is stored in file; used for RASTER3D_READ_DATA only */
    int hasIndex; /* RASTER3D_HAS_INDEX or RASTER3D_NO_INDEX */

    /* information concerning internal storage of data */

    /* index specific information */
    /* index[i] == the offset of tile "i" in the data file */
    long *index;

    /* tileLength[i] == # bytes used to store tile "i" */
    int *tileLength;

    /* tile specific information */

    /* type in which data is stored in memory */
    int typeIntern; /* DCELL_TYPE or FCELL_TYPE */

    /* in non-cache mode the "data" array is used to store one tile */
    char *data;

    /* index of tile currently stored in "data"; -1 if none */
    int currentIndex;

    /* cache related variables */

    int useCache;        /* 1 if cache is used */
    void *cache;         /* pointer to cache structure */
    int cacheFD;         /* file descriptor of cache file -- write mode only */
    char *cacheFileName; /* filename of cache file -- write mode only */
    long cachePosLast;   /* position of last entry in cache file -- write */
    /* mode only */

    /* range info */
    struct FPRange range;

    /* some constants stored for efficiency */

    /* number of bytes required to store a single value of "type" */
    int numLengthExtern;

    /* number of bytes required to store a single value of "typeIntern" */
    int numLengthIntern;

    /* see header.c for details */
    int clipX, clipY, clipZ;
    int tileXY, tileSize;
    int nxy, nTiles;

    /* mask related information */

    int useMask; /* 1 if mask is used; 0 otherwise */

} RASTER3D_Map;

/*---------------------------------------------------------------------------*/

typedef struct {

    char *elts;  /* ptr to array of elts */
    int nofElts; /* size of "elts" */
    int eltSize; /* size of elt in "elts" */

    int *names; /* name[i] is the name of elts[i] */

    char *locks;     /* lock[i] == 1 iff elts[i] is locked
                        lock[i] == 0 iff elts[i] is unlocked but active
                        lock[i] == 2 iff elts[i] doesn't contain valid data */
    int autoLock;    /* 1 if auto locking is turned on */
    int nofUnlocked; /* nof tiles which are unlocked */
    int minUnlocked; /* min nof elts which have to remain unlocked. min = 1 */

    int *next, *prev; /* prev/next pointers for fifo */
    int first, last;  /* index (into next) of first and last elt in fifo */
    /* first == -1 iff fifo is empty */

    int (*eltRemoveFun)(int, const void *,
                        void *); /* callback activated if the contents of an elt
                                    needs to be removed */
    void *eltRemoveFunData;      /* pointer to user data passed along with
                                    eltRemoveFun */
    int (*eltLoadFun)(
        int, void *,
        void *);          /* callback activated to load contents of an elt */
    void *eltLoadFunData; /* pointer to user data passed along with
                             eltLoadFun */

    void *hash; /* ptr to hashTable used to relate external names to
                   internal indices (elts) */

} RASTER3D_cache;

/*---------------------------------------------------------------------------*/

typedef struct {

    int nofNames;
    int *index;
    char *active;
    int lastName;
    int lastIndex;
    int lastIndexActive;

} Rast3d_cache_hash;

/*---------------------------------------------------------------------------*/

/*Structures */
typedef struct _d_interval {
    double low, high;
    int inf;
    struct _d_interval *next;
} d_Interval;

typedef struct _d_mask {
    d_Interval *list;
} d_Mask;

/*---------------------------------------------------------------------------*/

typedef int write_fn(int, const void *, void *);
typedef int read_fn(int, void *, void *);

/*---------------------------------------------------------------------------*/
/* for storing values of 3D raster block in a flat array */
typedef struct {
    DCELL *array;
    int sx;
    int sy;
    int sz;

} RASTER3D_Array_double;

#define RASTER3D_ARRAY_ACCESS(arr, x, y, z) \
    ((arr)->array[(arr)->sx * (arr)->sy * (z) + (arr)->sx * (y) + (x)])

/*============================== Prototypes ================================*/

#include <grass/defs/raster3d.h>

#endif /* #ifndef GRASS_RASTER3D_H */
