/* toon_query.c - query functions
 * -copyright-
#-# 
#-# Copyright (C) 1999-2001  Robin Hogan, 2021-2026 Willem Vermin
#-# 
#-# This program is free software; you can redistribute it and/or modify
#-# it under the terms of the GNU General Public License as published by
#-# the Free Software Foundation; either version 2 of the License, or
#-# (at your option) any later version.
#-# 
#-# This program is distributed in the hope that it will be useful,
#-# but WITHOUT ANY WARRANTY; without even the implied warranty of
#-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#-# GNU General Public License for more details.
#-# 
#-# You should have received a copy of the GNU General Public License
#-# along with this program; if not, write to the Free Software
#-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#-# 
*/
#include <stdio.h>
#include <gtk/gtk.h>
#include "toon.h"
#include "debug.h"
#include "utils.h"

/* QUERY FUNCTIONS */

/* Returns 1 if the toon is blocked in the specified direction, 0 if not 
   blocked and -1 if the direction arguments was out of bounds */
int ToonBlocked(Toon *toon, int direction)
{
   ToonData *data = toon_data[toon->genus] + toon->type;
   if (toon_edge_block) {
      switch (direction) {
	 case TOON_LEFT:
	    if ((toon->x) <= 0)
	       return 1;
	    break;
	 case TOON_RIGHT:
	    if (toon->x+data->width >= toon_display_width)
	       return 1;
	    break;
	 case TOON_UP:
	    if ((toon->y) <= 0)
	       return 1;
	    break;
	 case TOON_DOWN:
	    if (toon->y+data->height >= toon_display_height)
	       return 1;
	    break;
      }
   }
   switch (direction) {
      case TOON_HERE:
	 return (XRectInRegion(toon_windows,toon->x,toon->y,
		  data->width,
		  data->height) 
	       != RectangleOut);
      case TOON_LEFT:
	 return (XRectInRegion(toon_windows,toon->x-1,toon->y,
		  1,data->height) 
	       != RectangleOut);
      case TOON_RIGHT:
	 return (XRectInRegion(toon_windows,toon->x+data->width,
		  toon->y,1,data->height) 
	       != RectangleOut);
      case TOON_UP:
	 return (XRectInRegion(toon_windows,toon->x,toon->y-1,
		  data->width,1)
	       != RectangleOut);
      case TOON_DOWN:
	 return (XRectInRegion(toon_windows,toon->x,
		  toon->y+data->height,
		  data->width, 1)
	       != RectangleOut);
      default:
	 return -1;
   }
}

/* Returns 1 if the toon would be in an occupied area if moved by xoffset
   and yoffset, 0 otherwise */
int ToonOffsetBlocked(Toon *toon, int xoffset, int yoffset)
{
   ToonData *data = toon_data[toon->genus] + toon->type;
   if (toon_edge_block) {
      if (  ((toon->x + xoffset) <= 0)
	    || ((toon->x)+(data->width + xoffset) 
	       >= toon_display_width) 
	    || ((toon->y + yoffset) <= 0 && toon_edge_block != 2) 
	    || ((toon->y)+(data->height + yoffset) 
	       >= toon_display_height) ) {
	 return 1;
      }
   }
   return (XRectInRegion(toon_windows,toon->x + xoffset,toon->y + yoffset,
	    data->width, data->height) 
	 != RectangleOut);
}

/* Check to see if a toon would be squashed instantly if changed to
   certain type, return 1 if squashed, 0 otherwise. Useful to call
   before ToonSetType().  */
int ToonCheckBlocked(Toon *toon, int type, int gravity)
{
   ToonData *data = toon_data[toon->genus] + toon->type;
   ToonData *newdata = toon_data[toon->genus] + type;
   float x = toon->x;
   float y = toon->y;
   switch(gravity) {
      case TOON_HERE:
	 x += (data->width - newdata->width)/2;
	 y += (data->height - newdata->height)/2;
	 break;
      case TOON_DOWN:
	 x += (data->width - newdata->width)/2;
	 y += (data->height - newdata->height);
	 break;
      case TOON_UP:
	 x += (data->width - newdata->width)/2;
	 break;
      case TOON_LEFT:
	 y += (data->height - newdata->height)/2;
	 break;
      case TOON_RIGHT:
	 x += (data->width - newdata->width);
	 y += (data->height - newdata->height)/2;
	 break;
      case TOON_DOWNLEFT:
	 y += (data->height - newdata->height);
	 break;
      case TOON_DOWNRIGHT:
	 x += (data->width - newdata->width);
	 y += (data->height - newdata->height);
	 break;
      case TOON_UPRIGHT:
	 x += (data->width - newdata->width);
	 break;
   } /* Otherwise already in the right position */

   return (XRectInRegion(toon_windows, x, y, newdata->width, newdata->height)
	 != RectangleOut);
}

/* Returns 1 if any change to the top-level window configuration has occurred,
   0 otherwise */
int ToonWindowsMoved()
{
   static double prevtime = 0;
   const double time_win  = 0.05; /* at least time_win seconds between two calls */
   double t = wallclock();
   if (t - prevtime  < time_win)
   {
      return 0;
   }
   prevtime = t;
   P("ToonWindowsMoved %d\n",counter++);

   XEvent event;
   int windows_moved=0;
   while (XPending(toon_display)) 
   {
      XNextEvent(toon_display, &event);
      if (event.type == ConfigureNotify || event.type == MapNotify
	    || event.type == UnmapNotify) 
      {
	 P("windows moved %d\n",counter++);
	 windows_moved=1;
      }
      else if (event.type == ButtonPress) 
      {
	 toon_button_x = ((XButtonEvent *) &event)->x;
	 toon_button_y = ((XButtonEvent *) &event)->y;
      }
   }
   return windows_moved;
}
