/*
** XmgDict.c for  in 
** 
** Made by vianney rancurel
** Login   <vianney@epita.fr>
** 
** Started on  Wed Aug 25 14:15:11 1999 vianney rancurel
** Last update Thu Oct 28 20:22:34 1999 
*/
#include <X11/Intrinsic.h>
#include "XmgI.h"
#include "XmgDict.h"

extern Widget			toplevel;

t_dict				*XmgPixmapDict = NULL;
t_dict				*XmgXFSDict = NULL;
t_dict				*XmgPixelDict = NULL;

/* adds a XFontStruct* to XmgXFSDict.
   Returns 0 if OK. Might return various errors */
t_status			XmgXFSDictAdd(name,xfs)
char				*name;
XFontStruct			*xfs;
{
  t_hash_elt			*he;

  if (he = dict_get(XmgXFSDict,name))
    {
      return 0;
    }
  else
    return (dict_add(XmgXFSDict,
		     name,
		     xfs));
}

/* retrieves a XFontStruct* from XmgXFSDict.
   Returns 0 if OK. Might return various errors */
t_status			XmgXFSDictGet(name,xfs)
char				*name;
XFontStruct			**xfs;
{
  t_hash_elt			*he;

  if (he = dict_get(XmgXFSDict,name))
    {
      (*xfs) = (XFontStruct *)(he->value);
      return (0);
    }
  return (ERR_XMG_NO_ENT);
}

/* adds a Pixel to XmgPixelDict.
   Returns 0 if OK, might return various errors */
t_status			XmgPixelDictAdd(name,cmap,pixel)
char				*name;
Colormap			cmap;
Pixel				pixel;
{
  t_hash_elt			*he;
  t_status			status;
  t_vec				*vec;
  XmgPixelRec			*xpr;
  
  vec = NULL;
  if (he = dict_get(XmgPixelDict,name))
    {
      vec = (t_vec *)(he->value);
      VEC_FOR(vec,XmgPixelRec *x)
	{
	  if (cmap == x->cmap)
	    {
	      return 0;
	    }
	}
      VEC_ENDFOR;
    }
  if (!vec)
    {
      if ((vec = XMG_VEC_ONE_NEW(&status)) == NULL)
	return (status);
      if ((status = dict_add(XmgPixelDict,
			     name,
			     vec)) != 0)
	{
	  vec_delete(vec);
	  return (status);
	}
    }
  if ((xpr = XMG_ALLOC_PROC(sizeof (XmgPixelRec),
			    "Xmg",
			    "XmgPixelDictAdd:xpr",
			    &status)) == NULL)
    return (status);
  xpr->cmap = cmap;
  xpr->pixel = pixel;
  if ((status = vec_add(vec,xpr)) != 0)
    {
      XMG_FREE_PROC(xpr,
		    "Xmg",
		    "*:xpr");
      return (status);
    }
  return (0);
}

/* retrieves a Pixel from XmgPixelDict.
   Returns 0 if OK, might return various errors */
t_status			XmgPixelDictGet(name,cmap,pixel_ret)
char				*name;
int				cmap;
Pixel				*pixel_ret;
{
  t_hash_elt			*he;
  t_status			status;

  if (he = dict_get(XmgPixelDict,name))
    {
      t_vec			*vec;

      vec = (t_vec *)(he->value);
      VEC_FOR(vec,XmgPixelRec *xpr)
	{
	  if (cmap == xpr->cmap)
	    {
	      (*pixel_ret) = xpr->pixel;
	      return (0);
	    }
	}
      VEC_ENDFOR;
    }
  return (ERR_XMG_NO_ENT);
}

/* adds a Pixmap to XmgPixmapDict.
   Returns 0 if OK. Might return various errors */
