/*****************************************************************************
 *                                                                           *
 *  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 <X11/Shell.h>

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

unsigned long   plCountryToColor[MAX_COLORS];
Int32           piColorToCountry[MAX_COLORS];
Colormap        cmapColormap = 0;
Color           pWorldColors[MAX_COLORS];
Int32           iNumColors;


/************************************************************************ 
 *  FUNCTION: COLOR_Init
 *  HISTORY: 
 *     09.08.94  ESF  Created.
 *     01.01.95  ESF  Added making the player turn indicator black.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void COLOR_Init(void)
{
  Int32 i;

  /* Set the initial player colors to be black */
  for (i=0; i!=MAX_PLAYERS; i++)
    COLOR_StoreNamedColor("Black", i);

  /* Set the initial player turn indicator to be black */
  COLOR_CopyColor(COLOR_PlayerToColor(0), COLOR_DieToColor(2));
}


/************************************************************************ 
 *  FUNCTION: COLOR_GetColormap
 *  HISTORY: 
 *     09.19.94  ESF  Moved this stuff over here from gui.c.
 *     10.08.94  ESF  Enhanced to reduce flashing with private colormap. 
 *  PURPOSE: 
 *     Selects an appropriate visual if one is available, and then builds
 *   the required X args to pass to any top-level shells.  If no
 *   appropriate visual is available, then exit.  If a usable PseudoColor 
 *   visual exists, but there aren't enough colors available from the
 *   default colormap, then allocate a private colormap for the 
 *   application.  It allocates a colormap and sets up two mappings,
 *   from the index to the colors, and vice-versa.
 *  NOTES: 
 *     This function is specific to Frisk and sets global variables
 *   cmapColormap, hDisplay, etc.  Change it evantually.
 ************************************************************************/
void COLOR_GetColormap(void *pData, Int32 *piNumArgs, Int32 iNeededColors,
		       Int32 argc, CString *argv)
{
  Widget       wDummy;
  Arg         *pVisualArgs = (Arg *)pData; 
  XVisualInfo  Info;
  Int32        i;

  /* Create a dummy top level shell to learn more about the display */
  wDummy = XtAppInitialize(&appContext, "XFrisk", NULL, 0, 
			   &argc, argv, strResources, NULL, 0);
  hDisplay = XtDisplay(wDummy);

  /* See if there is a PseudoColor visual with a depth of 8 bits */
  if (XMatchVisualInfo(hDisplay, DefaultScreen(hDisplay), 
		       8, PseudoColor, &Info))
    {
      /* Save the visual for use in the program -- this shouldn't be here,
       * once all of this gets cleaned up.
       */

      pVisual = Info.visual;
	  
      /* Try to allocate the needed colors from the default colormap.
       * If this fails, then try allocating a private colormap.  If
       * it fails, it is probably because the Display is TrueColor, 
       * or else because there aren't enough free colors in the
       * default colormap.
       */
      
      cmapColormap = DefaultColormap(hDisplay, DefaultScreen(hDisplay));
      if (!XAllocColorCells(hDisplay, cmapColormap, False, NULL, 0, 
			    plCountryToColor, iNeededColors))
	{
 	  XColor    xColor;
	  
	  /* We must use a private colormap */
	  printf("CLIENT: Using a private colormap.\n");
	  cmapColormap = XCreateColormap(hDisplay,
					 RootWindowOfScreen(XtScreen(wDummy)),
					 Info.visual, AllocNone);
	  
  	 
  	  /* Since we only need some of the colors, copy the first bunch
  	   * of colors from the default colormap, in the hope that we'll
  	   * get the window manager colors, so that nasty flashing won't
  	   * occur...
  	   */
  
  	  for (i=0; i!=256 - iNeededColors; i++)
  	    {
  	      xColor.pixel = i;
  	      xColor.flags = DoRed | DoGreen | DoBlue;
  	      XQueryColor(hDisplay, 
  			  XDefaultColormap(hDisplay, DefaultScreen(hDisplay)),
  			  &xColor);
  	      XAllocColor(hDisplay, cmapColormap, &xColor);
	    }
	  
	  /* Allocate colors from this colormap */
	  if (!XAllocColorCells(hDisplay, cmapColormap, False, NULL, 0, 
				plCountryToColor, iNeededColors))
	    {
	      printf("CLIENT: Strange error, could not allocate colors.\n");
	      UTIL_ExitProgram(-1);
	    }
	}
      
      /* Set up mapping from color to country.  With this set up,
       * we have bidirectional mapping, from country to color and from
       * color to country. 
       */
      
      memset(piColorToCountry, (Byte)0, sizeof(Int32)*MAX_COLORS);
      for(i=0; i!=iNeededColors; i++)
	piColorToCountry[plCountryToColor[i]] = i;
    }
  else
    {
      /* Print an error message, deregister the client, and get out! */
      printf("Fatal Error!  Could not find a PseudoColor visual to use,\n"
	     "              or the one found was not deep enough to\n"
	     "              allocate %d colors.\n", iNeededColors);
      UTIL_ExitProgram(0);
    }

  /* Set up the arguments */
  *piNumArgs = 0;
  XtSetArg(pVisualArgs[*piNumArgs], XtNvisual, Info.visual); 
  (*piNumArgs)++;
  XtSetArg(pVisualArgs[*piNumArgs], XtNdepth, Info.depth); 
  (*piNumArgs)++;  
  XtSetArg(pVisualArgs[*piNumArgs], XtNcolormap, cmapColormap);
  (*piNumArgs)++;

  /* We don't need this anymore */
  XtDestroyWidget(wDummy);
}


