/* This file contains code for unified image loading from file  

 *  Copyright (c) 1998 Sasha Vasko <sashav@sprintmail.com>  
 * 
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#include "../configure.h"
#include "../include/aftersteplib.h"

#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include <X11/xpm.h>

#include "../include/afterstep.h"

/* our input-output data structures definitions */
#include "../include/loadimg.h"
#include "../include/XImage_utils.h"

/*
   #define LOG1(a)       fprintf( stderr, a );
   #define LOG2(a,b)    fprintf( stderr, a, b );
   #define LOG3(a,b,c)    fprintf( stderr, a, b, c );
   #define LOG4(a,b,c,d)    fprintf( stderr, a, b, c, d );
 */

#define LOG1(a)
#define LOG2(a,b)
#define LOG3(a,b,c)
#define LOG4(a,b,c,d)

/* Here we'll detect image type */
int bReportErrorIfTypeUnknown = 1;
/* we might have a compressed XPM file */
int 
CheckIfCompressed (const char *realfilename)
{
  int len = strlen (realfilename);

  if (len > 3 && strcasecmp (realfilename + len - 3, ".gz") == 0)
    return 1;
  if (len > 2 && strcasecmp (realfilename + len - 2, ".z") == 0)
    return 1;
  return 0;
}

#define FORMAT_TYPE_MAX_SIZE 128
#define FORMAT_TYPE_MIN_SIZE 10

/* return 0 if not detected      */
int 
GetImageType (const char *realfilename)
{
  int fd;
  unsigned char head[FORMAT_TYPE_MAX_SIZE];
  int bytes_in = FORMAT_TYPE_MAX_SIZE;

  if ((fd = open (realfilename, O_RDONLY)) == -1)
    return -1;
  bytes_in = read (fd, head, bytes_in);
  close (fd);

  if (bytes_in > FORMAT_TYPE_MIN_SIZE)
    {
      if (bytes_in < FORMAT_TYPE_MAX_SIZE)
	head[bytes_in] = '\0';
      else
	head[bytes_in - 1] = '\0';

      if (head[0] == 0xff && head[1] == 0xd8 && head[2] == 0xff)
	return F_JPEG;
      else if (head[0] == 'G' && head[1] == 'I' && head[2] == 'F')
	return F_GIF;
      else if (head[0] == head[1] && (head[0] == 'I' || head[0] == 'M'))
	return F_TIFF;
      else if (head[0] == 0xa && head[1] <= 5 && head[2] == 1)
	return F_PCX;
      else if (head[0] == 'B' && head[1] == 'M')
	return F_BMP;
      else if (head[0] == 0 && head[1] == 0 &&
	       head[2] == 2 && head[3] == 0 &&
	       head[4] == 0 && head[5] == 0 &&
	       head[6] == 0 && head[7] == 0)
	return F_TARGA;
      else if (strncmp ((char *) head + 1, "PNG", (size_t) 3) == 0)
	return F_PNG;
      else if (strncmp ((char *) head, "#define", (size_t) 7) == 0)
	return F_XBM;
      else if (strstr (head, "XPM") != NULL)
	return F_XPM;
      else if (CheckIfCompressed (realfilename) != 0)
	return F_XPM;
      /* nothing yet for PCD */

    }
  return F_UNKNOWN;
}



int 
CreateTarget (LImageParams * pParams)
{
  pParams->m_Target = XCreatePixmap (pParams->m_dpy, pParams->m_w,
				     pParams->m_width, pParams->m_height,
				     pParams->m_depth);
  if (pParams->m_Target)
    if ((pParams->m_pImage = CreateXImageAndData (pParams->m_dpy,
						  pParams->m_visual,
						  pParams->m_depth,
						  ZPixmap, 0,
						  pParams->m_width,
						pParams->m_height)) == NULL)
      {
	XFreePixmap (pParams->m_dpy, pParams->m_Target);
	pParams->m_Target = 0;
      }

  return ((pParams->m_pImage == NULL) ? 0 : 1);
}

int 
CreateMask (LImageParams * pParams)
{

  pParams->m_Mask = XCreatePixmap (pParams->m_dpy, pParams->m_w,
				   pParams->m_width, pParams->m_height,
				   MASK_DEPTH);
  if (pParams->m_Mask)
    if ((pParams->m_pMaskImage = XGetImage (pParams->m_dpy, pParams->m_Mask, 0, 0,
					pParams->m_width, pParams->m_height,
					    AllPlanes, ZPixmap)) == NULL)
      {
	XFreePixmap (pParams->m_dpy, pParams->m_Mask);
	pParams->m_Mask = 0;
      }
  LOG1 ("\nLoadImage: CreateMask done.");
  return ((pParams->m_pMaskImage == NULL) ? 0 : 1);
}

void 
XImageToPixmap (LImageParams * pParams, XImage * pImage, Pixmap * pTarget, int depth)
{
  if (pImage == NULL)
    {
      if (*pTarget)
	{
	  LOG1 ("\nLoadImage: XImageToPixmap pImage is NULL.");
	  XFreePixmap (pParams->m_dpy, *pTarget);
	  *pTarget = None;
	}
      return;
    }
  LOG1 ("\nLoadImage: XImageToPixmap pImage is not NULL.");
  if (*pTarget == None)
    *pTarget = XCreatePixmap (pParams->m_dpy, pParams->m_w,
			      pParams->m_width, pParams->m_height,
			      depth);
  if (*pTarget)
    {
      if (pParams->m_gc)
	XFreeGC (pParams->m_dpy, pParams->m_gc);

      if ((pParams->m_gc = XCreateGC (pParams->m_dpy, *pTarget, 0, NULL)) != NULL)
	XPutImage (pParams->m_dpy, *pTarget, pParams->m_gc, pImage,
		   0, 0, 0, 0, pParams->m_width, pParams->m_height);
      else
	{
	  XFreePixmap (pParams->m_dpy, *pTarget);
	  *pTarget = None;
	}
    }
}