t_status			XmgPixmapDictAdd(name,depth,pixmap)
char				*name;
int				depth; /* Might not be AnyDepth */
Pixmap				pixmap;
{
  t_hash_elt			*he;
  t_status			status;
  t_vec				*vec;
  XmgPixmapRec			*xpr;

#ifdef NOTDEF
  printf("XmgPixmapDictAdd(%s,%d)\n",name,depth);
#endif
  if (depth == AnyDepth)
    return (ERR_XMG_INVAL);
  vec = NULL;
  if (he = dict_get(XmgPixmapDict,name))
    {
      vec = (t_vec *)(he->value);
      VEC_FOR(vec,XmgPixmapRec *x)
	{
	  if (depth == x->depth)
	    {
	      return 0;
	    }
	}
      VEC_ENDFOR;
    }
  if (!vec)
    {
      if ((vec = XMG_VEC_ONE_NEW(&status)) == NULL)
	return (status);
      if ((status = dict_add(XmgPixmapDict,
			     name,
			     vec)) != 0)
	{
	  vec_delete(vec);
	  return (status);
	}
    }
  if ((xpr = XMG_ALLOC_PROC(sizeof (XmgPixmapRec),
			    "Xmg",
			    "XmgPixmapDictAdd:xpr",
			    &status)) == NULL)
    return (status);
  xpr->depth = depth;
  xpr->pixmap = pixmap;
  if ((status = vec_add(vec,xpr)) != 0)
    {
      XMG_FREE_PROC(xpr,
		    "Xmg",
		    "*:xpr");
      return (status);
    }
  return (0);
}

/* retrieves a Pixmap from XmgPixmapDict.
   If depth equals AnyDepth, then the deepest pixmap is choosen.
   Returns 0 if OK. Might return various errors */
t_status			XmgPixmapDictGet(name,depth,pixmap_ret)
char				*name;
int				depth; /* Might be AnyDepth */
Pixmap				*pixmap_ret;
{
  t_hash_elt			*he;
  t_status			status;
  int				best_depth;
  Pixmap			best_pixmap;

#ifdef NOTDEF
  printf("XmgPixmapDictGet(%s,%d)\n",name,depth);
#endif
  best_depth = 0;
  if (he = dict_get(XmgPixmapDict,name))
    {
      t_vec			*vec;

      vec = (t_vec *)(he->value);
      VEC_FOR(vec,XmgPixmapRec *xpr)
	{
	  if (depth == xpr->depth)
	    {
	      (*pixmap_ret) = xpr->pixmap;
	      return (0);
	    }
	  if (xpr->depth > best_depth)
	    {
	      best_depth = xpr->depth;
	      best_pixmap = xpr->pixmap;
	    }
	}
      VEC_ENDFOR;
      if (depth == AnyDepth && VEC_COUNT(vec) > 0)
	{
	  (*pixmap_ret) = best_pixmap;
	  return (0);
	}
    }
  return (ERR_XMG_NI);
}

/* force the named Pixmap from XmgPixmapDict to match depth.
   It recreates a new pixmap if needed. 
   Returns 0 if OK. Might return various errors */
t_status			XmgPixmapDictForceGet(display,
						      name,
						      depth,
						      pixmap_ret)
