//CHECK:
//What happens when ECQBits==1, or ECQBits==0 or ECQBits<0?
//Rounding? Scale originalEb by 0.99?

//Possible improvement: Change GAMESS format: {i i i i d} -> {i}{i}{i}{i}{d}
//Possible improvement: Optimize bookkeeping bits
//Possible improvement: Guess the type (C/UC, Sparse/Not)
//Possible improvement: Get rid of writing/reading some of the indexes to in/out buffers
//Possible improvement: Get rid of all debug stuff, including Makefile debug flags
//Possible improvement: Get rid of "compressedBytes"
//Possible improvement: SparseCompressed, ECQBits=2: 1's and -1's can be represented by just 0 and 1, instead 10 and 11. 
//Possible improvement: SparseCompressed, ECQBits>2: Again: 1: 10, -1:11, Others: 0XX...XX 
//Possible improvement: WriteBitsFast: maybe remove some masks?
//Possible improvement: WriteBitsFast: Get rid of multiple calls!
//Possible improvement: UCSparse: Indexes use 64 bits. It can be lowered to _1DIdxBits
//Possible improvement: Parameters: Smaller data sizes may be possible!



#ifndef PASTRI_H
#define PASTRI_H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <assert.h> //Just for debugging purposes!

//#define DATASIZE 8 //Bytes per input data point.
//We have only 1 double per data point, so it is 8 bytes.

#define MAX_PS_SIZE 100
#define MAX_BLOCK_SIZE 10000
#define MAX_BUFSIZE 160000  //Should be a multiple of 8
#define D_W 0 //Debug switch: Write (input block)
#define D_R 0 //Debug switch: Read (compressed block)
#define D_G 0 //Debug switch: General
#define D_G2 0 //Debug switch: General 2 (a little more detail)
#define D_C 0 //Debug switch: C
//#define DEBUG 1 //Debug switch

//#define BOOKKEEPINGBITS 0 //Currently unused
//#define BOOKKEEPINGBITS 120 //Includes: mode, indexOffsets, compressedBytes, Pb_, ECQBits_ (8+64+32+8+8) 
//BOOKKEEPINGBITS is defined here, because if P & S is going to be used, they appear just after the bookkeeping part.
//This allows us to write P and S directly onto using outBuf.
  

// IMPORTANT NOTE:
//Read/Write up to 56 bits.
//More than that is not supported!


/********************************************************************/
//Datatype Declarations:
/********************************************************************/
typedef struct pastri_params{
  double originalEb; //Error Bound entered by the user
  double usedEb; //Error Bound used during compression/deceompression
  
  int numBlocks; //Number of blocks to be compressed
  int dataSize; //8(=Double) or 4(=Float)
  
  int bf[4]; //Orbital types (basis function types). Typically in range [0,3]
  int idxRange[4];  //Ranges of indexes. idxRange[i]=(bf[i]+1)*(bf[i]+2)/2;
  
  int sbSize; //=idxRange[2]*idxRange[3];
  int sbNum;  //=idxRange[0]*idxRange[1];
  int bSize; //=sbSize*sbNum;
  
  //uint16_t idxOffset[4]; //Index offset values. No longer used.
  
}pastri_params;

//Block-specific stuff:
typedef struct pastri_blockParams{
  uint16_t nonZeros;
  //int ECQ0s; //= p->bSize - numOutliers //OR: p->bSize=ECQ0s+ECQ1s+ECQOthers
  int ECQ1s;
  int ECQOthers;
  int numOutliers; //=ECQ1s+ECQOthers
  int patternBits;
  int scaleBits;
  double binSize;
  double scalesBinSize;
  uint64_t ECQExt;
  int ECQBits;
  int _1DIdxBits;
}pastri_blockParams;

typedef union u_UI64I64D{
  uint64_t ui64;
  int64_t i64;
  double d;
} u_UI64I64D;

/********************************************************************/
//Function Prototypes:
/********************************************************************/
void SZ_pastriReadParameters(char paramsFilename[512],pastri_params *paramsPtr);
//Read the basic PaSTRI parameters from a file, speficied by paramsFilename.

void SZ_pastriPreprocessParameters(pastri_params *p);
//Using basic PaSTRI parameters, generate the others.
//For example, block and sub-block sizes are generated by using basis function types.

void SZ_pastriCompressBatch(pastri_params *p,unsigned char *originalBuf, unsigned char** compressedBufP,size_t *compressedBytes);
//INPUTS: p, originalBuf
//OUTPUTS: compressedBufP, compressedBytes
//Using the inputs, compressedBufP is allocated and populated by the compressed data. Compressed size is written into compressedBytes.
//Parameters are also stored at the beginning part of the compressedBuf

void SZ_pastriDecompressBatch(unsigned char*compressedBuf, pastri_params *p, unsigned char** decompressedBufP ,size_t *decompressedBytes);
//INPUTS: compressedBuf
//OUTPUTS: p, decompressedBufP, decompressedBytes
//First, parameters are read from compressedBuf and written into p.
//Then, decompressedBufP is allocated and populated by the decompressed data. Decompressed size is written into decompressedBytes.

void SZ_pastriCheckBatch(pastri_params *p,unsigned char*originalBuf,unsigned char*decompressedBuf); 
//INPUTS: p, originalBuf, decompressedBuf
//OUTPUTS: None (Just some on-screen messages)
//Compares originalBuf with decompressedBuf. Checks whether the absolute error condition is satisfied or not.

/********************************************************************/
//Other Includes:
/********************************************************************/



#include "pastriGeneral.h"  //General tools
#include "pastriD.h"  //Compression/Decompression for Double data
#include "pastriF.h"  //Compression/Decompression for Float data


#endif





