
#ifndef _BIOLIBC_SAM_BUFF_H_
#define _BIOLIBC_SAM_BUFF_H_

#ifndef __bool_true_false_are_defined
#include <stdbool.h>
#endif

#ifndef _BIOLIBC_SAM_H_
#include "sam.h"
#endif

#ifndef _BIOLIBC_H_
#include "biolibc.h"
#endif

/*
    256k was not enough for a few of the SRA CRAMs.
    NWD976804 needed more than 512k.  Bad data?
    Of 55k samples, only about 11% reached a sam buffer of > 8k.
    Set an upper limit to prevent runaway memory use and error out
    with EX_DATAERR to tell script not to retry.

    From sam-buff-stats script:
    
    Total      54982
    >4096      13723
    >8192       5824
    >16384      2795
    >32768      1612
    >65536       138
    >131072       33
    >262144       12
    >524288        0
*/
#define BL_SAM_BUFF_START_SIZE  4096

#define BL_SAM_BUFF_OK          0
#define BL_SAM_BUFF_ADD_FAILED  1

/*
 *  Copied from htslib/sam.h to avoid an htslib dependency.  It should be
 *  safe to assume this will never change, since changing it would break
 *  all existing SAM/BAM/CRAM files.
 */
#define     BAM_FUNMAP  4

// FIXME: Move this to samio when complete?
typedef struct
{
    size_t      buff_size;
    size_t      max_alignments;
    bl_sam_t    **alignments;
    size_t      buffered_count;
    size_t      max_count;
    int64_t     previous_pos;
    char        previous_rname[BL_SAM_RNAME_MAX_CHARS + 1];
    
    // Use 64 bits to accommodate large sums
    int64_t     mapq_min,
		mapq_low,
		mapq_high,
		mapq_sum,
		reads_used,
		total_alignments,
		trailing_alignments,
		discarded_alignments,
		discarded_score_sum,
		discarded_trailing,
		min_discarded_score,
		max_discarded_score,
		unmapped_alignments;
}   bl_sam_buff_t;

/* Not generated by gen-get-set */
#define BL_SAM_BUFF_INC_TOTAL_ALIGNMENTS(b)    (++(b)->total_alignments)
#define BL_SAM_BUFF_INC_TRAILING_ALIGNMENTS(b) (++(b)->trailing_alignments)
#define BL_SAM_BUFF_INC_DISCARDED_TRAILING(b)  (++(b)->discarded_trailing)

#include "sam-buff-rvs.h"
#include "sam-buff-accessors.h"
#include "sam-buff-mutators.h"

/* sam-buff.c */
void bl_sam_buff_check_order(bl_sam_buff_t *sam_buff, bl_sam_t *sam_alignment);
void bl_sam_buff_init(bl_sam_buff_t *sam_buff, unsigned int mapq_min, size_t max_alignments);
int bl_sam_buff_add_alignment(bl_sam_buff_t *sam_buff, bl_sam_t *sam_alignment);
void bl_sam_buff_out_of_order(bl_sam_buff_t *sam_buff, bl_sam_t *sam_alignment);
void bl_sam_buff_free_alignment(bl_sam_buff_t *sam_buff, size_t c);
void bl_sam_buff_shift(bl_sam_buff_t *sam_buff, size_t nelem);
bool bl_sam_buff_alignment_ok(bl_sam_buff_t *sam_buff, bl_sam_t *sam_alignment);

#endif  // _BIOLIBC_SAM_BUFF_H_
