/*  Motti -- a strategy game
    Copyright (C) 1999 Free Software Foundation

    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
*/
/* This file has all the drawing routines */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "xwin.h"
#include "xinit.h"
#include "map.h"

extern Display *display;
extern XrmDatabase DB;
extern XColor *player_col, *occupied_col, *misc_col;
extern int screen_num;

extern Window main_win;
extern Window but_win[NBUTS];
extern Window map_win;

extern GC mapgc, capitalgc, crossgc;
extern Pixmap *att_pix, def_pix, gue_pix;
extern Pixmap d_att_pix, d_def_pix, d_gue_pix;

static int set_fill_color (map_val);
static void draw_map_function (Coord, Coord);

extern void
update_buttons (last_modes, last_attacks)
     char *last_modes, *last_attacks;
{
  char update = 0;

  if (game_map.modes & MODE_ATT)
    {
      if (!(*last_modes & MODE_ATT))
	{
	  /* TODO: This is completely weird!  Why does this crash, if
	     done as:
	     XSetWindowBackgroundPixmap (display, but_win[ATT],
	                                 att_pix[5]);
	     It's almost like gcc itself is buggy!  */
	  Pixmap temp_att_pix;
	  temp_att_pix = (int) att_pix+5;
	  XSetWindowBackgroundPixmap (display, but_win[ATT],
				      temp_att_pix);
	  update |= MODE_ATT;
	}
      else if (game_map.n_att != *last_attacks)
	{
	  Pixmap temp_att_pix;
	  temp_att_pix = (int) att_pix+5-game_map.n_att;
	  XSetWindowBackgroundPixmap (display, but_win[ATT],
				      temp_att_pix);
	  update |= MODE_ATT;
	  *last_attacks = game_map.n_att;
	}
    }
  else if (*last_modes & MODE_ATT)
    {
      XSetWindowBackgroundPixmap (display, but_win[ATT], d_att_pix);
      update |= MODE_ATT;
    }

  if (game_map.modes & MODE_DEF)
    {
      if (!(*last_modes & MODE_DEF))
	{
	  update |= MODE_DEF;
	  XSetWindowBackgroundPixmap (display, but_win[DEF], def_pix);
	}
    }
  else if (*last_modes & MODE_DEF)
    {
      update |= MODE_DEF;
      XSetWindowBackgroundPixmap (display, but_win[DEF], d_def_pix);      
    }

  if (game_map.modes & MODE_GUE)
    {
      if (!(*last_modes & MODE_GUE))
	{
	  update |= MODE_GUE;
	  XSetWindowBackgroundPixmap (display, but_win[GUE], gue_pix);
	}
    }
  else if (*last_modes & MODE_GUE)
    {
      update |= MODE_GUE;
      XSetWindowBackgroundPixmap (display, but_win[GUE], d_gue_pix);      
    }

  if (update & MODE_ATT)
    XClearWindow (display, but_win[ATT]);
  if (update & MODE_DEF)
    XClearWindow (display, but_win[DEF]);
  if (update & MODE_GUE)
    XClearWindow (display, but_win[GUE]);

  *last_modes = game_map.modes;
}

static int
set_fill_color (status)
     map_val status;
{
  int color;
  if (status & MASK_OCCUPIED)
    color = occupied_col[(status & MASK_PLAYER)-1].pixel;
  else if(status != SEA_VAL)
    color = player_col[(status & MASK_PLAYER)-1].pixel;
  else
    /* Sea color is the background color.  */
    return 0;
  XSetForeground (display, mapgc, color);
  return 1;
}
  
static void
draw_map_function (loc, dim)
     Coord loc, dim;
{
  Coord offset;
  short basex;

  basex = loc.x;

  if (dim.x == loc.x)
    dim.x++;
  for (offset.y = loc.y; offset.y <= dim.y; offset.y++)
    {
      map_val last_status, status;
      short lastx;
      lastx = basex;
      last_status = get_map_val (loc);

      /* TODO: This part shows completely bizarre behaviour if dim.y >
	 dim.x!  The test offset.x == dim.x somehow becomes test
	 offset.x == dim.y.  This happens at least on gcc version
	 2.7.2.3.  */
      for (offset.x = loc.x; offset.x <= dim.x; offset.x++)
	{
	  status = get_map_val (offset);
	  if (last_status != status || offset.x == dim.x)
	    {
	      if (set_fill_color (last_status))
		{
		  XFillRectangle (display, map_win, mapgc, lastx *
				  MAPSQUARESIZE, offset.y *
				  MAPSQUARESIZE, (offset.x-lastx) *
				  MAPSQUARESIZE, MAPSQUARESIZE);

		  if (last_status & MASK_CAPITAL)
		    {
		      XFillRectangle (display, map_win, capitalgc,
				      lastx * MAPSQUARESIZE, offset.y
				      * MAPSQUARESIZE,
				      (offset.x-lastx) *
				      MAPSQUARESIZE, MAPSQUARESIZE);
		    }
		  if (last_status & MASK_CROSS)
		    {
		      XFillRectangle (display, map_win, crossgc, lastx
				      * MAPSQUARESIZE, offset.y *
				      MAPSQUARESIZE, (offset.x-lastx)
				      * MAPSQUARESIZE, MAPSQUARESIZE);
		    }
		}
	      lastx = offset.x;
	      last_status = status;
	    }
	}
    }
}

extern void
draw_map (x, y, width, height)
     int x, y, width, height;
{
  Coord loc, dim;

  loc.x = x / MAPSQUARESIZE;
  loc.y = y / MAPSQUARESIZE;
  dim.x = (width % MAPSQUARESIZE ? width / MAPSQUARESIZE + 1 :
	      width / MAPSQUARESIZE)+loc.x; 
  dim.y = (height % MAPSQUARESIZE ? height / MAPSQUARESIZE + 1 :
	       height / MAPSQUARESIZE)+loc.y;

  draw_map_function (loc, dim);
}

extern void
draw_effects (map_events)
     Action map_events;
{
  if ((map_events.type & (EVENT_ENCIRCLEMENT|EVENT_UNOCCUPY))
      || (map_events.type & EVENT_ATT && map_events.type &
	  EVENT_NEWTURN))
    {
      Coord top_left = {0, 0}, down_right;
      down_right.x = game_map.width;
      down_right.y = game_map.height;
      draw_map_function (top_left, down_right);
    }
  else
    {
      register int i;
      for (i = 0; i < map_events.count; i++)
	draw_map_function (map_events.loc[i], map_events.loc[i]);
    }
  free (map_events.loc);
}

extern Coord
win_pos2map_coord (x, y)
     int x, y;
{
  Coord ret_coord;
  ret_coord.x = x / MAPSQUARESIZE;
  ret_coord.y = y / MAPSQUARESIZE;
  return ret_coord;
}
