/* Talin's Region Manager */

#ifndef __REGIONS
#define __REGIONS

/* ===================================================================== *
   Constants
 * ===================================================================== */

	// Boolean operations which can be done on two regions.

enum regOps {				//	00	01	10	11
					//	~~	~~	~~	~~
    regOpClear = 0,			//	0	0	0	0
    regOpAnd,				//	0	0	0	1
    regOpAndReverse,			//	0	0	1	0
    regOpCopy,				//	0	0	1	1
    regOpAndInverted,			//	0	1	0	0
    regOpNoOp,				//	0	1	0	1
    regOpXor,				//	0	1	1	0
    regOpOr,				//	0	1	1	1

	// These operations are not supported because they
	// would create an inverted region. (However, we could
	// eventually support these by having an "inverted" bit
	// in the region struct. Of course, this would mean that each
	// time we use an opcode, we'd have to figure out what the
	// "correct" opcode is, probably using De Morgan's theorem:
	// NOT(a) or NOT(b) = NOT( a and b ). For example, a NAND operation
	// on two non-inverted regions can be synthesized by doing an
	// AND and then setting the 'inverted' bit on the result.
	// Of course, "drawing" through an inverted region is going
	// to be difficult, since getting the clip-rects is harder.)

/*  regOpNor,				//	1	0	0	0
    regOpEquiv,				//	1	0	0	1
    regOpInvert,			//	1	0	1	0
    regOpOrReverse,			//	1	0	1	1
    regOpCopyInverted,			//	1	1	0	0
    regOpOrInverted,			//	1	1	0	1
    regOpNand,				//	1	1	1	0
    regOpSet,				//	1	1	1	1
*/
};

/* ===================================================================== *
   evalOp: inline function to evalulate any boolean operator
 * ===================================================================== */

inline bool evalOp( int16 op, int16 a, int16 b )
{
    int16		bit = a ? 4 : 8;

	// Test the truth table in the bits
    return op & (b ? bit >> 2 : bit);
}

/* ===================================================================== *
   RegionRect: contains the individual clip rectangles for the region
 * ===================================================================== */

class RegionRect {
private:
    friend class	Region;
    friend class	RegionStrip;
    friend class	StripWalker;
    friend class	RegionWalker;
    friend class	RegionIterator;

	// We store only an x-position and a width.
    int16		x,			// left edge of rect
			width;			// width of span
    RegionRect		*next;			// pointer to next rect

    RegionRect();				// constructor
};

/* ===================================================================== *
   RegionStrip: A horizontal strip of region rectangles
 * ===================================================================== */

class RegionStrip {
private:
    friend class	Region;
    friend class	RegionRect;
    friend class	StripWalker;
    friend class	RegionWalker;
    friend class	RegionIterator;

    RegionStrip		*next;			// pointer to next strip
    RegionRect		*rectList,		// list of rectangles in strip.
			*lastRect;		// last rectangle added.
    int16		yPos,			// y position of strip
			height;			// height of the strip

    RegionStrip();				// constructor
    ~RegionStrip();				// destructor

    bool stripsEqual( RegionStrip &strip );	// compare strips for equality

    void addRect( int16 xPos, int16 width );	// add rectangle to strip

    RegionStrip *combine(			// combine two strips
	Rect16			stripExtent,	// extent of strip
	RegionStrip		&strip,		// region strip to combine with
	int16			op );		// boolean operation

	// Returns the left and right edge of a strip
    void stripExtent( int16 &leftEdge, int16 &width );

	// Makes a copy of a strip.
    RegionStrip *copy( int16 y, int16 h );
};

/* ===================================================================== *
   Region
 * ===================================================================== */

class Region {
private:
    friend class	RegionRect;
    friend class	RegionStrip;
    friend class	StripWalker;
    friend class	RegionWalker;
    friend class	RegionIterator;

    enum regionFlags {
	empty		= (1<<0),		// indicates "empty region"
	simpleRect	= (1<<1),		// region is simple rectangle
	inverted	= (1<<2),		// space outside region is inside
    };

    int16		flags;
    Rect16		bounds;			// bounding box of entire region
    RegionStrip		*stripList;

public:

	// Constructor and destructor
    Region();
    ~Region();

    void clearRegion();				// set region to empty

    void addRect( const Rect16 &r );		// add a rectangle
    void addRegion( const Region &reg );	// add a region
    void subtractRect( const Rect16 &r );	// clear a rectangle from a region
    void subtractRegion( const Region &reg );	// clear a region fro a region

	// These will do various boolean operations on a region
    void boolOpRect( const Rect16 &r, int16 op );
    void boolOpRegion( const Region &reg, int16 op );

	// Return the bounding rectangle of a region
    Rect16 getBounds() { return bounds; }

// void expand( int16 dx, int16 dy );

    void extractRegion( Region & );			// copy region and then clear
};

/* ===================================================================== *
   RegionIterator: iterates through all cliprects in region
 * ===================================================================== */

class RegionIterator {
private:
    const Region	*region;
    Rect16		searchRect;
    const RegionStrip	*strip;
    RegionRect 		*rect;
    bool		simpleFlag;
    int16		stripYPos,
			stripHeight;

public:
    RegionIterator( const Region *reg, const Rect16 &search );
    bool next( Rect16 &clipRect );
};

#endif
