#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* Bring in the gd library functions */
#include "gd.h"

/* Bring in standard I/O and string manipulation functions */
#include <stdio.h>
#include <stdlib.h>		/* for atoi() */
#include <string.h>

#ifdef _WIN32
#include <process.h>
int
getpid ()
{
	return _getpid ();
}
#else
#include <unistd.h>		/* for getpid(), unlink() */
#endif
int
main (int argc, char **argv)
{
	FILE *in;
	FILE *out;
	char outFn[20];
	int useStdinStdout = 0;

	/* Declare our image pointer */
	gdImagePtr im = 0;
	int i;
	/* We'll clear 'no' once we know the user has made a
	   reasonable request. */
	int no = 1;
	/* We'll set 'write' once we know the user's request
	   requires that the image be written back to disk. */
	int write = 0;
	/* C programs always get at least one argument; we want at
	   least one more (the image), more in practice. */
	if (argc < 2 || !strcmp (argv[1], "--help")) {
		no = 1;
		goto usage;
	}

	/* The last argument should be the image. Open the file. */
	if (strcmp ("-", argv[argc - 1]) == 0) {
		/* - is synonymous with STDIN */
		useStdinStdout = 1;
		in = stdin;
	} else {
		in = fopen (argv[argc - 1], "rb");
	}
	if (!in) {
		fprintf(stderr, "can't open file %s.\n", argv[argc - 1]);
		exit (1);
	}
	/* Now load the image. */
#ifdef HAVE_LIBPNG
	im = gdImageCreateFromPng (in);
#else
	fprintf(stderr, "No PNG library support.\n");
#endif
	fclose (in);
	/* If the load failed, it must not be a PNG file. */
	if (!im) {
		fprintf (stderr,
		         "Error: %s is not a valid PNG file.\n", argv[argc - 1]);
		exit (1);
	}
	/* Consider each argument in turn. */
	for (i = 1; (i < (argc - 1)); i++) {
		/* -i turns on and off interlacing. */
		if (!strcmp (argv[i], "--help")) {
			/* Every program should use this for help! :) */
			no = 1;
			goto usage;
		} else if (!strcmp (argv[i], "-i")) {
			if (i == (argc - 2)) {
				fprintf(stderr, "-i specified without y or n.\n");
				no = 1;
				goto usage;
			}
			if (!strcmp (argv[i + 1], "y")) {
				/* Set interlace. */
				gdImageInterlace (im, 1);
			} else if (!strcmp (argv[i + 1], "n")) {
				/* Clear interlace. */
				gdImageInterlace (im, 0);
			} else {
				fprintf(stderr, "Error: -i specified without y or n.\n");
				no = 1;
				goto usage;
			}
			i++;
			no = 0;
			write = 1;
		} else if (!strcmp (argv[i], "-t")) {
			/* Set transparent index (or none). */
			int index;
			if (i == (argc - 2)) {
				fprintf (stderr,
				         "Error: -t specified without a color table index.\n");
				no = 1;
				goto usage;
			}
			if (!strcmp (argv[i + 1], "none")) {
				/* -1 means not transparent. */
				gdImageColorTransparent (im, -1);
			} else {
				/* OK, get an integer and set the index. */
				index = atoi (argv[i + 1]);
				gdImageColorTransparent (im, index);
			}
			i++;
			write = 1;
			no = 0;
		} else if (!strcmp (argv[i], "-l")) {
			/* List the colors in the color table. */
			int j;
			if (!im->trueColor) {
				/* Tabs used below. */
				printf ("Index	Red	Green	Blue Alpha\n");
				for (j = 0; (j < gdImageColorsTotal (im)); j++) {
					/* Use access macros to learn colors. */
					printf ("%d	%d	%d	%d	%d\n",
					        j,
					        gdImageRed (im, j),
					        gdImageGreen (im, j),
					        gdImageBlue (im, j), gdImageAlpha (im, j));
				}
			} else {
				printf ("Truecolor image, no palette entries to list.\n");
			}
			no = 0;
		} else if (!strcmp (argv[i], "-d")) {
			/* Output dimensions, etc. */
			int t;
			printf ("Width: %d Height: %d Colors: %d\n",
			        gdImageSX (im), gdImageSY (im), gdImageColorsTotal (im));
			t = gdImageGetTransparent (im);
			if (t != (-1)) {
				printf ("First 100%% transparent index: %d\n", t);
			} else {
				/* -1 means the image is not transparent. */
				printf ("First 100%% transparent index: none\n");
			}
			if (gdImageGetInterlaced (im)) {
				printf ("Interlaced: yes\n");
			} else {
				printf ("Interlaced: no\n");
			}
			no = 0;
		} else if (!strcmp (argv[i], "-a")) {
			/* Alpha channel info -- thanks to Wez Furlong */
			int maxx, maxy, x, y, alpha, pix, nalpha = 0;

			maxx = gdImageSX (im);
			maxy = gdImageSY (im);

			printf ("alpha channel information:\n");

			if (im->trueColor) {
				for (y = 0; y < maxy; y++) {
					for (x = 0; x < maxx; x++) {
						pix = gdImageGetPixel (im, x, y);
						alpha = gdTrueColorGetAlpha (pix);

						if (alpha > gdAlphaOpaque) {
							/* Use access macros to learn colors. */
							printf ("%d	%d	%d	%d\n",
							        gdTrueColorGetRed (pix),
							        gdTrueColorGetGreen (pix),
							        gdTrueColorGetBlue (pix), alpha);
							nalpha++;
						}

					}
				}
			} else
				printf ("NOT a true color image\n");
			no = 0;
			printf ("%d alpha channels\n", nalpha);

		} else {
			fprintf(stderr, "Unknown argument: %s\n", argv[i]);
			break;
		}
	}
usage:
	if (no) {
		/* If the command failed, output an explanation. */
		fprintf (stderr,
		         "Usage: webpng [-i y|n ] [-l] [-t index|none ] [-d] pngname.png\n"
		         "  -i [y|n]   Turns on/off interlace\n"
		         "  -l         Prints the table of color indexes\n"
		         "  -t [index] Set the transparent color to the specified index (0-255 or \"none\")\n"
		         "  -d         Reports the dimensions and other characteristics of the image.\n"
		         "  -a         Prints all alpha channels that are not 100%% opaque.\n"
		         "\n"
		         "If you specify '-' as the input file, stdin/stdout will be used input/output.\n");
	}
	if (write) {
		if (useStdinStdout) {
			out = stdout;
		} else {
			/* Open a temporary file. */

			/* "temp.tmp" is not good temporary filename. */
			sprintf (outFn, "webpng.tmp%d", getpid ());
			out = fopen (outFn, "wb");

			if (!out) {
				fprintf(stderr, "Unable to write to %s -- exiting\n", outFn);
				exit (1);
			}
		}

		/* Write the new PNG. */
#ifdef HAVE_LIBPNG
		gdImagePng (im, out);
#else
		fprintf(stderr, "No PNG library support.\n");
#endif
		if (!useStdinStdout) {
			fclose (out);
			/* Erase the old PNG. */
			unlink (argv[argc - 1]);
			/* Rename the new to the old. */
			if (rename (outFn, argv[argc - 1]) != 0) {
				perror ("rename");
				exit (1);
			}
		}
	}
	/* Delete the image from memory. */
	if (im) {
		gdImageDestroy (im);
	}
	/* All's well that ends well. */
	return 0;
}
