/*****************************************************************************
 *                                                                           *
 *  Copyright (c) 1993, 1994, 1995, Elan Feingold (feingold@zko.dec.com)     *
 *                                                                           *
 *     PERMISSION TO USE, COPY, MODIFY, AND TO DISTRIBUTE THIS SOFTWARE      *
 *     AND ITS DOCUMENTATION FOR ANY PURPOSE IS HEREBY GRANTED WITHOUT       *
 *     FEE, PROVIDED THAT THE ABOVE COPYRIGHT NOTICE APPEAR IN ALL           *
 *     COPIES AND MODIFIED COPIES AND THAT BOTH THAT COPYRIGHT NOTICE AND    *
 *     THIS PERMISSION NOTICE APPEAR IN SUPPORTING DOCUMENTATION.  THERE     *
 *     IS NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR      *
 *     ANY PURPOSE.  THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS       *
 *     OR IMPLIED WARRANTY.                                                  *
 *                                                                           *
 *****************************************************************************/

#include <X11/X.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <stdlib.h>
#include <stdio.h>

#include "riskgame.h"
#include "gui-vars.h"
#include "dice.h"
#include "utils.h"
#include "colormap.h"
#include "client.h"
#include "network.h"
#include "debug.h"
#include "dice.bmp"

static Pixmap   pixAttackDice[6];
static Pixmap   pixDefendDice[6];
static Window   hDiceWindow;
static Int32    iWidth, iHeight;
static Int32    iHorizontalOffset, iVerticalOffset;
static Int32    iBoxWidth, iBoxHeight;
static Int32    iBackgroundColor;
static Int32    piAttackDice[3] = {-1, -1, -1}; 
static Int32    piDefendDice[3] = {-1, -1, -1};

#define DICE_Swap(a, b, temp) { temp=a; a=b; b=temp; }
#define DICE_SPACING 6

/************************************************************************ 
 *  FUNCTION: DICE_Init
 *  HISTORY: 
 *     02.07.94  ESF  Created.
 *     02.10.94  ESF  Started work on coloring dice.
 *     03.03.94  ESF  Changed to calculate offset numbers.
 *     03.05.94  ESF  Changed to use varargs calls.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void DICE_Init(void)
{
  Int32       i;
  Dimension   dimBoxWidth, dimBoxHeight;
  struct
    {
      Byte *pbBits;
    } pDice[] = 
      {
	(Byte *)one_bits,
	(Byte *)two_bits,
	(Byte *)three_bits,
	(Byte *)four_bits,
	(Byte *)five_bits,
	(Byte *)six_bits,
      };

  hDiceWindow = XtWindow(wDiceBox);

  /* Find the width and height of the bitmaps, assuming THEY ARE EQUAL */
  iWidth = one_height; iHeight = one_width;

  /* Get data from the die box widget */
  XtVaGetValues(wDiceBox, 
		XtNwidth, &dimBoxWidth, 
		XtNheight, &dimBoxHeight, 
		XtNbackground, &iBackgroundColor,
		NULL);
  iBoxWidth = dimBoxWidth;
  iBoxHeight = dimBoxHeight;

  iHorizontalOffset = (dimBoxWidth-3*iWidth-2*DICE_SPACING)/2;
  iVerticalOffset   = (dimBoxHeight-2*iWidth-DICE_SPACING)/2;
  
  /* Create the attack dice */
  for (i=0; i!=6; i++)
    pixAttackDice[i] = XCreatePixmapFromBitmapData(hDisplay, hDiceWindow, 
						   (char *)pDice[i].pbBits, 
						   iWidth, iHeight,
						   BlackPixel(hDisplay, 0),
						   COLOR_DieToColor(0), 
						   8);
  
  /* Create the defend dice */
  for (i=0; i!=6; i++)
    pixDefendDice[i] = XCreatePixmapFromBitmapData(hDisplay, hDiceWindow, 
						   (char *)pDice[i].pbBits,
						   iWidth, iHeight,
						   BlackPixel(hDisplay, 0),
						   COLOR_DieToColor(1), 
						   8);
}


