/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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 <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"

/* Originally S&P, I guess, hacked for 0.99 by Josh MacDonald. */
/* Declare some local functions.
 */
static void   query      (void);
static void   run        (char    *name,
                          int      nparams,
                          GParam  *param,
                          int     *nreturn_vals,
                          GParam **return_vals);
static gint32 load_image (char   *filename);


GPlugInInfo PLUG_IN_INFO =
{
  NULL,    /* init_proc */
  NULL,    /* quit_proc */
  query,   /* query_proc */
  run,     /* run_proc */
};


MAIN ();

static void
query ()
{
  static GParamDef load_args[] =
  {
    { PARAM_INT32, "run_mode", "Interactive, non-interactive" },
    { PARAM_STRING, "filename", "The name of the file to load" },
    { PARAM_STRING, "raw_filename", "The name entered" },
  };
  static GParamDef load_return_vals[] =
  {
    { PARAM_IMAGE, "image", "Output image" },
  };
  static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
  static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
  gimp_install_procedure ("file_xpm_load",
                          "loads files of the xpm file format",
                          "FIXME: write help for xpm_load",
                          "Spencer Kimball & Peter Mattis",
                          "Spencer Kimball & Peter Mattis",
                          "1995-1997",
                          "<Load>/Xpm",
			  NULL,
                          PROC_PLUG_IN,
                          nload_args, nload_return_vals,
                          load_args, load_return_vals);
  gimp_register_magic_load_handler ("file_xpm_load", "xpm", "",
                                    "0,string,/*\\040XPM\\040*/");
}

static void
run (char    *name,
     int      nparams,
     GParam  *param,
     int     *nreturn_vals,
     GParam **return_vals)
{
  static GParam values[2];
  GRunModeType run_mode;
  gint32 image_ID;

  run_mode = param[0].data.d_int32;

  *nreturn_vals = 1;
  *return_vals = values;

  values[0].type = PARAM_STATUS;
  values[0].data.d_status = STATUS_CALLING_ERROR;

  if (strcmp (name, "file_xpm_load") == 0)
    {
      image_ID = load_image (param[1].data.d_string);
      if (image_ID != -1)
	{
	  *nreturn_vals = 2;
	  values[0].data.d_status = STATUS_SUCCESS;
	  values[1].type = PARAM_IMAGE;
	  values[1].data.d_image = image_ID;
	}
      else
	{
	  values[0].data.d_status = STATUS_EXECUTION_ERROR;
	}
    }
  else
    g_assert (FALSE);
}

static gint32
load_image (char *filename)
{
  Display *display;
  XpmImage xpm_image;
  XpmColor *xpm_color;
  GPixelRgn pixel_rgn;
  GDrawable *drawable;
  gint32 image_ID;
  gint32 layer_ID;
  gchar *temp;
  guint *src;
  gint screen;
  guchar *dest, *dest_base;
  guchar *gimp_cmap;
  Colormap colormap;
  gint i, j, tile_height, val, row;
  XColor xcolor;

  temp = malloc (strlen (filename) + 12);
  if (!temp) gimp_quit ();
  sprintf (temp, "Loading %s:", filename);
  gimp_progress_init (temp);
  free (temp);

  display = XOpenDisplay (NULL);
  screen = DefaultScreen (display);
  colormap = DefaultColormap (display, screen);
  XpmReadFileToXpmImage (filename, &xpm_image, NULL);
  gimp_cmap = malloc (sizeof (guchar) * 3 * xpm_image.ncolors);

  for (i = 0, j = 0; i < xpm_image.ncolors; i++)
    {
      xpm_color = &xpm_image.colorTable[i];
      if (xpm_color->c_color)
	{
	  XParseColor (display, colormap, xpm_color->c_color, &xcolor);
	}
      else if (xpm_color->g_color)
	{
	  XParseColor (display, colormap, xpm_color->g_color, &xcolor);
	}
      else if (xpm_color->g4_color)
	{
	  XParseColor (display, colormap, xpm_color->g4_color, &xcolor);
	}
      else if (xpm_color->m_color)
	{
	  XParseColor (display, colormap, xpm_color->m_color, &xcolor);
	}
      gimp_cmap[j++] = xcolor.red >> 8;
      gimp_cmap[j++] = xcolor.green >> 8;
      gimp_cmap[j++] = xcolor.blue >> 8;
    }

  XCloseDisplay (display);

  if (xpm_image.ncolors > 256)
    {
      image_ID = gimp_image_new (xpm_image.width, xpm_image.height, RGB);
      gimp_image_set_filename (image_ID, filename);
      layer_ID = gimp_layer_new (image_ID, "Background",
				 xpm_image.width,
				 xpm_image.height,
				 RGB_IMAGE, 100, NORMAL_MODE);
      gimp_image_add_layer (image_ID, layer_ID, 0);
      drawable = gimp_drawable_get (layer_ID);
      gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);
      tile_height = gimp_tile_height ();
      dest_base = dest = g_new (guchar, 3 * xpm_image.width * tile_height);
      src = xpm_image.data;

      for (i = 0; i < xpm_image.height;)
	{
	  for (dest = dest_base, row = 0;
	       row < tile_height && i < xpm_image.height;
	       i += 1, row += 1)
	    {
	      for (j = 0; j < xpm_image.width; j++)
		{
		  val = *src++ * 3;
		  *dest++ = gimp_cmap[val+0];
		  *dest++ = gimp_cmap[val+1];
		  *dest++ = gimp_cmap[val+2];
		}
	    }
	  gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row, xpm_image.width, row);
	  gimp_progress_update ((double) i / (double) xpm_image.height);
	}
    }
  else
    {
      image_ID = gimp_image_new (xpm_image.width, xpm_image.height, INDEXED);
      gimp_image_set_filename (image_ID, filename);
      layer_ID = gimp_layer_new (image_ID, "Background",
				 xpm_image.width,
				 xpm_image.height,
				 INDEXED_IMAGE, 100, NORMAL_MODE);
      gimp_image_add_layer (image_ID, layer_ID, 0);
      drawable = gimp_drawable_get (layer_ID);
      gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE);
      gimp_image_set_cmap (image_ID,
			   gimp_cmap,
			   xpm_image.ncolors);
      tile_height = gimp_tile_height ();
      dest_base = dest = g_new (guchar, xpm_image.width * tile_height);
      src = xpm_image.data;

      for (i = 0; i < xpm_image.height;)
	{
	  for (dest = dest_base, row = 0;
	       row < tile_height && i < xpm_image.height;
	       i += 1, row += 1)
	    {
	      for (j = 0; j < xpm_image.width; j++)
		*dest++ = *src++;
	    }
	  gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row, xpm_image.width, row);
	  gimp_progress_update ((double) i / (double) xpm_image.height);
	}
    }

  gimp_drawable_flush (drawable);
  gimp_drawable_detach (drawable);

  return image_ID;
}
