#ifndef _gff_h_
#define _gff_h_

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

#ifndef _xtend_h_
//#include <xtend.h>  // strlcpy() on Linux
#endif

#define BL_GFF_SCORE_MAX_DIGITS        64       // Floating point
#define BL_GFF_SOURCE_MAX_CHARS        1024     // Guess
#define BL_GFF_FEATURE_MAX_CHARS       256      // Guess
#define BL_GFF_STRAND_MAX_CHARS        2
#define BL_GFF_LINE_MAX_CHARS          4096
#define BL_GFF_PHASE_MAX_DIGITS        2
#define BL_GFF_ATTRIBUTES_MAX_CHARS    8192     // For temp vars only.
						// Structure uses malloc()

#define BL_GFF_SCORE_UNAVAILABLE       -1.0
#define BL_GFF_PHASE_UNAVAILABLE       '.'

#define BL_GFF_INIT \
	{ "", "", "", 0, 0, 0.0, '.', '.', NULL, NULL, NULL }

typedef struct
{
    char            sequence[BL_CHROM_MAX_CHARS + 1];
    char            source[BL_GFF_SOURCE_MAX_CHARS + 1];
    char            feature[BL_GFF_FEATURE_MAX_CHARS + 1];
    uint64_t        start,
		    end;
    double          score;
    char            strand;         // '+' or '-' or '.'
    char            phase;          // 0, 1, 2, or '.' (bases to condon start)
    char            *attributes;    // Ensembl ID, Name, etc.
    
    /*
     *  Fields below are not part of GFF.  They are extracted from attributes
     *  and may be useful.
     */
    char            *feature_id;    // In every feature of Ensemble GFFs
    char            *gene_name;     // Extract from gene features and look
				    // up using Ensemble ID for others
}   bl_gff_t;

typedef unsigned int            gff_field_mask_t;

#define BL_GFF_FIELD_SEQUENCE   0x001
#define BL_GFF_FIELD_SOURCE     0x002
#define BL_GFF_FIELD_FEATURE    0x004
#define BL_GFF_FIELD_START      0x008
#define BL_GFF_FIELD_END        0x010
#define BL_GFF_FIELD_SCORE      0x020
#define BL_GFF_FIELD_STRAND     0x040
#define BL_GFF_FIELD_PHASE      0x080
#define BL_GFF_FIELD_ATTRIBUTES 0x100
#define BL_GFF_FIELD_ALL        0xfff

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

#define BL_GFF_SEQUENCE(ptr)            ((ptr)->sequence)
#define BL_GFF_SEQUENCE_AE(ptr,c)       ((ptr)->sequence[c])
#define BL_GFF_SOURCE(ptr)              ((ptr)->source)
#define BL_GFF_SOURCE_AE(ptr,c)         ((ptr)->source[c])
#define BL_GFF_FEATURE(ptr)             ((ptr)->feature)
#define BL_GFF_FEATURE_AE(ptr,c)        ((ptr)->feature[c])
#define BL_GFF_START(ptr)               ((ptr)->start)
#define BL_GFF_END(ptr)                 ((ptr)->end)
#define BL_GFF_SCORE(ptr)               ((ptr)->score)
#define BL_GFF_STRAND(ptr)              ((ptr)->strand)
#define BL_GFF_PHASE(ptr)               ((ptr)->phase)
#define BL_GFF_ATTRIBUTES(ptr)          ((ptr)->attributes)
#define BL_GFF_ATTRIBUTES_AE(ptr,c)     ((ptr)->attributes[c])
#define BL_GFF_FEATURE_ID(ptr)          ((ptr)->feature_id)
#define BL_GFF_FEATURE_ID_AE(ptr,c)     ((ptr)->feature_id[c])
#define BL_GFF_GENE_NAME(ptr)           ((ptr)->gene_name)
#define BL_GFF_GENE_NAME_AE(ptr,c)      ((ptr)->gene_name[c])

/*
 *  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_gff_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.
 */

