/*
 *
 * FITS.h
 *
 * Global fits header
 *
 * Author: lyard
 *
 */

#ifndef MARS_FITS
#define MARS_FITS

#include <stdint.h>

namespace FITS
{

    //Identifier of the compression schemes processes
    enum CompressionProcess_t
    {
        kFactRaw       = 0x0,
        kFactSmoothing = 0x1,
        kFactHuffman16 = 0x2
    };

    //ordering of the columns / rows
    enum RowOrdering_t
    {
        kOrderByCol = 'C',
        kOrderByRow = 'R'
    };

#ifdef __CINT__
    struct TileHeader;
    struct BlockHeader;
#else
    //Structure helper for tiles headers
    struct TileHeader
    {
      char     id[4];
      uint32_t numRows;
      uint64_t size;

      TileHeader() {}

      TileHeader(uint32_t nRows,
                 uint64_t s) : id({'T', 'I', 'L', 'E'}),
                                 numRows(nRows),
                                 size(s)
      { };
    } __attribute__((__packed__));

    //Structure helper for blocks headers and compresion schemes
    struct BlockHeader
    {
        uint64_t      size;
        char          ordering;
        unsigned char numProcs;
        uint16_t      processings[];

        BlockHeader(uint64_t      s=0,
                    char          o=kOrderByRow,
                    unsigned char n=1) : size(s),
                                         ordering(o),
                                         numProcs(n)
        {}
    } __attribute__((__packed__));
#endif

    //Helper structure to simplify the initialization and handling of compressed blocks headers
    struct Compression
    {
        BlockHeader header;
        std::vector<uint16_t> sequence;

        Compression(const std::vector<uint16_t> &seq, const RowOrdering_t &order=kOrderByCol)
            : header(0, order, seq.size()), sequence(seq)
        {

        }

        Compression(const CompressionProcess_t &compression=kFactRaw, const RowOrdering_t &order=kOrderByCol)
            : header(0, order, 1), sequence(1)
        {
            sequence[0] = compression;
        }

#ifdef __MARS__ // needed for CINT
        Compression(const int &compression)
            : header(0, kOrderByCol, 1), sequence(1)
        {
            sequence[0] = compression;
        }
#endif

        RowOrdering_t getOrdering() const { return RowOrdering_t(header.ordering); }
        uint32_t getSizeOnDisk() const { return sizeof(BlockHeader) + sizeof(uint16_t)*header.numProcs; }
        CompressionProcess_t getProc(uint32_t i) const { return CompressionProcess_t(sequence[i]); }
        uint16_t getNumProcs() const { return header.numProcs; }

        void SetBlockSize(uint64_t size) { header.size = size; }
        void Memcpy(char *dest) const
        {
            memcpy(dest, &header, sizeof(BlockHeader));
            memcpy(dest+sizeof(BlockHeader), sequence.data(), header.numProcs*sizeof(uint16_t));
        }
    };
};

#endif //_FITS_H_

