/* 
 * Motif Tools Library
 * $Id: mockup.c,v 1.13 1994/06/17 21:13:13 david Exp $
 * 
 * Written by David Flanagan.
 * Copyright (c) 1992, 1993 by Dovetail Systems.
 * All Rights Reserved.  See the file COPYRIGHT for details.
 * This is not free software.  See the file SHAREWARE for details.
 * There is no warranty for this software.  See the file WARRANTY for details.
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <Xmt/Xmt.h>
#include <Xmt/Create.h>
#include <Xmt/Converters.h>
#include <Xmt/Procedures.h>
#include <Xmt/Layout.h>
#include <Xmt/WidgetType.h>
#include <Xmt/Include.h>

#include <Xmt/WorkingBox.h>

#include <X11/IntrinsicP.h>
#ifdef X11R5
#include <X11/Xmu/Editres.h>
#endif

#ifndef X_NOT_STDC_ENV
#include <stdlib.h>
#else
extern char *getenv();
#endif

#ifndef X_NOT_POSIX
#include <unistd.h>
#else
extern int access();
extern void perror();
#endif

#define mockup_width 66
#define mockup_height 36
static  unsigned char mockup_bits[] = {
   0x00, 0xf8, 0x01, 0xfc, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x81,
   0xff, 0x03, 0xf0, 0x7f, 0x00, 0x00, 0xfc, 0xff, 0xe0, 0xff, 0x07, 0xfc,
   0xff, 0x00, 0x00, 0xff, 0xff, 0xfa, 0xff, 0x0f, 0xfe, 0xff, 0x01, 0x00,
   0xff, 0xff, 0xfd, 0xff, 0x8f, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0xfe,
   0xff, 0xcf, 0xff, 0xff, 0x07, 0x00, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff,
   0xff, 0x0b, 0x00, 0xf8, 0xff, 0xdf, 0xff, 0xff, 0xd5, 0xff, 0x17, 0x00,
   0xf8, 0xff, 0xab, 0xff, 0xff, 0xaa, 0xff, 0x0b, 0x00, 0xe0, 0xff, 0x55,
   0xff, 0x5f, 0xd5, 0xff, 0x17, 0x00, 0xe0, 0xff, 0x2a, 0xfc, 0xaf, 0x8a,
   0xff, 0x0b, 0x00, 0xe0, 0x7f, 0x05, 0xfc, 0x5f, 0x81, 0xff, 0x15, 0x00,
   0xf0, 0xff, 0x02, 0xfe, 0xaf, 0x80, 0xff, 0x0b, 0x00, 0xf0, 0x7f, 0x01,
   0xfe, 0x5f, 0x80, 0xff, 0x15, 0x00, 0xf0, 0xff, 0x02, 0xfe, 0x2f, 0xc0,
   0xff, 0x0a, 0x00, 0xf0, 0x7f, 0x01, 0xfe, 0x5f, 0xc0, 0xff, 0x05, 0x00,
   0xf0, 0xff, 0x02, 0xfe, 0x2f, 0xc0, 0xff, 0x0a, 0x00, 0xf8, 0x7f, 0x01,
   0xff, 0x57, 0xc0, 0xff, 0x05, 0x00, 0xf8, 0xbf, 0x00, 0xff, 0x2f, 0xe0,
   0xff, 0x02, 0x00, 0xf8, 0x7f, 0x01, 0xff, 0x17, 0xe0, 0x7f, 0x05, 0x00,
   0xf8, 0xbf, 0x00, 0xff, 0x2f, 0xe0, 0xff, 0x02, 0x00, 0xf8, 0x7f, 0x01,
   0xff, 0x17, 0xe0, 0x7f, 0x05, 0x00, 0xfc, 0xbf, 0x80, 0xff, 0x2b, 0xf0,
   0xff, 0x02, 0x00, 0xfc, 0x5f, 0x80, 0xff, 0x17, 0xf0, 0x7f, 0x01, 0x00,
   0xfc, 0xbf, 0x80, 0xff, 0x0b, 0xf0, 0xff, 0x02, 0x00, 0xfc, 0x5f, 0x80,
   0xff, 0x17, 0xf0, 0x7f, 0x01, 0x00, 0xfc, 0xbf, 0x80, 0xff, 0x0b, 0xf8,
   0xff, 0x02, 0x00, 0xfe, 0x5f, 0xc0, 0xff, 0x15, 0xf8, 0xff, 0x61, 0x00,
   0xfe, 0xbf, 0xc0, 0xff, 0x0b, 0xf8, 0xff, 0x7f, 0x00, 0xfe, 0x5f, 0xc0,
   0xff, 0x05, 0xf0, 0xff, 0x7f, 0x00, 0xfe, 0x2f, 0xc0, 0xff, 0x0b, 0xf0,
   0xff, 0x7f, 0x02, 0xfe, 0x5f, 0xc0, 0xff, 0x05, 0xe0, 0xff, 0x57, 0x01,
   0xff, 0x2f, 0xc0, 0xff, 0x0a, 0x80, 0xff, 0xaa, 0x02, 0x50, 0x55, 0x00,
   0x54, 0x05, 0x00, 0x55, 0x55, 0x01, 0xa0, 0x2a, 0x00, 0xaa, 0x0a, 0x00,
   0xaa, 0x2a, 0x00, 0x50, 0x15, 0x00, 0x54, 0x05, 0x00, 0x54, 0x01, 0x00};

static Widget working_shell, working_box;

#if NeedFunctionPrototypes
static void display_working_box(Widget toplevel, char *filename)
#else
static void display_working_box(toplevel, filename)
Widget toplevel;
char *filename;
#endif 
{
    static char working_font_list[] = "*-helvetica-bold-r-*-*-*-180-*";
    char working_message[200];

    working_shell = XtVaCreateWidget("_xmt_working_shell",
				     topLevelShellWidgetClass,
				     toplevel,
				     XtNtitle, "mockup",
				     XtNsaveUnder, True,
				     NULL);

    sprintf(working_message, "Mocking up %s\nPlease wait...", filename);


    XmtRegisterXbmData("_xmt_mockup_image",
		       mockup_bits, NULL, mockup_width, mockup_height,
		       0,0);

    working_box = XtVaCreateManagedWidget("_xmt_working_box",
		      xmtWorkingBoxWidgetClass, working_shell,
		      XmtNmessage, working_message,
		      XtVaTypedArg, XmtNfontList, XtRString,
			working_font_list, sizeof(working_font_list),
		      XtVaTypedArg, XmtNicon, XtRString,
			 "_xmt_mockup_image",
			 sizeof("_xmt_mockup_image")+1,
		      XmtNshowScale, False,
		      XmtNshowButton, False,
		      NULL);

    XtRealizeWidget(working_shell);
    XtPopup(working_shell, XtGrabNone);

    /*
     * we rely upon a special case in XmtWaitUntilMapped that will
     * do the right thing here for TopLevelShell.  A TransientShell
     * or XmDialogShell wouldn't work because the app shell isn't realized
     * yet.
     */
    XmtWaitUntilMapped(working_shell);

}

