#include "X.h"
#include "Xproto.h"
#include "Xint.h"
#include "dix.h"

#define MIN(a,b) ((a)>(b)?(b):(a))
#define MAX(a,b) ((a)>(b)?(a):(b))

#define EXTENTCHECK(r1, r2) \
      ( ( ((r1)->x2 < (r2)->x1)) || \
        ( ((r1)->x1 > (r2)->x2)) || \
        ( ((r1)->y2 < (r2)->y1)) || \
        ( ((r1)->y1 > (r2)->y2)) ) \
        ? 0 : 1

/*
/*  update region extents
*/
#define EXTENTS(r,idRect){\
            if((r)->x1 < (idRect)->extents.x1)\
              (idRect)->extents.x1 = (r)->x1;\
            if((r)->y1 < (idRect)->extents.y1)\
              (idRect)->extents.y1 = (r)->y1;\
            if((r)->x2 > (idRect)->extents.x2)\
              (idRect)->extents.x2 = (r)->x2;\
            if((r)->y2 > (idRect)->extents.y2)\
              (idRect)->extents.y2 = (r)->y2;\
        }

/*
 *   Check to see if there is enough memory in the present region.
*/
#define MEMCHECK(reg, rect, firstrect){\
        if ((reg)->numRects >= ((reg)->size - 1)){\
          (firstrect) = (BOX *) Xrealloc \
          ((firstrect), (2 * (sizeof(BOX)) * ((reg)->size)));\
          if ((firstrect) == 0)\
            return(0);\
          (reg)->size *= 2;\
          (rect) = &(firstrect)[(reg)->numRects];\
         }\
       }

/*  this routine checks to see if the previous rectangle is the same
 *  or subsumes the new rectangle to add.
*/

#define CHECK←PREVIOUS(Reg, R, Rx1, Ry1, Rx2, Ry2)\
               ((((Reg)->numRects > 0)&&\
                  ((R-1)->y1 == (Ry1)) &&\
                  ((R-1)->y2 == (Ry2)) &&\
                  ((R-1)->x1 <= (Rx1)) &&\
                  ((R-1)->x2 >= (Rx2)))\
                 ? 0 : 1)

/*  add a rectangle to the given region */
#define ADDRECTNOX(reg, r, rx1, ry1, rx2, ry2){\
            if ((rx1 < rx2) && (ry1 < ry2) &&\
                (CHECK←PREVIOUS((reg), (r), (rx1), (ry1), (rx2), (ry2)))){\
              (r)->x1 = (((rx1) < 0) ? 0 : (rx1));\
              (r)->y1 = (((ry1) < 0) ? 0 : (ry1));\
              (r)->x2 = (((rx2) < 0) ? 0 : (rx2));\
              (r)->y2 = (((ry2) < 0) ? 0 : (ry2));\
              (reg)->numRects++;\
              (r)++;\
            }\
        }

/*
 *    This set of utilities is primarily used for functions needed
 *    by Union.c.  NOT by UnionS.c .
*/

BOX *IndexAddRects();

/*
 *  combinRegs(newReg, reg1, reg2)
 *    if one region is above or below the other.
*/


combineRegs(newReg, reg1, reg2)
    register REGION *newReg;
    REGION *reg1;
    REGION *reg2;
{
    extern REGION *RegionCreate();
    register REGION *tempReg;
    register BOX *rects;
    register BOX *rects1;
    register BOX *rects2;
    register int total;

    rects1 = reg1->rects;
    rects2 = reg2->rects;

    total = reg1->numRects + reg2->numRects;
    tempReg = RegionCreate(NULL, total);
          /*  region 1 is below region 2  */
    if (reg1->extents.y1 > reg2->extents.y1)
    {
        RegionCopy(tempReg, reg2);
        rects = &tempReg->rects[tempReg->numRects];
        total -= tempReg->numRects;
        while (total--)
            *rects++ = *rects1++;
    }
    else
    {
        RegionCopy(tempReg, reg1);
        rects = &tempReg->rects[tempReg->numRects];
        total -= tempReg->numRects;
        while (total--)
            *rects++ = *rects2++;
    }
    tempReg->extents = reg1->extents;
    tempReg->numRects = reg1->numRects + reg2->numRects;
    EXTENTS(&reg2->extents, tempReg);  
    RegionCopy(newReg, tempReg);
/*
  if (newReg->size)
      Xfree(newReg->rects);

  *newReg = *tempReg;
  Xfree(tempReg);
*/
}


/*
 *   TopRects(rects, reg1, reg2)
*/

int 
TopRects(newReg, rects, reg1, size1, reg2, size2, FirstRect)
    register REGION *newReg;
    register BOX *rects;
    register REGION *reg1;
    int size1;
    register REGION *reg2; 
    int size2;
    BOX *FirstRect;
{
    register BOX *tempRects;
    register int num;

    num = 0;
    /*  need to add some rects from region 1 */
    if (reg1->extents.y1 < reg2->extents.y1)
    {
        tempRects = reg1->rects;
        while((tempRects->y1 < reg2->extents.y1) &&
              (tempRects != reg1->rects+size1))
        {
            MEMCHECK(newReg, rects, FirstRect);
            ADDRECTNOX(newReg,rects, tempRects->x1, tempRects->y1, 
		       tempRects->x2, MIN(tempRects->y2, reg2->extents.y1));
            num++;
            tempRects++;
	}
    }
          /*  need to add some rects from region 2 */
    if (reg2->extents.y1 < reg1->extents.y1)
    {
        tempRects = reg2->rects;
        while ((tempRects->y1 < reg1->extents.y1) &&
               (tempRects != reg2->rects+size2))
        {
            MEMCHECK(newReg, rects, FirstRect);
            ADDRECTNOX(newReg, rects, tempRects->x1,tempRects->y1, 
		       tempRects->x2, MIN(tempRects->y2, reg1->extents.y1));
            tempRects++;
            num++;
	}
    }
    return(num);
}

/*
 *  QuickCheck checks to see if it does not have to go through all the
 *  the ugly code for the region call.  It returns 1 if it did all
 *  the work for Union, otherwise 0 - still work to be done.
*/

int 
QuickCheck(newReg, reg1, reg2)
    REGION *newReg, *reg1, *reg2;
{

    /*  if unioning with itself or no rects to union with  */
    if ( (reg1 == reg2) || (!(reg1->numRects)) )
    {
        RegionCopy(newReg, reg2);
        return(1);
    }

       /*   if nothing to union   */
    if (!(reg2->numRects))
    {
        RegionCopy(newReg, reg1);
        return(1);
    }

        /*   could put an extent check to see if add above or below */

    if ((reg1->extents.y1 >= reg2->extents.y2) ||
        (reg2->extents.y1 >= reg1->extents.y2) )
    {
        combineRegs(newReg, reg1, reg2);
        return(1);
    }
    return(0);
}