extern int LoadJPEGFile (LImageParams * pParams);
extern int LoadXPMFile (LImageParams * pParams);
extern void LoadPNGFile (LImageParams * pParams);

/* this one will load image from file */
Pixmap 
LoadImageEx (LImageParams * pParams)
{
  pParams->m_Target = 0;
  pParams->m_Mask = 0;
  pParams->m_pImage = NULL;
  pParams->m_pMaskImage = NULL;
  pParams->m_gc = 0;
  LOG1 ("\nLoadImage: Checking file format...");
  switch (GetImageType (pParams->m_realfilename))
    {
    case -1:
      fprintf (stderr, "\n LoadImage: cannot read file[%s].", pParams->m_realfilename);
      break;
    case F_XPM:
#ifdef XPM
      LoadXPMFile (pParams);
      LOG1 ("\nLoadImage: XPM format");
#else
      if (bReportErrorIfTypeUnknown)
	{
	  fprintf (stderr, "\n LoadImage: cannot load XPM file [%s]", pParams->m_realfilename);
	  fprintf (stderr, "\n LoadImage: you need to install libXPM v 4.0 or higher, in order to read images of this format.");
	}
#endif /* XPM */
      break;

    case F_JPEG:
#ifdef JPEG
      LoadJPEGFile (pParams);
      LOG1 ("\nLoadImage: JPEG format");
#else
      if (bReportErrorIfTypeUnknown)
	{
	  fprintf (stderr, "\n LoadImage: cannot load JPEG file [%s]", pParams->m_realfilename);
	  fprintf (stderr, "\n LoadImage: you need to install libJPEG v 6.0 or higher, in order to read images of this format.");
	}
#endif /* JPEG */
      break;

    case F_PNG:
#ifdef PNG
      LoadPNGFile (pParams);
      LOG1 ("\nLoadImage: PNG format");
#else
      if (bReportErrorIfTypeUnknown)
	{
	  fprintf (stderr, "\n LoadImage: cannot load PNG file [%s]", pParams->m_realfilename);
	  fprintf (stderr, "\n LoadImage: you need to install libPNG, in order to read images of this format.");
	}
#endif /* PNG */
      break;

    default:
      if (bReportErrorIfTypeUnknown)
	fprintf (stderr, "\n LoadImage: Unknown or unsupported image format.");
      return 0;
    }

  /* here deallocating resources if needed */
  if (pParams->m_pImage)
    {
      LOG1 ("\nLoadImage: Destroying m_pImage..");
      XDestroyImage (pParams->m_pImage);
      pParams->m_pImage = NULL;
      LOG1 (" Done.");
    }

  if (pParams->m_pMaskImage)
    {
      LOG1 ("\nLoadImage: Destroying m_pMaskImage..");
      XDestroyImage (pParams->m_pMaskImage);
      pParams->m_pMaskImage = NULL;
      LOG1 (" Done.");
    }

  if (pParams->m_gc != 0)
    {
      LOG1 ("\nLoadImage: Freeing GC...");
      XFreeGC (pParams->m_dpy, pParams->m_gc);
      pParams->m_gc = 0;
      LOG1 (" Done.");
    }

  return pParams->m_Target;
}
Pixmap 
LoadImageWithMask (Display * dpy, Window w, unsigned long max_colors, const char *realfilename, Pixmap * pMask)
{
  LImageParams Params;
  XWindowAttributes win_attr;

  if (dpy == NULL || w == 0 || realfilename == NULL)
    return 0;
  if (strlen (realfilename) <= 0 || max_colors == 0)
    return 0;

  Params.m_dpy = dpy;
  Params.m_w = w;
  Params.m_max_colors = max_colors;

  XGetWindowAttributes (dpy, w, &win_attr);
  LOG4 ("\nLoadImageWithMask: window size %dx%d, colors num= %lu", win_attr.width, win_attr.height, max_colors);
  Params.m_max_x = win_attr.width;
  Params.m_max_y = win_attr.height;
  Params.m_colormap = win_attr.colormap;
  Params.m_visual = win_attr.visual;
  Params.m_depth = win_attr.depth;

  Params.m_realfilename = realfilename;
  LOG2 ("\nLoadImageWithMask: filename: [%s].", realfilename);
  LoadImageEx (&Params);
  LOG1 ("\nLoadImageWithMask: image loaded, saving mask...");
  if (pMask)
    {
      if (Params.m_Target != None)
	*pMask = Params.m_Mask;
      else
	*pMask = None;
    }
  else if (Params.m_Target != None && Params.m_Mask)
    {
      XFreePixmap (dpy, Params.m_Mask);
      Params.m_Mask = None;
    }
  LOG1 (" Done.");

  return Params.m_Target;
}

/*Pixmap LoadImage( Display *dpy, Window w, unsigned long max_colors, char* realfilename ){} */