/************************************************************************ 
 *  FUNCTION: COLOR_
 *  HISTORY: 
 *     05.12.94  ESF  Created.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void COLOR_SetWorldColormap(Color *cmap)
{
  memcpy(pWorldColors, cmap, sizeof(Color)*iNumColors);
}


/************************************************************************ 
 *  FUNCTION: COLOR_
 *  HISTORY: 
 *     05.12.94  ESF  Created.
 *     08.03.94  ESF  Fixed loop bug.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void COLOR_SetWorldColors(void)
{
  XColor   xColor;
  Int32    i;

  /* Now read in the colormap, store it, and setup the screen.
   * Note that color == country here.
   */

  for (i=0; i!=iNumColors; i++)
    {
      xColor.flags = DoRed | DoGreen | DoBlue;
      xColor.pixel = COLOR_CountryToColor(i);
      xColor.red   = pWorldColors[i].r << 8;
      xColor.green = pWorldColors[i].g << 8;
      xColor.blue  = pWorldColors[i].b << 8;

      D_Assert(xColor.pixel<=MAX_COLORS, "Pixel out of range.");
      XStoreColor(hDisplay, cmapColormap, &xColor);
    }
  XFlush(hDisplay);
}


/************************************************************************ 
 *  FUNCTION: COLOR_DieToColor 
 *  HISTORY: 
 *     03.04.94  ESF  Created.
 *     03.05.94  ESF  Fixed bug, wrong offset.
 *     08.28.94  ESF  Fixed bug, wrong argument.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 COLOR_DieToColor(Int32 iDie)
{
  D_Assert(iDie>=0 && iDie<MAX_PLAYERS, 
	   "Wrong range for die color.");
  return (plCountryToColor[NUM_COUNTRIES+2+MAX_PLAYERS+iDie]);
}


/************************************************************************ 
 *  FUNCTION: 
 *  HISTORY: 
 *     02.05.94  ESF  Created.
 *     05.05.94  ESF  Fixed for new colormap scheme.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 COLOR_CountryToColor(Int32 iCountry)
{
  /* It's +2 because of the two reserved colors for ocean and lines */
  D_Assert(iCountry>=0 && iCountry<NUM_COUNTRIES+2,
	   "Country out of range.");
  return(plCountryToColor[iCountry]);
}


/************************************************************************ 
 *  FUNCTION: 
 *  HISTORY: 
 *     02.05.94  ESF  Created.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 COLOR_PlayerToColor(Int32 iPlayer)
{
  D_Assert(iPlayer>=0 && iPlayer<MAX_PLAYERS,
	   "Player out of range.");
  return (plCountryToColor[NUM_COUNTRIES+2+iPlayer]);
}


/************************************************************************ 
 *  FUNCTION: COLOR_ColorCountry
 *  HISTORY: 
 *     02.05.94  ESF  Created.
 *     02.05.94  ESF  Factored out color changing code.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void COLOR_ColorCountry(Int32 iCountry, Int32 iPlayer)
{
  D_Assert(iCountry>=0 && iCountry<NUM_COUNTRIES &&
	   iPlayer>=0 && iPlayer<MAX_PLAYERS,
	   "Bad range for ColorCountry().");
  COLOR_CopyColor(COLOR_PlayerToColor(iPlayer), 
		  COLOR_CountryToColor(iCountry));
}


/************************************************************************ 
 *  FUNCTION: 
 *  HISTORY: 
 *     02.05.94  ESF  Created.
 *     05.05.94  ESF  Fixed for new colormap scheme.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
Int32 COLOR_ColorToCountry(Int32 iColor)
{
  D_Assert(iColor>=0 && iColor<MAX_COLORS,
	   "Color out of range.");
  return(piColorToCountry[iColor]);
}


/************************************************************************ 
 *  FUNCTION: COLOR_CopyColor
 *  HISTORY: 
 *     02.05.94  ESF  Created.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void COLOR_CopyColor(Int32 iSrc, Int32 iDst)
{
  XColor  xColor;

  D_Assert(iSrc>=0 && iSrc<=MAX_COLORS, "Source color out of range.");
  D_Assert(iDst>=0 && iDst<=MAX_COLORS, "Source color out of range.");
  
  xColor.flags = DoRed | DoGreen | DoBlue;
  xColor.pixel = iSrc;
  XQueryColor(hDisplay, cmapColormap, &xColor);

  xColor.pixel = iDst;
  XStoreColor(hDisplay, cmapColormap, &xColor);
  
  XFlush(hDisplay);
}


/************************************************************************ 
 *  FUNCTION: COLOR_StorePlayerColor
 *  HISTORY: 
 *     05.03.94  ESF  Created.
 *  PURPOSE: 
 *  NOTES: 
 ************************************************************************/
void COLOR_StoreNamedColor(CString strPlayerColor, Int32 iPlayer) 
{
  D_Assert(iPlayer>=0 && iPlayer<MAX_PLAYERS,
	   "Player out of range.");

  D_Assert(cmapColormap!=0, "Colormap is not there!");

  XStoreNamedColor(hDisplay, cmapColormap, strPlayerColor,  
		   COLOR_PlayerToColor(iPlayer), 
		   DoRed | DoGreen | DoBlue);
}








