/* +-------------------------------------------------------------------+ */
/* | Copyright 1992, 1993, David Koblas (koblas@netcom.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 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/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <stdio.h>
#include <fcntl.h>
#ifndef NOSTDHDRS
#include <unistd.h>
#endif

#define DEFINE_GLOBAL
#include "xpaint.h"
#include "misc.h"

#include "XPaintIcon.xpm"

static char *appDefaults[] = {
#include "XPaint.ad.h"
	NULL
};

typedef struct {
	String	visualType;
	String	size;
	String	help;
	String	rcFile;
	Boolean	popped;
} AppInfo;

static AppInfo	appInfo;

static XtResource resources[] = {
	{ "visualType", "VisualType", XtRString, sizeof(String),
	   XtOffset(AppInfo*, visualType), XtRImmediate, (XtPointer)"default" },
	{ "size", "Size", XtRString, sizeof(String),
	   XtOffset(AppInfo*, size), XtRImmediate, (XtPointer)"640x480" },
	{ "rcFile", "RcFile", XtRString, sizeof(String),
	   XtOffset(AppInfo*, rcFile), XtRImmediate, (XtPointer)NULL },
	{ "help", "Help", XtRString, sizeof(String),
	   XtOffset(AppInfo*, help), XtRImmediate, (XtPointer)NULL },
	{ "popped", "Popped", XtRBoolean, sizeof(Boolean),
	   XtOffset(AppInfo*, popped), XtRImmediate, (XtPointer)False },
};

static XrmOptionDescRec options[] = {
	{ "-24",     ".visualType", XrmoptionNoArg,  (XtPointer)"true24" },
	{ "-12",     ".visualType", XrmoptionNoArg,  (XtPointer)"cmap12" },
	{ "-size",   ".size",       XrmoptionSepArg, (XtPointer)NULL },
	{ "-rcFile", ".rcFile",     XrmoptionSepArg, (XtPointer)NULL },
	{ "-popped", ".popped",     XrmoptionNoArg,  (XtPointer)"True" },
	{ "-help",   ".help",       XrmoptionNoArg,  (XtPointer)"command" },
	{ "+help",   ".help",       XrmoptionSepArg, (XtPointer)NULL },
};

void BrushInit(Widget);
void HelpInit(Widget);
void OperationInit(Widget);
void InitTypeConverters();

/*
**  Public query functions for application defaults
*/

void GetDefaultWH(int *w, int *h)
{
	int		x, y;
	unsigned int	width, height;

	XParseGeometry(appInfo.size, &x, &y, &width, &height);
	*w = width;
	*h = height;
}

char *GetDefaultRC()
{
	return appInfo.rcFile;
}

/*
**  Create a nice icon image for XPaint...
*/
void SetIconImage(Widget w, Boolean flag)
{
	static Pixmap	icon = None;
	static int	iconW = 1, iconH = 1;
	Window		iconWindow;
	XWMHints	wmHints;
	Screen		*screen = XtScreen(w);
	Display		*dpy = XtDisplay(w);

#if 0
	int		i, count;
	XIconSize	*list;

	/*
	**  Should use this information
	*/

	XGetIconSizes(dpy, RootWindowOfScreen(screen), &list, &count);
	printf("got %d sizes\n", count);
	for (i = 0; i < count; i++) {
		printf("#%d:  min = %d,%d  max = %d,%d  inc = %d,%d\n", i, 
			list[i].min_width, list[i].min_height,
			list[i].max_width, list[i].max_height,
			list[i].width_inc, list[i].height_inc);
	}
	XFree((XPointer)list);
#endif

	/*
	**  Build the XPaint icon
	*/
	iconWindow = XCreateSimpleWindow(dpy, RootWindowOfScreen(screen),
						0, 0, /* x, y */
						iconW, iconH, 0,
						BlackPixelOfScreen(screen),
						BlackPixelOfScreen(screen));
	if (icon == None) {
		XpmCreatePixmapFromData(dpy, iconWindow,
				XPaintIcon_xpm, &icon, NULL, NULL);
		GetPixmapWHD(dpy, icon, &iconW, &iconH, NULL);
		XResizeWindow(dpy, iconWindow, iconW, iconH);
	}

	XSetWindowBackgroundPixmap(dpy, iconWindow, icon);

	XtVaSetValues(w, XtNiconWindow, iconWindow, NULL);
}


/*
**  The rest of main
*/
extern void HelpTextOutput(FILE*, char *);

static void usage(char *prog, char *msg)
{
	if (msg)
		fprintf(stderr,"%s\n", msg);
	fprintf(stderr,"Usage: %s\n", prog);
	HelpTextOutput(stderr, appInfo.help == NULL ? "command" : appInfo.help);
	exit(1);
}