#if NeedFunctionPrototypes
static void destroy_working_box(Widget toplevel)
#else
static void destroy_working_box(toplevel)
Widget toplevel;
#endif 
{
    XtPopdown(working_shell);
    XtDestroyWidget(working_shell);
}


#ifndef VMS

main(argc, argv)
int argc;
char* argv[];
{   
    XtAppContext app;
    String appname, appclass;
    String filename;
    int i;
    Widget toplevel;
    String oldpath, path;
    String fallbacks[4];
    char fallback1[500];
    char fallback2[500];
    char buf[500];

    /*
     * The first non-option arg is app name.  Second, if any, is filename.
     * We assume all Xt and Xmt options begin with a - or + and are followed
     * by an associated value.  This is not actually always true.
     */
    appname = NULL;
    filename = NULL;
    for(i=1; i < argc; i++) {
	if ((argv[i][0] != '-') && (argv[i][0] != '+')) {
	    appname = argv[i];
	    break;
	}
	else i++;
    }

    if (appname == NULL) {
	fprintf(stderr, "%s\n",
		"Usage: mockup app-name [resource-file] [options]");
	exit(1);
    }

    for(i++; i < argc; i++) {
	if ((argv[i][0] != '-') && (argv[i][0] != '+')) {
	    filename = argv[i];
	    break;
	}
	else i++;
    }

    /* fake our our application name */
    argv[0] = appname;

    /* figure out class from name */
    appclass = XtNewString(appname);
    appclass[0] = toupper(appclass[0]);
    if (appclass[0] == 'X') appclass[1] = toupper(appclass[1]);

    /*
     * if there was no filename explictly specified, use XmtFindFile
     * to find one based on the app-name.
     */
    if (!filename) {
	sprintf(buf, "%s:%s.ad:%s:%s.ad:app-defaults/%s:app-defaults/%s",
		appname, appname, appclass, appclass, appclass, appname);
	filename = XtFindFile(buf, NULL, 0, NULL);
    }

    /*
     * if still no filename, or if the filename doesn't exist or
     * is not readable, then fail with an error message.
     */
    if (!filename || !filename[0]) {
	fprintf(stderr,
		"mockup: no resource file found for application '%s'\n",
		appname);
	exit(1);
    }
    if (access(filename, R_OK) == -1) {
	sprintf(buf, "mockup: %s", filename);
	perror(buf);
	exit(1);
    }

    /*
     * set the XENVIRONMENT variable to the resource file
     */
    sprintf(buf, "XENVIRONMENT=%s", filename);
    putenv(buf);

    /*
     * Now set some fallback resources to notify the user if the app-defaults
     * file was malformed and didn't have valid xmtChildren resource.
     * Using fallback resources is the only way we can know what happens.
     */
    sprintf(fallback1, "%s.xmtChildren: XmPushButton _mockup;", appname);
    sprintf(fallback2, "*_mockup.labelString: Error: \\n no `%s.xmtChildren' resource \\n in `%s'. ",
	    appname, filename);

    fallbacks[0] = fallback1;
    fallbacks[1] = fallback2;
    fallbacks[2] = "*_mockup.activateCallback: exit(0);";
    fallbacks[3] = NULL;


    /*
     * and finally go create the root shell widget.
     * This call also parses Xmt command-line options,
     * registers type converters, and reads Xmt app resources.
     */
    toplevel = XmtInitialize (&app, appclass, NULL, 0,
			      &argc, argv, fallbacks, NULL, 0);
    
    /*
     * if any args remain, it is a syntax error; issue a warning.
     */
    for(i=1; i < argc; i++)
	if ((argv[i] != appname) && (argv[i] != filename))
	    XmtWarningMsg("mockup", "badarg",
			  "unknown argument '%s'.",
			  argv[i]);
    
    /* register all known Motif and Xmt widgets and procedures */
    XmtRegisterAll();
    
#ifdef X11R5
    XtAddEventHandler(toplevel, 0, True,
		      (XtEventHandler)_XEditResCheckMessages, NULL);
#endif    

    display_working_box(toplevel, filename);

    XmtCreateChildren(toplevel);
    XtRealizeWidget(toplevel);
    XmtDisplayDefaultCursor(toplevel);

    destroy_working_box(toplevel);

    XtAppMainLoop(app);
}

