#include "evas_common.h"

#if 0
Regionbuf *
evas_common_regionbuf_new(int w, int h)
{
   Regionbuf *rb;

   rb = calloc(1, sizeof(Regionbuf) + (h * sizeof(Regionspan)));
   if (!rb) return NULL;
   rb->spans = (Regionspan **)(rb + sizeof(Regionbuf));
   rb->w = w;
   rb->h = h;
   return rb;
}

void
evas_common_regionbuf_free(Regionbuf *rb)
{
   evas_common_regionbuf_clear(rb);
   free(rb);
}

void
evas_common_regionbuf_clear(Regionbuf *rb)
{
   int y;

   for (y = 0; y < rb->h; y++)
     {
	while (rb->spans[y])
	  {
	     Regionspan *span;

	     span = rb->spans[y];
	     rb->spans[y] = eina_inlist_remove(rb->spans[y], rb->spans[y]);
	     free(span);
	  }
     }
}

void
evas_common_regionbuf_span_add(Regionbuf *rb, int x1, int x2, int y)
{
   Regionspan *span, *span2, *nspan, *sp_start, *sp_stop;

   /* abort if outside */
   if ((y < 0) ||
       (y >= rb->h) ||
       (x2 < 0) ||
       (x1 >= rb->w)) return;
   /* clip to horiz bounds */
   if (x1 < 0) x1 = 0;
   if (x2 < (rb->w - 1)) x2 = rb->w - 1;
   sp_start = NULL;
   sp_stop = NULL;
   EINA_INLIST_FOREACH(rb->spans[y], span)
     {
	nspan = (Regionspan *)(EINA_INLIST_GET(span))->next;
	/* we dont know what t do with the span yet */
	if (!sp_start)
	  {
	     /* if new span starts before or on this span or just after
	      * with no gap */
	     if (x1 <= (span->x2 + 1))
	       sp_start = span;
	     /* if there is no next span */
	     if (!nspan)
	       {
		  sp_stop = span;
		  break;
	       }
	     /* if new span ends before the next span starts with a gap of
	      * 1 pixel (or more) */
	     else if (x2 < (nspan->x1 - 1))
	       {
		  sp_stop = span;
		  break;
	       }
	  }
	/* we already know it already starts before or in sp_start */
	else
	  {
	     /* there is no span after this one, so this has to be the stop */
	     if (!nspan)
	       {
		  sp_stop = span;
		  break;
	       }
	     /* if new span ends before the next span starts with a gap of
	      * 1 pixel (or more) */
	     else if (x2 < (nspan->x1 - 1))
	       {
		  sp_stop = span;
		  break;
	       }
	  }
     }
   /* sp_start is where the new span starts in or before */
   /* sp_stop is where the new span stops in or after */
   if ((sp_start) && (sp_stop))
     {
	/* same start and stop */
	if (sp_start == sp_stop)
	  {
	     if (x2 < (sp_start->x1 - 1))
	       {
		  span2 = calloc(1, sizeof(Regionspan));
		  span2->x1 = x1;
		  span2->x2 = x2;
		  rb->spans[y] = eina_inlist_prepend_relative(rb->spans[y], span2, sp_start);
		  return;
	       }
	     if (x1 < sp_start->x1)
	       sp_start->x1 = x1;
	     if (x2 > sp_start->x2)
	       sp_start->x2 = x2;
	     return;
	  }
	else
	  {
	     Eina_Inlist *l;

	     /* remove all nodes after sp_start and before_sp_stop because
	      * the new  */
	     for (l = (EINA_INLIST_GET(sp_start))->next; l != EINA_INLIST_GET(sp_stop);)
	       {
		  span = (Regionspan *)l;
		  l = l->next;
		  rb->spans[y] = eina_inlist_remove(rb->spans[y], span);
		  free(span);
	       }
	     /* remove the end span */
	     rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_stop);
	     /* if the new span is before the start span - extend */
	     if (x1 < sp_start->x1)
	       sp_start->x1 = x1;
	     /* if it goes beyond the stop span - extend stop span */
	     if (x2 > sp_stop->x2)
	       sp_stop->x2 = x2;
	     /* extend start span to stop span */
	     sp_start->x2 = sp_stop->x2;
	     /* don't need stop span anymore */
	     free(sp_stop);
	     return;
	  }
     }
   /* no start AND stop... just append */
   span2 = calloc(1, sizeof(Regionspan));
   span2->x1 = x1;
   span2->x2 = x2;
   rb->spans[y] = eina_inlist_append(rb->spans[y], span2);
}

