#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <stdio.h>
#include <time.h>

#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/AsciiText.h>

#define OUTPUTLENGTH 100    /* total length of output string */
#define LONGLENGTH 10   /* at least number of bytes per long + 1 */
#define TIMELENGTH 40  /* length for time string */
#define TIMERINTERVAL 5  /* how long to wait with the calculation */

/*
  * Now the prototypings of the functions, used in this program:
  */

void doCalculation(Widget, XKeyEvent *, char **, Cardinal *);
void inputError(void);
void calculateTimerProc(XtPointer , XtInputId *);

char inputTranslationsString[] = "<Key>Return: doCalculation()";

Widget topLevel, top, input, result, quit, info;
XtAppContext appContext;

XtActionsRec globalActions[] = {
      {"doCalculation", doCalculation}
      };


void
quitCallbackProc(w, clientData, callData)
Widget     w;
XtPointer  clientData;
XtPointer  callData;
     {
     fprintf(stderr, "Goodbye\n");
     exit(0);
     }



void
inputError()
     {
     XtVaSetValues(result,
          XtNlabel, "",
          NULL);

     XtVaSetValues(info,
          XtNwidth, 150,
          XtNlabel, "Invalid Input",
          NULL);
     return;
     }


void 
doCalculation(w, event, args, numArgs)
Widget  w;
XKeyEvent *event;
char  **args;
Cardinal *numArgs;
     {
     XtVaSetValues(info,
          XtNlabel, "thinking...",
          NULL);

     XtAppAddTimeOut(appContext, TIMERINTERVAL, calculateTimerProc, NULL);

     XtVaSetValues(result,
          XtNlabel, "",
          NULL);

     return;
     }

void
calculateTimerProc(clientData, id)
XtPointer clientData;
XtIntervalId  *id;
     {
     char *inputVal;
     char output[OUTPUTLENGTH];
     char divisorString[LONGLENGTH];
     char timeString[TIMELENGTH];
     long  value;
     long divisor;
     struct timeval  endTime, startTime;
     struct timezone  dummy;

     XtVaGetValues(input,
          XtNstring, &inputVal,
          NULL);

     if (!sscanf(inputVal, "%ld", &value))
          {
          inputError();
          return;
	  }

     output[0] = '\0';
     gettimeofday(&startTime, &dummy);

     /*
       * Now comes the real calculation...
       */

     for (divisor = 2; divisor <= value; divisor++)
          while (!(value % divisor))
	       {
               value/= divisor;
               sprintf(divisorString, "%ld", divisor);

               if (!output[0])
                    strcpy(output, divisorString);
               else
		    {
                    strcat(output, "*");
                    strcat(output, divisorString);
		    }
	       }

     gettimeofday(&endTime, &dummy);

     sprintf(timeString, "%ld milliseconds", 
		       (endTime.tv_sec-startTime.tv_sec)*1000 + 
		       (endTime.tv_usec-startTime.tv_usec)/1000);

     XtVaSetValues(info, 
              XtNlabel, timeString,
               XtNwidth, 150,
              NULL);

     XtVaSetValues(result, 
              XtNlabel, output,
              NULL);
           
     return;
     }

main(argc, argv)
int argc;
char **argv;
     {
     XtTranslations  inputTranslations;


     topLevel = XtVaAppInitialize(
                &appContext,
                "XCprim",
                NULL, 0,
                &argc, argv,
                NULL,
                NULL);

     top  = XtVaCreateManagedWidget(
	    "top",
	    formWidgetClass,
	    topLevel,
	    NULL);

     input =  XtVaCreateManagedWidget(
             "input",
	     asciiTextWidgetClass,
	     top,
             XtNwidth, 200,
             XtNtype, XawAsciiString,
             XtNeditType, XawtextEdit,
	     NULL);

     result = XtVaCreateManagedWidget(
             "result",
             labelWidgetClass,
             top,
             XtNwidth, 200,
             XtNfromVert, input,
             XtNlabel, "",
             NULL);

     quit = XtVaCreateManagedWidget(
	      "quit",
	      commandWidgetClass,
	      top,
              XtNwidth, 40,
              XtNfromVert, result,
	      NULL);

     info = XtVaCreateManagedWidget(
             "info",
             labelWidgetClass,
             top,
             XtNfromVert, result,
             XtNfromHoriz, quit,
             XtNborderWidth, 0,
             XtNlabel, "",
             XtNwidth, 150,
             NULL);

     XtAddCallback(quit, XtNcallback, quitCallbackProc, NULL);  

     XtAppAddActions(appContext, globalActions, XtNumber(globalActions));
     inputTranslations = XtParseTranslationTable(inputTranslationsString);
     XtOverrideTranslations(input, inputTranslations);

     XtRealizeWidget(topLevel);
 
     XtAppMainLoop(appContext);
     }
