#include <stdio.h>
#include <Xmt/Xmt.h>
#include <Xmt/MsgLine.h>
#include <Xmt/Layout.h>
#include <Xmt/Menu.h>
#include <Xmt/Procedures.h>
#include <Xm/Label.h>  /* for XmIsLabel() */
#include <Xm/LabelG.h> /* for XmIsLabelGadget() */

static Widget msgline, toplevel;
static char filename[200];

/*
 * Get an input string from the message line or a dialog 
 * depending on the use_msgline argument.
 */
static Boolean GetString(String prompt, char *buffer, int buffer_len,
                         Boolean use_msgline)
{
    Boolean status;
    if (use_msgline) {
        XmtMsgLinePush(msgline);
        XmtMsgLineSet(msgline, prompt);
        XmtMsgLineSetInput(msgline, buffer);
        if (XmtMsgLineGetString(msgline, buffer, buffer_len))
            status = True;
        else
            status = False;
        XmtMsgLinePop(msgline, XmtMsgLineNow);
    }
    else
        status = XmtAskForString(toplevel, NULL, prompt,
                                 buffer, buffer_len, NULL);
    return status;
}


/*
 * This function returns True if the event e could have triggered
 * the accelerator for the Motif button widget w.
 */
static Boolean IsAcceleratorEvent(Widget w, XEvent *e)
{
    String accelerator;
    char c, lc, uc;
    KeySym key;
    Modifiers mods;

    /* if not a key event, it can't be an accelerator */
    if ((e->type != KeyPress) && (e->type != KeyRelease)) return False;

    /* only subclasses of XmLabel have menu accelerators */
    if (!XmIsLabel(w) && !XmIsLabelGadget(w)) return False;

    /* get the last character of the accelerator string */
    XtVaGetValues(w, XmNaccelerator, &accelerator, NULL);
    c = accelerator[strlen(accelerator)-1];
    XtFree(accelerator);
    lc = tolower(c);
    uc = toupper(c);
    
    /* get the keysym from the event */
/*    key = XtGetActionKeysym(e, NULL);  */

    XtTranslateKeycode(e->xany.display, e->xkey.keycode,
		       e->xkey.state, &mods, &key);

    key = key & 0xFF;

    /* X protocol says keysym encoding matches ASCII encoding
     * so we can compare them directly here if we don't care
     * about internationalization.
     */
    if ((key == lc) || (key == uc)) return True;
    else return False;
}

/*
 * Display an error message in a dialog box or the message line
 * depending on the value of the errorInMsgLine app resource.
 */
static void DisplayError(String msg)
{
    static Boolean use_msgline;
    static Boolean got_resource = False;
    static XtResource error_resource[] = {
        {"errorInMsgLine", "ErrorInMsgLine", XtRBoolean,
         sizeof(Boolean), 0, XtRImmediate, (XtPointer) False}
    };

    /* query the app resource first time we are called */
    if (!got_resource) {
        got_resource = True;
        XtGetApplicationResources(toplevel, &use_msgline,
                                  error_resource, 1,
                                  NULL, 0);
    }

    /* display the message depending on the app resource */
    if (use_msgline) {
        XmtMsgLinePush(msgline);
        XmtMsgLineSet(msgline, "ERROR: ");
        XmtMsgLineAppend(msgline, msg);
        XmtMsgLinePop(msgline, XmtMsgLineOnAction);
    }
    else
        XmtDisplayError(toplevel, NULL, msg);
}

/*
 * The SaveAs callback procedure, registered on an menu button and
 * invoked either directly or through an accelerator
 */
static void SaveAs(Widget w, XtPointer tag, XtPointer call_data)
{
    XmPushButtonCallbackStruct *data = (XmPushButtonCallbackStruct *)call_data;
    Boolean status;

    /*
     * Get the filename to save as.
     * Use message line if invoked as an accelerator, otherwise a dialog.
     * Check for user cancellation.
     */
    if (!GetString("Save As: ", filename, 200,
                   IsAcceleratorEvent(w, data->event)))
        return;

    /* Provide feedback that we're saving the file using cursor and msgline */
    XmtDisplayBusyCursor(toplevel);
    XmtMsgLinePush(msgline);
    XmtMsgLineClear(msgline, XmtMsgLineNow);
    XmtMsgLinePrintf(msgline, "Saving %s...", filename);

    /* save the file */
/*    status = save_file(filename); */
    sleep(1);
    {
	extern long random();
	status = random()%2;
    }

    /*
     * if successful, give simple feedback in the message line, otherwise
     * display a warning in a dialog box or message line, depending on
     * an application resource.
     */
    if (status) { /* successfully saved */
        XmtMsgLineAppend(msgline, "Done.");
        XmtMsgLinePop(msgline, XmtMsgLineOnAction);
    }
    else {  /* error while saving */
        extern int errno;
        extern char *sys_errlist[]; /* or use strerror() */

        XmtMsgLinePop(msgline, XmtMsgLineNow);
        DisplayError(sys_errlist[random()%20]);
    }

    /* finally, restore the cursor */
    XmtDisplayDefaultCursor(toplevel);
}

int main(argc,argv)
int argc;
char **argv;
{
    XtAppContext app;

    toplevel = XtAppInitialize(&app, "Msgline", NULL, 0, &argc, argv,
			       NULL, NULL, 0);

    XmtRegisterCallbackProcedure("SaveAs", SaveAs, XmtRCallbackUnused);
    XmtRegisterCallbackConverter();
    XmtRegisterMenuItemsConverter();
    XmtVaRegisterWidgetConstructors("XmtLayout", XmtCreateLayout,
				    "XmtMenu", XmtCreateMenubar,
				    "XmtMsgLine", XmtCreateMsgLine,
				    NULL);
    XmtCreateQueryChildren(toplevel, "msgline", &msgline, NULL);

    XtRealizeWidget(toplevel);
    XtAppMainLoop(app);
}
