#ifndef _sam_h_
#define _sam_h_

#ifndef _INTTYPES_H
#include <inttypes.h>
#endif

#ifndef __xtend_h__
//#include <xtend.h>
#endif

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

#define BL_SAM_MAPQ_MAX_CHARS  3
#define BL_SAM_QNAME_MAX_CHARS 4096
#define BL_SAM_RNAME_MAX_CHARS 4096
#define BL_SAM_FLAG_MAX_DIGITS 4096    // What should this really be?
#define BL_SAM_CIGAR_MAX_CHARS 4096
// Usually < 200 for Illumina data, but a few oddballs in SRA CRAMs
#define BL_SAM_SEQ_MAX_CHARS   1024*1024

// Use this or the function for every new object
#define BL_SAM_ALIGNMENT_INIT  { "", 0, "", 0, 0, "", "", 0, 0, NULL, NULL, 0, 0 }

typedef struct
{
    /* SAM specification fields.  Meet or exceed published ranges. */
    char            qname[BL_SAM_QNAME_MAX_CHARS + 1];
    unsigned        flag;
    char            rname[BL_SAM_RNAME_MAX_CHARS + 1];
    uint64_t        pos;
    unsigned char   mapq;
    char            cigar[BL_SAM_CIGAR_MAX_CHARS + 1];
    char            rnext[BL_SAM_RNAME_MAX_CHARS + 1];
    uint64_t        pnext;
    long            tlen;   // Max size?
    char            *seq;   // This can be large, so malloc() it
    char            *qual;  // PHRED scores, same length as seq if present
    
    /* Additional data */
    size_t          seq_len;
    size_t          qual_len;
}   bl_sam_t;

typedef unsigned int        sam_field_mask_t;

#define BL_SAM_FIELD_ALL    0xfff
#define BL_SAM_FIELD_QNAME  0x001
#define BL_SAM_FIELD_FLAG   0x002
#define BL_SAM_FIELD_RNAME  0x004
#define BL_SAM_FIELD_POS    0x008
#define BL_SAM_FIELD_MAPQ   0x010
#define BL_SAM_FIELD_CIGAR  0x020
#define BL_SAM_FIELD_RNEXT  0x040
#define BL_SAM_FIELD_PNEXT  0x080
#define BL_SAM_FIELD_TLEN   0x100
#define BL_SAM_FIELD_SEQ    0x200
#define BL_SAM_FIELD_QUAL   0x400

/*
 *  Generated by /home/bacon/scripts/gen-get-set
 *
 *  Accessor macros.  Use these to access structure members from functions
 *  outside the bl_sam_t class.
 *
 *  These generated macros are not expected to be perfect.  Check and edit
 *  as needed before adding to your code.
 */

#define BL_SAM_QNAME(ptr)               ((ptr)->qname)
#define BL_SAM_QNAME_AE(ptr,c)          ((ptr)->qname[c])
#define BL_SAM_FLAG(ptr)                ((ptr)->flag)
#define BL_SAM_RNAME(ptr)               ((ptr)->rname)
#define BL_SAM_RNAME_AE(ptr,c)          ((ptr)->rname[c])
#define BL_SAM_POS(ptr)                 ((ptr)->pos)
#define BL_SAM_MAPQ(ptr)                ((ptr)->mapq)
#define BL_SAM_CIGAR(ptr)               ((ptr)->cigar)
#define BL_SAM_CIGAR_AE(ptr,c)          ((ptr)->cigar[c])
#define BL_SAM_RNEXT(ptr)               ((ptr)->rnext)
#define BL_SAM_RNEXT_AE(ptr,c)          ((ptr)->rnext[c])
#define BL_SAM_PNEXT(ptr)               ((ptr)->pnext)
#define BL_SAM_TLEN(ptr)                ((ptr)->tlen)
#define BL_SAM_SEQ(ptr)                 ((ptr)->seq)
#define BL_SAM_SEQ_AE(ptr,c)            ((ptr)->seq[c])
#define BL_SAM_QUAL(ptr)                ((ptr)->qual)
#define BL_SAM_QUAL_AE(ptr,c)           ((ptr)->qual[c])
#define BL_SAM_SEQ_LEN(ptr)             ((ptr)->seq_len)
#define BL_SAM_QUAL_LEN(ptr)            ((ptr)->qual_len)

/*
 *  Generated by /home/bacon/scripts/gen-get-set
 *
 *  Mutator macros for setting with no sanity checking.  Use these to
 *  set structure members from functions outside the bl_sam_t
 *  class.  These macros perform no data validation.  Hence, they achieve
 *  maximum performance where data are guaranteed correct by other means.
 *  Use the mutator functions (same name as the macro, but lower case)
 *  for more robust code with a small performance penalty.
 *
 *  These generated macros are not expected to be perfect.  Check and edit
 *  as needed before adding to your code.
 */