#else /*  VMS  */

#include <descrip.h>
#include <lnmdef.h>

typedef struct _itmlist {
   short blen, code;
   void *baddr, *rladdr;
} itmlist;

static $DESCRIPTOR(table, "LNM$PROCESS");
static $DESCRIPTOR(user, "DECW$USER_DEFAULTS");
static $DESCRIPTOR(sys, "DECW$SYSTEM_DEFAULTS");

static void set_logicals(void)
{
   String nl = "NL:";
   itmlist user_items[] = {
   {sizeof(nl)-1, LNM$_STRING, nl, NULL},
   {0, 0, 0, 0},
   };
   itmlist sys_items[] = {
   {sizeof(nl)-1, LNM$_STRING, nl, NULL},
   {0, 0, 0, 0},
   };
   
   sys$crelnm(0, &table, &user, 0, &user_items);
   sys$crelnm(0, &table, &sys, 0, &sys_items);
}

static void delete_logicals(void)
{
    sys$dellnm(&table, &user, 0);
    sys$dellnm(&table, &sys, 0);
}

static char *curdir(void)
{
    char buf[256], *p;
    $DESCRIPTOR(cur, buf);
    short len;
    
    sys$setddir(0, &len, &cur);
    buf[len] = '\0';
    p = XtMalloc(10+len);
    strcpy(p, "sys$disk:");
    strcat(p, buf);
    return p;
}

