#ifndef _bed_h_
#define _bed_h_

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

#define BL_BED_NAME_MAX_CHARS          256
#define BL_BED_SCORE_MAX_DIGITS        4   // 0 to 1000
#define BL_BED_STRAND_MAX_CHARS        2
#define BL_BED_ITEM_RGB_MAX_CHARS      11  // 255,255,255
#define BL_BED_BLOCK_COUNT_MAX_DIGITS  5
#define BL_BED_BLOCK_SIZE_MAX_DIGITS   20  // 2^64
#define BL_BED_BLOCK_START_MAX_DIGITS  20  // 2^64

#define BL_BED_INIT \
	{ "", 0, 0, "", 0, '.', 0, 0, "", 0, NULL, NULL, 0 }

typedef struct
{
    char            chrom[BL_CHROM_MAX_CHARS + 1];
    /*
     *      12345
     *      ACCGT
     *      01234
     *
     *      chr1 0 5
     */
    uint64_t        chrom_start,
		    chrom_end;
    char            name[BL_BED_NAME_MAX_CHARS + 1];
    unsigned short  score; // 0 to 1000
    char            strand;
    uint64_t        thick_start,
		    thick_end;
    // FIXME: Store RGB in a more compact format
    char            item_rgb[BL_BED_ITEM_RGB_MAX_CHARS+1];
    unsigned short  block_count;
    uint64_t        *block_sizes;
    uint64_t        *block_starts;

    // Not part of BED spec
    unsigned short  fields;     // 3 to 9
}   bl_bed_t;

typedef unsigned int            bed_field_mask_t;

/*
 *  Chromosome, start, and end are required so no mask bits are defined
 */
#define BL_BED_FIELD_NAME      0x01
#define BL_BED_FIELD_SCORE     0x02
#define BL_BED_FIELD_STRAND    0x04
#define BL_BED_FIELD_THICK     0X08
#define BL_BED_FIELD_RGB       0x10
#define BL_BED_FIELD_BLOCK     0x20
#define BL_BED_FIELD_ALL       0xff

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

#define BL_BED_CHROM(ptr)               ((ptr)->chrom)
#define BL_BED_CHROM_AE(ptr,c)          ((ptr)->chrom[c])
#define BL_BED_CHROM_START(ptr)         ((ptr)->chrom_start)
#define BL_BED_CHROM_END(ptr)           ((ptr)->chrom_end)
#define BL_BED_NAME(ptr)                ((ptr)->name)
#define BL_BED_NAME_AE(ptr,c)           ((ptr)->name[c])
#define BL_BED_SCORE(ptr)               ((ptr)->score)
#define BL_BED_STRAND(ptr)              ((ptr)->strand)
#define BL_BED_THICK_START(ptr)         ((ptr)->thick_start)
#define BL_BED_THICK_END(ptr)           ((ptr)->thick_end)
#define BL_BED_ITEM_RGB(ptr)            ((ptr)->item_rgb)
#define BL_BED_ITEM_RGB_AE(ptr,c)       ((ptr)->item_rgb[c])
#define BL_BED_BLOCK_COUNT(ptr)         ((ptr)->block_count)
#define BL_BED_BLOCK_SIZES(ptr)         ((ptr)->block_sizes)
#define BL_BED_BLOCK_STARTS(ptr)        ((ptr)->block_starts)
#define BL_BED_FIELDS(ptr)              ((ptr)->fields)

// After bl_bed_t def for prototypes
#ifndef _gff_h_
#include "gff.h"
#endif

#ifndef _bl_overlap_h
#include "overlap.h"
#endif

/* bed.c */
FILE *bl_bed_skip_header(FILE *bed_stream);
int bl_bed_read(bl_bed_t *bed_feature, bed_field_mask_t field_mask, FILE *bed_stream);
int bl_bed_write(bl_bed_t *bed_feature, bed_field_mask_t field_mask, FILE *bed_stream);
void bl_bed_check_order(bl_bed_t *bed_feature, char last_chrom[], uint64_t last_start);
int bl_bed_gff_cmp(bl_bed_t *bed_feature, bl_gff_t *gff_feature, bl_overlap_t *overlap);

/* bed-mutators.c */
int bl_bed_set_chrom_ae(bl_bed_t *bl_bed_ptr, size_t c, char new_chrom_element);
int bl_bed_set_chrom_cpy(bl_bed_t *bl_bed_ptr, char new_chrom[], size_t array_size);
int bl_bed_set_chrom_start(bl_bed_t *bl_bed_ptr, uint64_t new_chrom_start);
int bl_bed_set_chrom_end(bl_bed_t *bl_bed_ptr, uint64_t new_chrom_end);
int bl_bed_set_name_ae(bl_bed_t *bl_bed_ptr, size_t c, char new_name_element);
int bl_bed_set_name_cpy(bl_bed_t *bl_bed_ptr, char new_name[], size_t array_size);
int bl_bed_set_score(bl_bed_t *bl_bed_ptr, unsigned short new_score);
int bl_bed_set_strand(bl_bed_t *bl_bed_ptr, char new_strand);
int bl_bed_set_thick_start(bl_bed_t *bl_bed_ptr, uint64_t new_thick_start);
int bl_bed_set_thick_end(bl_bed_t *bl_bed_ptr, uint64_t new_thick_end);
int bl_bed_set_item_rgb_ae(bl_bed_t *bl_bed_ptr, size_t c, char new_item_rgb_element);
int bl_bed_set_item_rgb_cpy(bl_bed_t *bl_bed_ptr, char new_item_rgb[], size_t array_size);
int bl_bed_set_block_count(bl_bed_t *bl_bed_ptr, unsigned short new_block_count);
int bl_bed_set_block_sizes(bl_bed_t *bl_bed_ptr, uint64_t *new_block_sizes);
int bl_bed_set_block_sizes_ae(bl_bed_t *bl_bed_ptr, size_t c, uint64_t new_block_sizes_element);
int bl_bed_set_block_sizes_cpy(bl_bed_t *bl_bed_ptr, uint64_t *new_block_sizes, size_t array_size);
int bl_bed_set_block_starts(bl_bed_t *bl_bed_ptr, uint64_t *new_block_starts);
int bl_bed_set_block_starts_ae(bl_bed_t *bl_bed_ptr, size_t c, uint64_t new_block_starts_element);
int bl_bed_set_block_starts_cpy(bl_bed_t *bl_bed_ptr, uint64_t *new_block_starts, size_t array_size);
int bl_bed_set_fields(bl_bed_t *bl_bed_ptr, unsigned short new_fields);

#endif  // _bed_h_
