#ifndef BI_HELIX_HXX
#define BI_HELIX_HXX

#ifndef ARBDB_BASE_H
#include <arbdb_base.h>
#endif
#ifndef ARB_ASSERT_H
#include <arb_assert.h>
#endif
#ifndef ARBTOOLS_H
#include <arbtools.h>
#endif

#ifndef bi_assert
#define bi_assert(bed) arb_assert(bed)
#endif


enum BI_PAIR_TYPE {
    HELIX_STRONG_PAIR,
    HELIX_NORMAL_PAIR,
    HELIX_WEAK_PAIR,

    HELIX_NO_PAIR,

    HELIX_USER0,
    HELIX_USER1,
    HELIX_USER2,
    HELIX_USER3,
    HELIX_USER4,
    HELIX_USER5,

    HELIX_DEFAULT,
};

const BI_PAIR_TYPE PAIR_TYPE_COUNT = BI_PAIR_TYPE(HELIX_DEFAULT+1);


class BI_pairdef : virtual Noncopyable {

    bool is_pairtype(char left, char right, BI_PAIR_TYPE pair_type) const;

    char *pairs_def[PAIR_TYPE_COUNT]; // pairs of upper case sequence characters (or gaps). separated by spaces. e.g.: "AC GT C-"
    char *char_bind[PAIR_TYPE_COUNT]; // helix symbol used for pairs listed in pairs_def

public:
    BI_pairdef();
    ~BI_pairdef();

    char get_symbol(char left, char right) const;
    int pair_strength(char left, char right); // return >0 if bases form a pair

    const char *get_pairs_def(int i) const {
        bi_assert(i>=0 && i<PAIR_TYPE_COUNT);
        return pairs_def[i];
    }
    const char *get_char_bind(int i) const {
        bi_assert(i>=0 && i<PAIR_TYPE_COUNT);
        return char_bind[i];
    }

    void set_pairs_def(int i, const char *new_pairs_def) {
        bi_assert(i>=0 && i<PAIR_TYPE_COUNT);
        freedup(pairs_def[i], new_pairs_def);
    }
    void set_char_bind(int i, const char *new_char_bind) {
        bi_assert(i>=0 && i<PAIR_TYPE_COUNT);
        freedup(char_bind[i], new_char_bind);
    }
};


struct BI_helix_entry {
    long  pair_pos;
    bool  is_pairpos; // true if position is a pairing position
    char *helix_nr;

    long next_pair_pos;                             /* next position with pair_type != HELIX_NONE
                                                     * contains
                                                     *  0 if uninitialized,
                                                     * -1 behind last position */
    bool allocated;
};

class BI_helix : virtual Noncopyable {
    BI_helix_entry *entries;
    size_t          Size;

    static char *helix_error; // error occurring during init is stored here

    static void clear_error() { freenull(helix_error); }
    static void set_error(GB_ERROR err) { freedup(helix_error, err); }

public:

    static GB_ERROR get_error() { return helix_error; }

    BI_helix();
    ~BI_helix();

    GB_ERROR init(GBDATA *gb_main); // [used by NALIGNER + EDIT4]
    GB_ERROR init(GBDATA *gb_main, const char *alignment_name); // [used by SEQ_QUALITY + ColumnStat + SINA]
    GB_ERROR initFromData(const char *helix_nr, const char *helix, size_t size); // [used from SECEDIT]

    size_t size() const { return Size; }
    bool has_entries() const { return entries; }
    const BI_helix_entry& entry(size_t pos) const {
        bi_assert(pos<Size);
        bi_assert(entries);
        return entries[pos];
    }

    size_t opposite_position(size_t pos) const {
        bi_assert(is_pairpos(pos)); // not a pair -> no opposite position
        return entry(pos).pair_pos;
    }
    bool is_pairpos(size_t pos) const { return pos<Size && entry(pos).is_pairpos; }
    const char *helixNr(size_t pos) const { return is_pairpos(pos) ? entry(pos).helix_nr : NULp; }
    // Note: results of helixNr may be compared by == (instead of strcmp())

    long first_pair_position() const; // first pair position (or -1)
    long next_pair_position(size_t pos) const; // next pair position behind 'pos' (or -1)

    long first_position(const char *helixNr) const; // returns -1 for non-existing helixNr's
    long last_position(const char *helixNr) const; // returns -1 for non-existing helixNr's

    // Note: all position-values used in BI_helix are in range [0 .. N-1].
    // Consider using info2bio() when using these positions in error messages or similar.
};





#endif
