/*
     Description: bam压缩，解压和读入头文件等函数

     Copyright : All right reserved by ICT

     Author : Zhang Zhonghai
     Date : 2026/06/05
*/

#pragma once
#include <htslib/sam.h>
#include <stdio.h>

#define INCREASE_SIZE (8L * 1024 * 1024)

// 一般用途的数据缓冲区
struct DataBuffer {
    uint8_t *data;
    size_t readPos = 0; // 当前读取的位置
    size_t lastPos = 0; // 最后一个bam的起始位置
    size_t curLen = 0;  // 当前使用的空间
    size_t maxLen = 0;  // 最大空间

    DataBuffer() {
        curLen = 0;
        maxLen = 0;
        data = nullptr;
    }
    DataBuffer(size_t initSize) {
        curLen = 0;
        maxLen = initSize;
        data = (uint8_t *)malloc(maxLen);
    }
    ~DataBuffer() {
        if (data) {
            free(data);
            data = nullptr;
        }
        readPos = 0;
        lastPos = 0;
        curLen = 0;
        maxLen = 0;
    }
    void AllocMem(size_t memSize) {
        curLen = 0;
        maxLen = memSize;
        data = (uint8_t *)realloc(data, maxLen);
    }

    void ReAllocMem(size_t memSize) {
        if (memSize > maxLen) {
            maxLen = memSize;
            data = (uint8_t *)realloc(data, maxLen);
        }
    }

    void MemCopy(uint8_t *src, size_t len) {
        if (len > 0) {
            ReAllocMem(curLen + len);
            memcpy(&data[curLen], src, len);
            curLen += len;
        }
    }

    void ReSize(size_t memSize) {
        ReAllocMem(memSize);
        curLen = memSize;
    }

    void MemCopy(size_t offset, uint8_t* src, size_t len) {
        memcpy(&data[offset], src, len);
    }

    void Clear() {
        curLen = 0;
        readPos = 0;
        lastPos = 0;
    }
};

struct HeaderBuf {
    uint8_t *data = nullptr; // 保留除header之外的解压数据（即最开始的bam记录）
    int dataLen = 0; // 解压数据的字节数
    sam_hdr_t *header;
    DataBuffer compressed;
};

static int unpackInt16(const uint8_t *buffer) { return buffer[0] | buffer[1] << 8; }

void parseSamHeader(FILE *fp, HeaderBuf &hdrBuf);

int bgzfCompress(void* _dst, size_t* dlen, const void* src, size_t slen, int level);
int bgzfUncompress(uint8_t* dst, size_t* dlen, const uint8_t* src, size_t slen, uint32_t expected_crc);