#define BL_GFF_SET_SEQUENCE_CPY(ptr,val,array_size) strlcpy((ptr)->sequence,val,array_size)
#define BL_GFF_SET_SEQUENCE_AE(ptr,c,val)       ((ptr)->sequence[c] = (val))
#define BL_GFF_SET_SOURCE_CPY(ptr,val,array_size) strlcpy((ptr)->source,val,array_size)
#define BL_GFF_SET_SOURCE_AE(ptr,c,val)         ((ptr)->source[c] = (val))
#define BL_GFF_SET_FEATURE_CPY(ptr,val,array_size) strlcpy((ptr)->feature,val,array_size)
#define BL_GFF_SET_FEATURE_AE(ptr,c,val)        ((ptr)->feature[c] = (val))
#define BL_GFF_SET_START(ptr,val)               ((ptr)->start = (val))
#define BL_GFF_SET_END(ptr,val)                 ((ptr)->end = (val))
#define BL_GFF_SET_SCORE(ptr,val)               ((ptr)->score = (val))
#define BL_GFF_SET_STRAND(ptr,val)              ((ptr)->strand = (val))
#define BL_GFF_SET_PHASE(ptr,val)               ((ptr)->phase = (val))
#define BL_GFF_SET_ATTRIBUTES(ptr,val)          ((ptr)->attributes = (val))
#define BL_GFF_SET_ATTRIBUTES_CPY(ptr,val,array_size) strlcpy((ptr)->attributes,val,array_size)
#define BL_GFF_SET_ATTRIBUTES_AE(ptr,c,val)     ((ptr)->attributes[c] = (val))
#define BL_GFF_SET_FEATURE_ID(ptr,val)          ((ptr)->feature_id = (val))
#define BL_GFF_SET_FEATURE_ID_CPY(ptr,val,array_size) strlcpy((ptr)->feature_id,val,array_size)
#define BL_GFF_SET_FEATURE_ID_AE(ptr,c,val)     ((ptr)->feature_id[c] = (val))
#define BL_GFF_SET_GENE_NAME(ptr,val)           ((ptr)->gene_name = (val))
#define BL_GFF_SET_GENE_NAME_CPY(ptr,val,array_size) strlcpy((ptr)->gene_name,val,array_size)
#define BL_GFF_SET_GENE_NAME_AE(ptr,c,val)      ((ptr)->gene_name[c] = (val))

// After bl_gff_t for prototypes
#ifndef _bed_h_
#include "bed.h"
#endif

/* gff.c */
FILE *bl_gff_skip_header(FILE *gff_stream);
int bl_gff_read(FILE *gff_stream, bl_gff_t *gff_feature, gff_field_mask_t field_mask);
int bl_gff_write(FILE *gff_stream, bl_gff_t *gff_feature, gff_field_mask_t field_mask);
void bl_gff_to_bed(bl_bed_t *bed_feature, bl_gff_t *gff_feature);

/* gff-mutators.c */
int bl_gff_set_sequence_ae(bl_gff_t *bl_gff_ptr, size_t c, char new_sequence_element);
int bl_gff_set_sequence_cpy(bl_gff_t *bl_gff_ptr, char new_sequence[], size_t array_size);
int bl_gff_set_source_ae(bl_gff_t *bl_gff_ptr, size_t c, char new_source_element);
int bl_gff_set_source_cpy(bl_gff_t *bl_gff_ptr, char new_source[], size_t array_size);
int bl_gff_set_feature_ae(bl_gff_t *bl_gff_ptr, size_t c, char new_feature_element);
int bl_gff_set_feature_cpy(bl_gff_t *bl_gff_ptr, char new_feature[], size_t array_size);
int bl_gff_set_start(bl_gff_t *bl_gff_ptr, uint64_t new_start);
int bl_gff_set_end(bl_gff_t *bl_gff_ptr, uint64_t new_end);
int bl_gff_set_score(bl_gff_t *bl_gff_ptr, double new_score);
int bl_gff_set_strand(bl_gff_t *bl_gff_ptr, char new_strand);
int bl_gff_set_phase(bl_gff_t *bl_gff_ptr, char new_phase);
int bl_gff_set_attributes(bl_gff_t *bl_gff_ptr, char *new_attributes);
int bl_gff_set_attributes_ae(bl_gff_t *bl_gff_ptr, size_t c, char new_attributes_element);
int bl_gff_set_attributes_cpy(bl_gff_t *bl_gff_ptr, char *new_attributes, size_t array_size);
int bl_gff_set_feature_id(bl_gff_t *bl_gff_ptr, char *new_feature_id);
int bl_gff_set_feature_id_ae(bl_gff_t *bl_gff_ptr, size_t c, char new_feature_id_element);
int bl_gff_set_feature_id_cpy(bl_gff_t *bl_gff_ptr, char *new_feature_id, size_t array_size);
int bl_gff_set_gene_name(bl_gff_t *bl_gff_ptr, char *new_gene_name);
int bl_gff_set_gene_name_ae(bl_gff_t *bl_gff_ptr, size_t c, char new_gene_name_element);
int bl_gff_set_gene_name_cpy(bl_gff_t *bl_gff_ptr, char *new_gene_name, size_t array_size);

#endif  // _gff_h_
