/* libblx - Magellan BLX topo reader/writer library
 *
 * Copyright (c) 2008, Henrik Johansson <henrik@johome.net>
 *
 * SPDX-License-Identifier: MIT
 */

#ifndef BLX_H_INCLUDED
#define BLX_H_INCLUDED

#include <stdio.h>

#ifdef GDALDRIVER
#include "cpl_conv.h"
#include "cpl_vsi.h"
#endif

/* Constants */
#define BLX_UNDEF -32768
#define BLX_OVERVIEWLEVELS 4

/* Possible values of ctx.endian */
#define BIGENDIAN 1
#define LITTLEENDIAN 0

/* Data types */

typedef short int blxdata;

struct cellindex_s
{
    int offset;
    unsigned int datasize;     /* Uncompressed size */
    unsigned int compdatasize; /* Compressed data size */
};

struct blxcontext_s
{
    int xsize, ysize;
    int cell_xsize, cell_ysize;
    int cell_cols, cell_rows;
    double lon, lat;
    double pixelsize_lon, pixelsize_lat;

    int zscale;
    int maxchunksize;
    int minval, maxval;

    int endian;

    struct cellindex_s *cellindex;

    int debug;

    int fillundef; /* If non-zero, fillundefval will be used instead of -32768
                    for undefined values in non-empty cells when a cell is
                    written */
    int fillundefval;

#ifdef GDALDRIVER
    VSILFILE *fh;
#else
    FILE *fh;
#endif
    int write;
    int open;
};

typedef struct blxcontext_s blxcontext_t;

struct component_s
{
    int n;
    blxdata *lut;
    int dlen;
    blxdata *data;
};

/* Included all functions in the global name space when testing */
#ifdef TEST
#define STATIC
#else
#define STATIC static
#endif

/* Define memory allocation and I/O function macros */
#ifdef GDALDRIVER
#define BLXfopen VSIFOpenL
#define BLXfclose VSIFCloseL
#define BLXfread VSIFReadL
#define BLXfwrite VSIFWriteL
#define BLXfseek VSIFSeekL
#define BLXftell VSIFTellL
#define BLXmalloc VSIMalloc
#define BLXfree CPLFree
#define BLXdebug0(text) CPLDebug("BLX", text)
#define BLXdebug1(text, arg1) CPLDebug("BLX", text, arg1)
#define BLXdebug2(text, arg1, arg2) CPLDebug("BLX", text, arg1, arg2)
#define BLXerror0(text) CPLError(CE_Failure, CPLE_AppDefined, text)
#define BLXnotice1(text, arg1) CPLDebug("BLX", text, arg1)
#define BLXnotice2(text, arg1, arg2) CPLDebug("BLX", text, arg1, arg2)
#else
#define BLXfopen fopen
#define BLXfclose fclose
#define BLXfread fread
#define BLXfwrite fwrite
#define BLXfseek fseek
#define BLXftell ftell
#define BLXmalloc malloc
#define BLXfree free
#define BLXdebug0 printf
#define BLXdebug1 printf
#define BLXdebug2 printf
#define BLXerror0 printf
#define BLXnotice1 printf
#define BLXnotice2 printf
#endif

/* Function prototypes */
#ifdef TEST
STATIC int compress_chunk(unsigned char *inbuf, int inlen,
                          unsigned char *outbuf, int outbuflen);
STATIC int uncompress_chunk(unsigned char *inbuf, int inlen,
                            unsigned char *outbuf, int outbuflen);
STATIC blxdata *reconstruct_horiz(blxdata *base, blxdata *diff, unsigned rows,
                                  unsigned cols, blxdata *out);
STATIC blxdata *reconstruct_vert(blxdata *base, blxdata *diff, unsigned rows,
                                 unsigned cols, blxdata *out);
STATIC void decimate_horiz(blxdata *in, unsigned rows, unsigned cols,
                           blxdata *base, blxdata *diff);
STATIC void decimate_vert(blxdata *in, unsigned int rows, unsigned int cols,
                          blxdata *base, blxdata *diff);
STATIC blxdata *decode_celldata(blxcontext_t *blxcontext, unsigned char *inbuf,
                                int len, int *side, blxdata *outbuf,
                                int outbufsize, int overviewlevel);
#endif

blxcontext_t *blx_create_context(void);
void blx_free_context(blxcontext_t *ctx);
int blxopen(blxcontext_t *ctx, const char *filename, const char *rw);
int blxclose(blxcontext_t *ctx);
void blxprintinfo(blxcontext_t *ctx);
short *blx_readcell(blxcontext_t *ctx, int row, int col, short *buffer,
                    int bufsize, int overviewlevel);
int blx_encode_celldata(blxcontext_t *ctx, blxdata *indata, int side,
                        unsigned char *outbuf, int outbufsize);
int blx_checkheader(const char *header);
int blx_writecell(blxcontext_t *ctx, blxdata *cell, int cellrow, int cellcol);

#endif