Display				*display;
char				*name;
int				depth;
Pixmap				*pixmap_ret;
{
  t_status			status;
  Window			root;
  int				x;
  int				y;
  unsigned int			width;
  unsigned int			height;
  unsigned int			border_width;
  unsigned int			real_depth;
  Pixmap			new_pixmap;
  
#ifdef NOTDEF
  printf("XmgPixmapDictForceGet(%s,%d)\n",name,depth);
#endif
  if ((status = XmgPixmapDictGet(name,
				 depth,
				 pixmap_ret)) == 0)
    return (0);
  if (depth == AnyDepth)
    return (ERR_XMG_NO_ENT);
  if ((status = XmgPixmapDictGet(name,
				 AnyDepth,
				 pixmap_ret)) != 0)
    return (status);
  XGetGeometry(display,
	       *pixmap_ret,
	       &root,
	       &x,
	       &y,
	       &width,
	       &height,
	       &border_width,
	       &real_depth);
  if (real_depth == 1)
    {
      GC			gc;
      XGCValues			xgcv;

      new_pixmap = XCreatePixmap(display,
				 DefaultRootWindow(display),
				 width,
				 height,
				 depth);
      xgcv.foreground = BlackPixel(display,
				   DefaultScreen(display));
      xgcv.background = WhitePixel(display,
				   DefaultScreen(display));
      gc = XCreateGC(display,
		     DefaultRootWindow(display),
		     GCForeground|GCBackground,
		     &xgcv);
      XCopyPlane(display,
		 *pixmap_ret,
		 new_pixmap,
		 gc,
		 0,
		 0,
		 width,
		 height,
		 0,
		 0,
		 1);
      XFreeGC(display,gc);
      if ((status = XmgPixmapDictAdd(name,
				     depth,
				     new_pixmap)) != 0)
	{
	  XFreePixmap(display,new_pixmap);
	  return (status);
	}
      (*pixmap_ret) = new_pixmap;
      return (0);
    }
  return (ERR_XMG_NO_ENT);
}

t_status			XmgDestroyPixmapDictWalk(he,unused)
t_hash_elt			*he;
VOID_PTR			unused;
{
  t_vec				*vec;

  vec = (t_vec *)(he->value);
  VEC_FOR(vec,XmgPixmapRec *xpr)
    {
      XFreePixmap(XtDisplay(toplevel),
		  xpr->pixmap);
      XMG_FREE_PROC(xpr,
		    "Xmg",
		    "*:xpr");
    }
  VEC_ENDFOR;
  vec_delete(vec);
  return (0);
}

t_status			XmgDestroyXFSDictWalk(he,unused)
t_hash_elt			*he;
VOID_PTR			unused;
{
  XFreeFont(XtDisplay(toplevel),
	    (XFontStruct *)(he->value));
  return (0);
}

t_status			XmgDestroyPixelDictWalk(he,unused)
t_hash_elt			*he;
VOID_PTR			unused;
{
  t_vec				*vec;

  vec = (t_vec *)(he->value);
  VEC_FOR(vec,XmgPixelRec *xpr)
    {
      XFreeColors(XtDisplay(toplevel),
		  xpr->cmap,
		  &(xpr->pixel),
		  1,
		  0);
      XMG_FREE_PROC(xpr,
		    "Xmg",
		    "*:xpr");
    }
  VEC_ENDFOR;
  vec_delete(vec);
  return (0);
}

/* destroys XmgPixmapDict, XmgXFSDict and XmgPixelDict freeing appropriate
 X resources (Pixmaps, XFontStructs and Pixels) */
VOID_FUNC			XmgDestroy(VOID_DECL)
{
  t_status			status;

  status = dict_walk(XmgPixmapDict,
		     (t_dict_walk_proc)XmgDestroyPixmapDictWalk,
		     NULL);
  dict_delete(XmgPixmapDict);
  status = dict_walk(XmgXFSDict,
		     (t_dict_walk_proc)XmgDestroyXFSDictWalk,
		     NULL);
  dict_delete(XmgXFSDict);
  status = dict_walk(XmgPixelDict,
		     (t_dict_walk_proc)XmgDestroyPixelDictWalk,
		     NULL);
  dict_delete(XmgPixelDict);
}

t_status			XmgPixmapDictStatusWalk(he,unused)
t_hash_elt			*he;
VOID_PTR			unused;
{
  t_vec				*vec;

  vec = (t_vec *)(he->value);
  fprintf(stderr,"%s\n",he->key);
  VEC_FOR(vec,XmgPixmapRec *xpr)
    {
      fprintf(stderr,"\t%d %x\n",xpr->depth,xpr->pixmap);
    }
  VEC_ENDFOR;
  return (0);
}
