/*-------------------------------------*
 | File: MAINLOOP.c - MLO 900131 V1.00 |
 | Here is RPN main loop               |
 *-------------------------------------*/

#include "rpn.h"
#include "proto.h"
#include "mainloop.h"
#include <ctype.h>

extern struct Window *Wrpn;
extern struct Window *Wreg;
extern struct Gadget *pIG;
extern struct StringInfo *pIS;
extern Boolean MathError;
extern int LastCode;
extern char InBuf[];
extern double stack[];

static Boolean readInput(void);

void mainloop(void)
{/*-------------------------------------*
  | Wait for an Intuition message, then |
  | calls the appropriate processor     |
  *-------------------------------------*/

  struct IntuiMessage *pIM;
  struct Gadget *addr;
  ULONG class;
  USHORT code;
  Boolean numInput = False;

/*--------------------------------------*
 | Waiting for an Intuition message ... |
 *--------------------------------------*/
 
  FOREVER {
    Wait(1 << Wrpn->UserPort->mp_SigBit);
    while ( (pIM = (struct IntuiMessage *) GetMsg(Wrpn->UserPort))
             != NULL) {
              
/*-----------------------------------------------------------*
 | Cleanup of the error flag, then look at the message: pick |
 | up type, code and address, and reply as soon as possible. |
 *-----------------------------------------------------------*/

      MathError = False;
      class = pIM->Class;
      code = pIM->Code;
      addr = (struct Gadget *) pIM->IAddress;
      ReplyMsg(pIM);
      
      switch (class) {

/*----------------------*
 | Request to terminate |
 *----------------------*/

        case CLOSEWINDOW:
          return;

/*-------------------------------*
 | Menu; if a number was input   |
 | read it, then call menupick() |
 *-------------------------------*/

        case MENUPICK:
          if (numInput) {
            numInput = False;
            if (!readInput())   break;
          }
          menupick(code);
          break;

/*---------------------------------------------------*
 | A Gadget was hit. If it is the Input Field, input |
 | a number; else, if a number was input read it.    |
 *---------------------------------------------------*/

        case GADGETDOWN:
          if (addr == pIG) {
            numInput = True;
          } else if (numInput) {
            numInput = False;
            readInput();
          }
          break;

/*--------------------------------------------------------*
 | A Gadget was released. If a number was input, read it; |
 | then perform the appropriate action calling keypick()  |
 *--------------------------------------------------------*/

        case GADGETUP:
          if (numInput) {
            numInput = False;
            if (!readInput())   break;
          }
          keypick(addr->GadgetID);
          break;

/*-----------------------------------------------------*
 | A keyboard key was hit; of course the Input string  |
 | gadget is NOT selected. If this key is suitable for |
 | numerical input, activate the input field gadget.   |
 *-----------------------------------------------------*/

        case VANILLAKEY:
          if (isdigit(code)   ||   code == '.'   ||   code == 'e'   ||
                code == 'E'   ||   code == '+'   ||   code == '-') {
            InBuf[0] = code;
            InBuf[1] = '\0';
            pIS->BufferPos = 1;
            pIS->DispPos = 0;
            if (ActivateGadget(pIG, Wrpn, NULL)) {
              RefreshGList(pIG, Wrpn, NULL, 1);
              numInput = True;
            }
          }
          break;

        default:
          fprintf(stderr, "Unknown message for Wrpn, class 0x%X\n", class);
          break;
      }
    }
  }
}

static Boolean readInput(void)
{/*-----------------------------------------------------*
  | Local function: read a number from the input field, |
  | and display a requester if some error is detected.  |
  *-----------------------------------------------------*/

  double x;
  char dummy;

  struct IntuiText invalid = {
    BLUE_PEN, WHITE_PEN, JAM2, INV_X, INV_Y, NULL,
    "Invalid numeric input:", NULL
  };

  struct IntuiText field = {
    BLUE_PEN, WHITE_PEN, JAM2, FIE_X, FIE_Y, NULL,
    InBuf, NULL
  };

  struct IntuiText ok = {
    BLUE_PEN, WHITE_PEN, JAM2, OK_X, OK_Y, NULL,
    "OK", NULL
  };

  if (sscanf(InBuf, "%lg%c", &x, &dummy) == 1) {
    impEnter();
    stack[0] = x;
    outStk();
    return True;
  } else {
    invalid.NextText = &field;
    AutoRequest(Wrpn, &invalid, NULL, &ok, NULL, NULL, INV_W, INV_H);
    return False;
  }
}