/************************************************************************ 
 *  FUNCTION: DICE_Attack
 *  HISTORY: 
 *     02.07.94  ESF  Created.
 *     03.03.94  ESF  Changed to center the dice correctly.
 *     03.03.94  ESF  Adding sorting of the dice and misc. checks.
 *     03.07.94  ESF  Fixed iArmiesWon calculation.
 *     04.11.94  ESF  Added refresh storage, factored out refresh code.
 *     10.30.94  ESF  Added sending message to server, attacker/defender.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 DICE_Attack(Int32 iAttack, Int32 iDefend, 
		  Int32 iAttacker, Int32 iDefender)
{
  Int32        i, j, iTemp;
  Int32        iArmiesWon=0;
  MsgDiceRoll  msgDiceRoll;

  if (iAttack>3 || iAttack<0 || iDefend>2 || iDefend<0)
    {
      (void)UTIL_PopupDialog("Fatal Error", 
			     "DICE: Attack has bogus params...\n",
		       1, "Ok", NULL, NULL);
      (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(iThisClient), 
			     MSG_EXIT, NULL);
      UTIL_ExitProgram(-1);
    }

  /* Erase previous rolls */
  DICE_Hide();

  /* Init dice */
  for (i=0; i!=3; i++)
    piAttackDice[i] = piDefendDice[i] = -1;

  /* Get the attack rolls */
  for (i=0; i!=iAttack; i++)
    piAttackDice[i] = rand() % 6;
  
  /* Get the defense rolls */
  for (i=0; i!=iDefend; i++)
    piDefendDice[i] = rand() % 6;

  /* Sort the dice rolls using bubble sort (at most needs two passes) */
  for (i=0; i!=2; i++)
    for (j=0; j!=2-i; j++)
      {
	if (piAttackDice[j] < piAttackDice[j+1])
	  DICE_Swap(piAttackDice[j], piAttackDice[j+1], iTemp);
	if (piDefendDice[j] < piDefendDice[j+1])
	  DICE_Swap(piDefendDice[j], piDefendDice[j+1], iTemp);
      }

  /* Send a message to the server about the dice roll */
  for (i=0; i!=3; i++)
    {
      msgDiceRoll.pAttackDice[i] = piAttackDice[i];
      msgDiceRoll.pDefendDice[i] = piDefendDice[i];
    }
  msgDiceRoll.iDefendingPlayer = iDefender;
  (void)RISK_SendMessage(CLNT_GetCommLinkOfClient(iThisClient), 
			 MSG_DICEROLL, &msgDiceRoll);

  /* Show the dice */
  DICE_Refresh();

  /* Find out the outcome of the battle */
  for (i=0; i!=MIN(iDefend, iAttack); i++)
    if (piAttackDice[i] > piDefendDice[i])
      iArmiesWon++;
  
  return iArmiesWon; /* For defender, iArmiesWon = iDefend-iArmiesWon */
}


/************************************************************************ 
 *  FUNCTION: DICE_Hide
 *  HISTORY: 
 *     02.07.94  ESF  Stubbed.
 *     03.06.94  ESF  Coded.
 *     04.11.94  ESF  Added invalidation of the dice.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void DICE_Hide(void)
{
  Int32 i;

  /* Delete the contents of the box */
  XSetForeground(hDisplay, hGC, iBackgroundColor);
  XFillRectangle(hDisplay, hDiceWindow, hGC, 0, 0, iBoxWidth, iBoxHeight); 

  /* Invalidate the saved dice */
  for (i=0; i!=3; i++)
    piAttackDice[i] = piDefendDice[i] = -1;
}


/************************************************************************ 
 *  FUNCTION: DICE_Refresh
 *  HISTORY: 
 *     04.11.94  ESF  Created.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void DICE_Refresh(void)
{
  DICE_DrawDice(piAttackDice, piDefendDice);
}


/************************************************************************ 
 *  FUNCTION: 
 *  HISTORY: 
 *     10.30.94  ESF  Moved here and added parameter validation.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void DICE_DrawDice(Int32 *pAttackDice, Int32 *pDefendDice)
{
  Int32 i;

  for (i=0; i!=3; i++)
    {
      /* Save these so that a refresh can see them */
      piAttackDice[i] = pAttackDice[i];
      piDefendDice[i] = pDefendDice[i];

      /* Parameter validation */
      D_Assert(pAttackDice[i]==-1 || (pAttackDice[i]>=0 && pAttackDice[i]<=5),
	       "Dice number is out of range.");
      D_Assert(pDefendDice[i]==-1 || (pDefendDice[i]>=0 && pDefendDice[i]<=5),
	       "Dice number is out of range.");
    }

  /* Show the dice */
  for (i=0; i!=3; i++)
    {
      if (piAttackDice[i] != -1)
	XCopyArea(hDisplay, pixAttackDice[pAttackDice[i]], hDiceWindow, hGC, 
		  0, 0, iWidth, iHeight, 
		  iHorizontalOffset + i*(iWidth+DICE_SPACING), 
		  iVerticalOffset);
      if (piDefendDice[i] != -1)
	XCopyArea(hDisplay, pixDefendDice[pDefendDice[i]], hDiceWindow, hGC, 
		  0, 0, iWidth, iHeight, 
		  iHorizontalOffset + i*(iWidth+DICE_SPACING), 
		  iVerticalOffset + (iHeight+DICE_SPACING));
    }
}
