// -*- related-file-name: "../../libefont/pairop.cc" -*-
#ifndef PAIROP_HH
#define PAIROP_HH
#include <efont/encoding.hh> /* get GlyphIndex */
namespace Efont {

enum PairOpDefs {

    opNoop		= -1,
    opLigature		= -2,

    opLigSimple		= 0,
    opLigSaveLeft		= 1,
    opLigSaveRight	= 2,
    opLigPast1		= 4,
    opLigPast2		= 8,

    opAllblock		= 0

};


typedef int PairOpIndex;


class PairOp { public:

    PairOp()			{ }
    inline PairOp(GlyphIndex l, GlyphIndex r, int v, PairOpIndex nl);
    inline PairOp(GlyphIndex l, GlyphIndex r, GlyphIndex x, int kind, PairOpIndex nl);

    void noopify()		{ _val = opNoop; }
    void set_value(int val)	{ _val = val; }

    inline void set_next(PairOpIndex);

    bool is_lig() const		{ return _val <= opLigature; }
    bool is_kern() const	{ return _val >= 0; }
    bool is_noop() const	{ return _val == opNoop; }
    int lig_kind() const	{ assert(is_lig()); return -_val+opLigature; }

    GlyphIndex left() const	{ return _left; }
    GlyphIndex right() const	{ return _right; }
    GlyphIndex result() const	{ assert(is_lig()); return _result; }
    int value() const		{ return _val; }
    PairOpIndex next_left() const { return _next_left; }

  private:

    GlyphIndex _left;
    GlyphIndex _right;
    GlyphIndex _result;
    int _val;

    PairOpIndex _next_left;

};


class PairProgram { public:

    PairProgram()				: _reversed(false) { }
    PairProgram(const PairProgram &);

    void reserve_glyphs(int);

    PairOpIndex find_left(GlyphIndex gi) const	{ return _left_map[gi]; }
    PairOpIndex find(GlyphIndex leftgi, GlyphIndex rightgi) const;

    int op_count() const			{ return _op.size(); }
    const PairOp &op(PairOpIndex i) const	{ return _op[i]; }

    // Return true if it's a duplicate.
    bool add_kern(GlyphIndex, GlyphIndex, int);
    bool add_lig(GlyphIndex, GlyphIndex, GlyphIndex, int kind = opLigSimple);

    void set_reversed(bool r)			{ _reversed = r; }
    void unreverse();
    void optimize();

    void print() const;

  private:

    bool _reversed;
    Vector<PairOpIndex> _left_map;
    Vector<PairOp> _op;

    inline const char *print_name(GlyphIndex) const;

    PairProgram &operator=(const PairProgram &)	{ assert(0); return *this; }

};


inline PairOp::PairOp(GlyphIndex l, GlyphIndex r, int v, PairOpIndex nl)
    : _left(l), _right(r), _result(), _val(v), _next_left(nl)
{
}

inline PairOp::PairOp(GlyphIndex l, GlyphIndex r, GlyphIndex x, int kind,
		      PairOpIndex nl)
    : _left(l), _right(r), _result(x), _val(opLigature - kind), _next_left(nl)
{
}

inline void PairOp::set_next(PairOpIndex nl)
{
    _next_left = nl;
}

}
#endif