main(argc, argv)
int argc;
char* argv[];
{   
    XtAppContext app;
    String appname, appclass;
    String filename;
    int i;
    Widget toplevel;

    String merge_file, c;
    char fallbackdb[512];
    XrmDatabase db, newdb;
    static void set_logicals(void);
    static void delete_logicals(void);
    static char *curdir(void);

    /*
     * The first non-option arg is app name.  Second, if any, is filename.
     * We assume all Xt and Xmt options begin with a - or + and are followed
     * by an associated value.  This is not actually always true.
     */
    appname = NULL;
    filename = NULL;
    for(i=1; i < argc; i++) {
	if ((argv[i][0] != '-') && (argv[i][0] != '+')) {
	    appname = argv[i];
	    break;
	}
	else i++;
    }

    if (appname == NULL) {
	fprintf(stderr, "%s\n",
		"Usage: mockup app-name [resource-file] [options]");
	exit(1);
    }

    for(i++; i < argc; i++) {
	if ((argv[i][0] != '-') && (argv[i][0] != '+')) {
	    filename = argv[i];
	    break;
	}
	else i++;
    }

    /* fake our our application name */
    argv[0] = appname;

    /* figure out class from name */
    appclass = XtNewString(appname);
    appclass[0] = toupper(appclass[0]);
    if (appclass[0] == 'X') appclass[1] = toupper(appclass[1]);

    /*
     * app names are uppercase on VMS
     */
    for(c = appname; *c; c++)*c = toupper(*c);
    /*
     * Ensure that DECwindows can't find the app defaults file, even if there
     * is one.
     */
    set_logicals();
    /*
     * Set up a fallback resource database string to use if we can't find
     * the specified file. We can't use the fallback resources, because
     * merging in a new database doesn't seem to override it. I don't know why
     * not.
     */
    strcpy(fallbackdb, appname);
    strcat(fallbackdb, ".xmtChildren: XmPushButton button;\n");
    strcat(fallbackdb, "*button.activateCallback: exit(0);\n");
    if(filename){
	strcat(fallbackdb, "*button.labelString: Error: mockup: Resource file '");
	strcat(fallbackdb, filename);
	strcat(fallbackdb, "' not found.");
    } else {
	strcat(fallbackdb, "*button.labelString: Error: mockup: No resource file found for application name '");
	strcat(fallbackdb, appname);
	strcat(fallbackdb, "'.");
    }
    
    /*
     * and finally go create the root shell widget
     */
    toplevel = XtAppInitialize (&app, appclass, NULL, 0,
				&argc, argv, NULL, NULL, 0);
    
    /*
     * Delete our logical names, find the user's file, and merge it into the
     * resource database. If we can't find it, create a resource database from
     * the fallbackdb string and merge it in instead. We should get the same
     * behavior as on unix. Note the where argument to XmtFindFile. This is a
     * disgusting hack supported by that routine for mockup's exclusive use in
     * this one call. See the comments before the VMS version of XmtFindFile in
     * findfile.c for more info.
     */
    delete_logicals();
    db = XmtDatabaseOfWidget(toplevel);
    newdb = NULL;
    merge_file = XmtFindFile(toplevel, "app-defaults", filename, ".dat",
        curdir(), "%R%N:%R%N%S:%R%T/%N:%R%T/%N%S", (XmtSearchEverywhere)+1);
    if(merge_file)newdb = XrmGetFileDatabase(merge_file);
    else newdb = XrmGetStringDatabase(fallbackdb);
    if(newdb)XrmMergeDatabases(newdb, &db);
    if(merge_file)XtFree(merge_file);

    /*
     * parse Xmt-specific command-line options
     */
    XmtParseCommandLine(toplevel, &argc, argv);

    /*
     * if any args remain, it is a syntax error; issue a warning.
     */
    for(i=1; i < argc; i++)
	if ((argv[i] != appname) && (argv[i] != filename))
	    XmtWarningMsg("mockup", "badarg",
			  "unknown argument '%s'.",
			  argv[i]);

    
    /* register all Motif and Xmt widgets and procedures and converters */
    XmtRegisterAll();

    /*
     * and do Xmt-specific initialization
      */
    XmtInitializeApplicationShell(toplevel, NULL, 0);
    
#ifdef X11R5
    XtAddEventHandler(toplevel, 0, True,
		      (XtEventHandler)_XEditResCheckMessages, NULL);
#endif    

    display_working_box(toplevel, filename);

    XmtCreateChildren(toplevel);
    XtRealizeWidget(toplevel);
    XmtDisplayDefaultCursor(toplevel);

    destroy_working_box(toplevel);

    XtAppMainLoop(app);
}

#endif /* VMS */