// FIXME: Assuming char array is a null-terminated string
#define BL_SAM_SET_QNAME_CPY(ptr,val,array_size) strlcpy((ptr)->qname,val,array_size)
#define BL_SAM_SET_QNAME_AE(ptr,c,val)          ((ptr)->qname[c] = (val))
#define BL_SAM_SET_FLAG(ptr,val)                ((ptr)->flag = (val))
// FIXME: Assuming char array is a null-terminated string
#define BL_SAM_SET_RNAME_CPY(ptr,val,array_size) strlcpy((ptr)->rname,val,array_size)
#define BL_SAM_SET_RNAME_AE(ptr,c,val)          ((ptr)->rname[c] = (val))
#define BL_SAM_SET_POS(ptr,val)                 ((ptr)->pos = (val))
#define BL_SAM_SET_MAPQ(ptr,val)                ((ptr)->mapq = (val))
// FIXME: Assuming char array is a null-terminated string
#define BL_SAM_SET_CIGAR_CPY(ptr,val,array_size) strlcpy((ptr)->cigar,val,array_size)
#define BL_SAM_SET_CIGAR_AE(ptr,c,val)          ((ptr)->cigar[c] = (val))
// FIXME: Assuming char array is a null-terminated string
#define BL_SAM_SET_RNEXT_CPY(ptr,val,array_size) strlcpy((ptr)->rnext,val,array_size)
#define BL_SAM_SET_RNEXT_AE(ptr,c,val)          ((ptr)->rnext[c] = (val))
#define BL_SAM_SET_PNEXT(ptr,val)               ((ptr)->pnext = (val))
#define BL_SAM_SET_TLEN(ptr,val)                ((ptr)->tlen = (val))
#define BL_SAM_SET_SEQ(ptr,val)                 ((ptr)->seq = (val))
// FIXME: Assuming char array is a null-terminated string
#define BL_SAM_SET_SEQ_CPY(ptr,val,array_size)  strlcpy((ptr)->seq,val,array_size)
#define BL_SAM_SET_SEQ_AE(ptr,c,val)            ((ptr)->seq[c] = (val))
#define BL_SAM_SET_QUAL(ptr,val)                ((ptr)->qual = (val))
// FIXME: Assuming char array is a null-terminated string
#define BL_SAM_SET_QUAL_CPY(ptr,val,array_size) strlcpy((ptr)->qual,val,array_size)
#define BL_SAM_SET_QUAL_AE(ptr,c,val)           ((ptr)->qual[c] = (val))
#define BL_SAM_SET_SEQ_LEN(ptr,val)             ((ptr)->seq_len = (val))
#define BL_SAM_SET_QUAL_LEN(ptr,val)            ((ptr)->qual_len = (val))

/* sam.c */
int bl_sam_read(FILE *sam_stream, bl_sam_t *sam_alignment, sam_field_mask_t field_mask);
void bl_sam_copy(bl_sam_t *dest, bl_sam_t *src);
void bl_sam_free(bl_sam_t *sam_alignment);
void bl_sam_init(bl_sam_t *sam_alignment, size_t seq_len, sam_field_mask_t field_mask);
int bl_sam_write(FILE *sam_stream, bl_sam_t *sam_alignment, sam_field_mask_t field_mask);

/* sam-mutators.c */
int bl_sam_set_qname_ae(bl_sam_t *bl_sam_ptr, size_t c, char new_qname_element);
int bl_sam_set_qname_cpy(bl_sam_t *bl_sam_ptr, char new_qname[], size_t array_size);
int bl_sam_set_flag(bl_sam_t *bl_sam_ptr, unsigned new_flag);
int bl_sam_set_rname_ae(bl_sam_t *bl_sam_ptr, size_t c, char new_rname_element);
int bl_sam_set_rname_cpy(bl_sam_t *bl_sam_ptr, char new_rname[], size_t array_size);
int bl_sam_set_pos(bl_sam_t *bl_sam_ptr, uint64_t new_pos);
int bl_sam_set_mapq(bl_sam_t *bl_sam_ptr, unsigned char new_mapq);
int bl_sam_set_cigar_ae(bl_sam_t *bl_sam_ptr, size_t c, char new_cigar_element);
int bl_sam_set_cigar_cpy(bl_sam_t *bl_sam_ptr, char new_cigar[], size_t array_size);
int bl_sam_set_rnext_ae(bl_sam_t *bl_sam_ptr, size_t c, char new_rnext_element);
int bl_sam_set_rnext_cpy(bl_sam_t *bl_sam_ptr, char new_rnext[], size_t array_size);
int bl_sam_set_pnext(bl_sam_t *bl_sam_ptr, uint64_t new_pnext);
int bl_sam_set_tlen(bl_sam_t *bl_sam_ptr, long new_tlen);
int bl_sam_set_seq(bl_sam_t *bl_sam_ptr, char *new_seq);
int bl_sam_set_seq_ae(bl_sam_t *bl_sam_ptr, size_t c, char new_seq_element);
int bl_sam_set_seq_cpy(bl_sam_t *bl_sam_ptr, char *new_seq, size_t array_size);
int bl_sam_set_qual(bl_sam_t *bl_sam_ptr, char *new_qual);
int bl_sam_set_qual_ae(bl_sam_t *bl_sam_ptr, size_t c, char new_qual_element);
int bl_sam_set_qual_cpy(bl_sam_t *bl_sam_ptr, char *new_qual, size_t array_size);
int bl_sam_set_seq_len(bl_sam_t *bl_sam_ptr, size_t new_seq_len);
int bl_sam_set_qual_len(bl_sam_t *bl_sam_ptr, size_t new_qual_len);

#endif // _sam_h_