typedef struct {
	XtWorkProcId	id;
	Widget		toplevel;
	int		nfiles;
	int		pos;
	char		**files;
} LocalInfo;

extern void StateSetBusy(Boolean);
extern char *RWGetMsg();

static void workProc(LocalInfo *l)
{
	extern void	GraphicOpenFile(Widget, char *, void *);
	extern void	*ReadMagic(char *);
	char		*file;
	void		*v;

	if (l == NULL || l->id == None)
		return;
	XtRemoveWorkProc(l->id);
	l->id = None;

	file = l->files[l->pos];

	StateSetBusy(True);
	if ((v = (void *)ReadMagic(file)) != NULL) {
		GraphicOpenFile(l->toplevel, file, v);
	} else {
		Notice(l->toplevel, "Unable to open input file \"%s\"\n	%s", file, RWGetMsg());
	}
	StateSetBusy(False);

	if (++l->pos == l->nfiles) {
		XtFree((XtPointer)l->files);
		XtFree((XtPointer)l);
	} else {
		l->id = XtAppAddWorkProc(XtWidgetToApplicationContext(l->toplevel), (XtWorkProc)workProc, (XtPointer)l);
	}
}

void main(int argc, char *argv[])
{
	Pixmap		icon;
	XtAppContext	app;
	Display		*dpy;
	Widget		toplevel;
	int		i;
	XEvent		event;
	Arg		args[5];
	int		nargs = 0;
	XrmDatabase	rdb;
	char		*rmType;
	XrmValue	rvalue;
	Boolean		isIcon;

	InitTypeConverters();

	/*
	**  Create the application context
	*/
	toplevel = XtAppInitialize(&Global.appContext, "XPaint", 
				options, XtNumber(options), &argc, argv, 
				appDefaults, args, nargs);

	XtGetApplicationResources(toplevel, (XtPointer)&appInfo,
				resources, XtNumber(resources), NULL, 0);

	rdb = XtDatabase(XtDisplay(toplevel));

	if (appInfo.help != NULL)
		usage(argv[0],NULL);

	if (strcmp(appInfo.visualType, "default") != 0) {
		char	*cp = appInfo.visualType;
		if (strncmp(cp, "cmap", 4) == 0) {
			XrmPutStringResource(&rdb, "Canvas*visual", "PseudoColor");
			cp+=4;
		} else if (strncmp(cp, "true", 4) == 0) {
			XrmPutStringResource(&rdb, "Canvas*visual", "TrueColor");
			cp+=4;
		} else if (strncmp(cp, "gray", 4) == 0) {
			XrmPutStringResource(&rdb, "Canvas*visual", "StaticGray");
			cp+=4;
		} else {
			usage(argv[0], "bad visual type specification");
		}
		if (*cp != '\0') 
			XrmPutStringResource(&rdb, "Canvas*depth", cp);
	}
	if (argc != 1 && argv[1][0] == '-')
		usage(argv[0], "Invalid option");

	/*
	**  A little initilization
	*/
	Global.region.image = NULL;
	Global.region.cmap  = None;
	Global.region.width = 0;
	Global.region.height= 0;
	Global.region.pix   = None;
	Global.region.mask  = None;

	/*
	**
	*/
	XtVaGetValues(toplevel, XtNiconic, &isIcon, NULL);
	if (isIcon) 
		XrmPutStringResource(&rdb, "Canvas.iconic", "on");

	/*
	**  Now build and construct the widgets
	*/
	Global.timeToDie = False;
	app = XtWidgetToApplicationContext(toplevel);
	dpy = Global.display = XtDisplay(toplevel);

	/*
	**  Call the initializers
	*/

	OperationInit(toplevel);

	/*
	**  A few rogue initaliziers
	*/
	BrushInit(toplevel);
	HelpInit(toplevel);

	SetIconImage(toplevel, True);

	/*
	**  Realize it  (doesn't hurt)
	*/
	XtRealizeWidget(toplevel);


	/*
	**  Now open any file on the command line
	*/
	if (argc != 1) {
		LocalInfo	*l = XtNew(LocalInfo);
		l->pos = 0;
		l->toplevel = toplevel;
		l->nfiles = argc - 1;
		l->files = (char **)XtCalloc(argc, sizeof(char*));
		for (i = 1; i < argc; i++)
			l->files[i-1] = argv[i];
		l->id = XtAppAddWorkProc(app, (XtWorkProc)workProc, (XtPointer)l);
	} else if (appInfo.popped) {
		/*
		**  If nothing is comming up, bring up a blank canvas
		*/
		GraphicCreate(toplevel, 0);
	}

	/*
	**  MainLoop
	*/
	do {
		XtAppNextEvent(app, &event);
		if (event.type == ButtonPress || event.type == ButtonRelease)
			Global.currentTime = event.xbutton.time;
		XtDispatchEvent(&event);
	} while (!Global.timeToDie);
}
