/*  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#include <config.h>

/* This file has all the drawing routines */

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

#include <stdio.h>
#ifdef HAVE_STRING_H
# include <string.h>
#else
# include <strings.h>
#endif
#include <stdlib.h>

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

static void x_update_borders (struct x_info_struct *);
static int set_fill_color (struct x_info_struct *, map_val);

static void
x_update_borders (x_info)
     struct x_info_struct *x_info;
{
  if (x_info->last_sel != game_map.sel_mode
      || (x_info->last_sel && !x_info->active))
    {
      switch (x_info->last_sel)
	{
	case MODE_ATT:
	  XSetWindowBorderWidth (x_info->display, x_info->but_win[ATT], 1);
	  break;
	case MODE_DEF:
	  XSetWindowBorderWidth (x_info->display, x_info->but_win[DEF], 1);
	  break;
	case MODE_GUE:
	  XSetWindowBorderWidth (x_info->display, x_info->but_win[GUE], 1);
	  break;
	}
      if (!x_info->active)
	{
	  x_info->last_sel = 0;
	  return;
	}
      switch (game_map.sel_mode)
	{
	case MODE_ATT:
	  XSetWindowBorderWidth (x_info->display, x_info->but_win[ATT],
				 x_info->db_tab.sel_width);
	  break;
	case MODE_DEF:
	  XSetWindowBorderWidth (x_info->display, x_info->but_win[DEF],
				 x_info->db_tab.sel_width);
	  break;
	case MODE_GUE:
	  XSetWindowBorderWidth (x_info->display, x_info->but_win[GUE],
				 x_info->db_tab.sel_width);
	  break;
	}
      x_info->last_sel = game_map.sel_mode;
    }
}

extern void
x_update_buttons (x_info)
     struct x_info_struct *x_info;
{
  char update;
  update = need_update (&x_info->last_modes);
  if (x_info->uses_def_mode)
    x_update_borders (x_info);

  if (update & MODE_ATT)
    {
      if (game_map.modes & MODE_ATT)
	{
	  if (x_info->active)
	    XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[ATT],
					x_info->att_pix[5 - game_map.n_att]);
	  else
	    XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[ATT],
					x_info->d_att_pix[6 - game_map.n_att]);
	}
      else
	XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[ATT],
				    x_info->d_att_pix[0]);
      XClearWindow (x_info->display, x_info->but_win[ATT]);
    }

  if (update & MODE_DEF)
    {
      if ((game_map.modes & MODE_DEF) && x_info->active)
	XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[DEF],
				    x_info->def_pix);
      else
	XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[DEF],
				    x_info->d_def_pix);
      XClearWindow (x_info->display, x_info->but_win[DEF]);
    }

  if (update & MODE_GUE)
    {
      if ((game_map.modes & MODE_GUE) && x_info->active)
	XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[GUE],
				    x_info->gue_pix);
      else
	XSetWindowBackgroundPixmap (x_info->display, x_info->but_win[GUE],
				    x_info->d_gue_pix);
      XClearWindow (x_info->display, x_info->but_win[GUE]);
    }
}

extern void
x_draw_turn_win (x_info)
     struct x_info_struct *x_info;
{
  unsigned char symbol_n;
  const char *turn_num[] = {"6", "5", "4", "3", "2", "1", "0", "*"};

  XSetBackground (x_info->display, x_info->turngc,
		  x_info->occupied_col[game_map.turn-1].pixel);
  XSetWindowBackground (x_info->display, x_info->turn_win,
			x_info->player_col[game_map.turn-1].pixel);

  if (!(game_map.modes & MODE_ATT))
    symbol_n = 7;
  else
    symbol_n = game_map.n_cross;

  XClearWindow (x_info->display, x_info->turn_win);
  XDrawImageString (x_info->display, x_info->turn_win, x_info->turngc,
		    x_info->turnwin_num_base[symbol_n].x,
		    x_info->turnwin_num_base[symbol_n].y,
		    turn_num[symbol_n], 1);
}

/* TODO: map background should be defined as none instead of the sea
   color, since it's all anyway overdrawn.  Somehow drawing to the map
   with sea color crashes the program.  Weird.  */