void
evas_common_regionbuf_span_del(Regionbuf *rb, int x1, int x2, int y)
{
   /* FIXME: del span */
   Regionspan *span, *span2, *nspan, *sp_start, *sp_stop;

   /* abort if outside */
   if ((y < 0) ||
       (y >= rb->h) ||
       (x2 < 0) ||
       (x1 >= rb->w)) return;
   /* clip to horiz bounds */
   if (x1 < 0) x1 = 0;
   if (x2 < (rb->w - 1)) x2 = rb->w - 1;
   sp_start = NULL;
   sp_stop = NULL;
   EINA_INLIST_FOREACH(rb->spans[y], span)
     {
	nspan = (Regionspan *)(EINA_INLIST_GET(l))->next;
	/* we dont know what t do with the span yet */
	if (!sp_start)
	  {
	     /* if new span starts before or on this span or just after
	      * with no gap */
	     if (x1 <= (span->x2))
	       sp_start = span;
	     /* if there is no next span */
	     if (!nspan)
	       {
		  sp_stop = span;
		  break;
	       }
	     /* if new span ends before the next span starts with a gap of
	      * 1 pixel (or more) */
	     else if (x2 < nspan->x1)
	       {
		  sp_stop = span;
		  break;
	       }
	  }
	/* we already know it already starts before or in sp_start */
	else
	  {
	     /* there is no span after this one, so this has to be the stop */
	     if (!nspan)
	       {
		  sp_stop = span;
		  break;
	       }
	     /* if new span ends before the next span starts with a gap of
	      * 1 pixel (or more) */
	     else if (x2 < nspan->x1)
	       {
		  sp_stop = span;
		  break;
	       }
	  }
     }
   /* sp_start is where the new span starts in or before */
   /* sp_stop is where the new span stops in or after */
   if ((sp_start) && (sp_stop))
     {
	/* same start and stop */
	if (sp_start == sp_stop)
	  {
	     /* if it ends before this the span start starts... return */
	     if (x2 < sp_start->x1)
	       return;
	     /* it starts on or before this span */
	     else if (x1 <= sp_start->x1)
	       {
		  /* right edge is within the span */
		  if (x2 < sp_start->x2)
		    {
		       sp_start->x2 = x2;
		       return;
		    }
		  else
		    {
		       rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_start);
		       return;
		    }
	       }
	     /* it ends on or after the end of this span */
	     else if (x2 >= sp_start->x2)
	       {
		  /* it starts after the start */
		  if (x1 > sp_start->x1)
		    {
		       sp_start->x1 = x1;
		       return;
		    }
		  /* remove it all */
		  else
		    {
		       rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_start);
		       return;
		    }
		  return;
	       }
	     /* this breaks the span into 2 */
	     else
	       {
		  span2 = calloc(1, sizeof(Regionspan));
		  span2->x1 = sp_start->x1;
		  span2->x2 = x1 - 1;
		  rb->spans[y] = eina_inlist_prepend_relative(rb->spans[y], span2, sp_start);
		  sp_start->x1 = x2 + 1;
		  return;
	       }
	  }
	else
	  {
	     Eina_Inlist *l;

	     /* remove all nodes after sp_start and before_sp_stop because
	      * the new  */
	     for (l = (EINA_INLIST_GET(sp_start))->next; l != EINA_INLIST_GET(sp_stop);)
	       {
		  span = (Regionspan *)l;
		  l = l->next;
		  rb->spans[y] = eina_inlist_remove(rb->spans[y], span);
		  free(span);
	       }
	     /* all of the start span is cut out */
	     if (x1 <= sp_start->x1)
	       {
		  rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_start);
		  free(sp_start);
	       }
	     /* chup it off at the new span start */
	     else
	       sp_start->x2 = x1 - 1;
	     /* all of the end span is cut out */
	     if (x2 >= sp_stop->x2)
	       {
		  rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_stop);
		  free(sp_stop);
	       }
	     /* chop it up at the end */
	     else
	       sp_stop->x1 = x2 + 1;
	     return;
	  }
     }
}

Tilebuf_Rect *
evas_common_regionbuf_rects_get(Regionbuf *rb)
{
   Tilebuf_Rect *rects = NULL, *r;
   int y;

   /* FIXME: take spans, make rects */
   for (y = 0; y < rb->h; y++)
     {
	Regionspan *sp_start;
	Eina_Inlist *l, *ll;

	for (l = EINA_INLIST_GET(rb->spans[y]); l;)
	  {
	     Regionspan *span;
	     int yy;

	     sp_start = (Regionspan *)l;
	     l = l->next;
	     rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_start);
	     for (yy = y + 1; yy < rb->h; yy++)
	       {
		  int match = 0;

		  for (ll = EINA_INLIST_GET(rb->spans[yy]); ll;)
		    {
		       span = (Regionspan *)ll;
		       ll = ll->next;
		       if (span->x1 == sp_start->x1)
			 {
			    if ((span->x1 != sp_start->x1) ||
				(span->x2 != sp_start->x2))
			      {
				 goto coallate;
			      }
			    match = 1;
			    rb->spans[yy] = eina_inlist_remove(rb->spans[yy], span);
			    free(span);
			 }
		    }
		  if (!match) goto coallate;
	       }
	     coallate:
	     r = calloc(1, sizeof(Tilebuf_Rect));
	     r->x = sp_start->x1;
	     r->y = y;
	     r->w = sp_start->x2 - sp_start->x1 + 1;
	     r->h = yy - y;
	     rects = eina_inlist_append(rects, r);
	     free(sp_start);
	  }
     }
   evas_common_regionbuf_clear(rb);
   return rects;
}
#endif