static int
set_fill_color (x_info, status)
     struct x_info_struct *x_info;
     map_val status;
{
  int color;
  if (status & MASK_OCCUPIED)
    color = x_info->occupied_col[(status & MASK_PLAYER)-1].pixel;
  else if(status != SEA_VAL)
    color = x_info->player_col[(status & MASK_PLAYER)-1].pixel;
  else
    /* Sea color is the background color.  */
    return 0;
  XSetForeground (x_info->display, x_info->mapgc, color);
  return 1;
}
  
extern void
x_draw_map (x_info, loc, dim)
     struct x_info_struct *x_info;
     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);

      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 (x_info, last_status))
		{
		  XFillRectangle (x_info->display, x_info->map_win,
				  x_info->mapgc, lastx *
				  x_info->db_tab.map_square_size, offset.y *
				  x_info->db_tab.map_square_size,
				  (offset.x-lastx) *
				  x_info->db_tab.map_square_size,
				  x_info->db_tab.map_square_size);

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

extern void
translate_box (x_info, x, y, width, height, loc, dim)
     struct x_info_struct *x_info;
     int x, y, width, height;
     Coord *loc, *dim;
{
  loc->x = x / x_info->db_tab.map_square_size;
  loc->y = y / x_info->db_tab.map_square_size;
  dim->x = (width % x_info->db_tab.map_square_size ? width /
	   x_info->db_tab.map_square_size + 1 :
	   width / x_info->db_tab.map_square_size)+loc->x; 
  dim->y = (height % x_info->db_tab.map_square_size ? height /
	   x_info->db_tab.map_square_size + 1 :
	   height / x_info->db_tab.map_square_size)+loc->y;
}

extern Coord
win_pos2map_coord (x_info, x, y)
     struct x_info_struct *x_info;
     int x, y;
{
  Coord ret_coord;
  ret_coord.x = x / x_info->db_tab.map_square_size;
  ret_coord.y = y / x_info->db_tab.map_square_size;
  return ret_coord;
}

extern void
x_create_end_win (x_info)
     struct x_info_struct *x_info;
{
  int null;
  XCharStruct charstr;
  XGCValues gcvalues = {0};

  x_info->endgame_msg = (char *) my_malloc (sizeof (char) * strlen
					    (x_info->db_tab.end_msg));

  gcvalues.foreground = 0;
  /* This gc is for the game over message.  */
  gcvalues.foreground = x_info->misc_col[end_font_col].pixel;
  gcvalues.background = x_info->misc_col[end_bg_col].pixel;
  gcvalues.font = XLoadFont (x_info->display, x_info->db_tab.end_font);

  if (!gcvalues.font)
    die ("can't load font: %s", x_info->db_tab.cross_left_font);
  x_info->endgamegc = XCreateGC (x_info->display, x_info->main_win,
				 GCBackground | GCForeground | GCFont,
				 &gcvalues);

  /* The player in turn is guaranteed to be winner.  */
  x_info->endmsg_len = sprintf (x_info->endgame_msg, x_info->db_tab.end_msg,
				game_map.turn);
  XQueryTextExtents (x_info->display, gcvalues.font,
		     x_info->endgame_msg, x_info->endmsg_len, &null, &null,
		     &null, &charstr);

  x_info->endmsg_y = charstr.ascent;

  x_info->endgame_win =
    XCreateSimpleWindow (x_info->display, x_info->main_win,
			 x_info->main_win_width/2 - charstr.width/2,
			 x_info->main_win_height/2 - (charstr.ascent -
						      (charstr.ascent +
						       charstr.descent)/2),
			 charstr.width, charstr.ascent + charstr.descent, 1,
			 x_info->misc_col[end_bor_col].pixel,
			 x_info->misc_col[end_bg_col].pixel);
  XSelectInput (x_info->display, x_info->endgame_win,
		ExposureMask | ButtonReleaseMask);
  XMapWindow (x_info->display, x_info->endgame_win);
}

extern void
x_draw_end_win (x_info)
     struct x_info_struct *x_info;
{
  XDrawImageString (x_info->display, x_info->endgame_win,
		    x_info->endgamegc, 0, x_info->endmsg_y,
		    x_info->endgame_msg, x_info->endmsg_len);
}
