/*---------------------------------*
 | File: MENU.c - MLO 900131 V1.00 |
 | Procedures for menu handling    |
 *---------------------------------*/

#include "rpn.h"
#include "proto.h"
#include "hmenu.h"
#include <math.h>

extern double stack[];
extern double reg[];
extern double acc[];
extern double Convert, ConvertD, ConvertG, ConvertR;
extern double LastX;
extern double Pig;
extern int LastCode;
extern Boolean MathError;
extern struct Window *Wrpn;
extern struct Menu *MenuStrip;

static void clearStk(void);
static void clearReg(void);
static void clearAcc(void);
static void vanity(void);

void menupick(
  USHORT code
)
{
  struct MenuItem *thisItem;
  int nmenu, nitem, nsub, i;
  double x, y;
  double *p;

/*------------------------------*
 | Pick up menu, item and (if   |
 | appropriate) subitem numbers |
 *------------------------------*/

  while (code != MENUNULL) {
    nmenu = MENUNUM(code);
    nitem = ITEMNUM(code);
    if (nmenu > 3   &&   nmenu < 6) {
      nsub = SUBNUM(code);
    }
    switch (nmenu) {
      case 0:
        switch (nitem) {
          case 0:                               /* Quit */
            cleanup(SYS_NORMAL);
            break;
          case 1:                               /* About */
            vanity();
            break;
        }
        break;
      case 1:
        switch (nitem) {
          case 0:                               /* Clear X */
            stack[0] = 0.0;
            outStk();
            LastCode = ENTER_CODE;
            break;
          case 1:                               /* Clear Stack */
            clearStk();
            LastCode = ENTER_CODE;
            break;
          case 2:                               /* Clear Registers */
            clearReg();
            break;
          case 3:                               /* Clear Accumulators */
            clearAcc();
            break;
          case 4:                               /* Clear All */
            clearStk();
            clearReg();
            clearAcc();
            LastCode = ENTER_CODE;
            break;
        }
        break;
      case 2:
        switch (nitem) {
          case 0:                               /* Set Deg */
            Convert = ConvertD;
            break;
          case 1:                               /* Set Rad */
            Convert = ConvertR;
            break;
          case 2:                               /* Set Grd */
            Convert = ConvertG;
            break;
        }
        break;
      case 3:
        switch (nitem) {
          case 0:                               /* To H.... */
            x = floor(y = fabs(stack[0]));
            y = (y - x) * 100.0;
            y = y / 0.36 - floor(y) / 0.9;
            x += y / 100.0;
hxs:        if (stack[0] < 0)   x = -x;
            xs(x);
            break;
          case 1:                               /* To H.MMSS */
            x = floor(y = fabs(stack[0]));
            y = (y - x) * 60.0;
            x += floor(y) * 0.004 + y * 0.006;
            goto hxs;
          case 2:                               /* To Rad */
            x = stack[0] * ConvertD;
            xs(x);
            break;
          case 3:                               /* To Deg */
            x = stack[0] / ConvertD;
            xs(x);
            break;
          case 4:                               /* To Polar */
            x = sqrt(stack[0] * stack[0] + stack[1] * stack[1]);
            y = (x == 0.0) ? 0.0 : (atan2(stack[1], stack[0]) / Convert);
xys:        if (!MathError) {
              stack[0] = x;
              stack[1] = y;
              outStk();
            }
            break;
          case 5:                               /* To Cartesian */
            x = stack[0] * cos( (y = stack[1] * Convert) );
            y = stack[0] * sin(y);
            goto xys;
        }
        break;
      case 4:                                   /* Store ... */
        if ((i = nsub) < NREGS) {
          p = reg + i;
        } else {
          i -= NREGS;
          p = acc + i;
        }
        switch (nitem) {
          case 0:                               /* Store */
            *p = stack[0];
            outReg(nsub);
            break;
          case 1:                               /* Store + */
            x = *p + stack[0];
sxs:        if (!MathError) {
              *p = x;
              outReg(nsub);
            }
            break;
          case 2:                               /* Store - */
            x = *p - stack[0];
            goto sxs;
          case 3:                               /* Store * */
            x = *p * stack[0];
            goto sxs;
          case 4:                               /* Store / */
            x = *p / stack[0];
            goto sxs;
        }
        break;
      case 5:                                   /* Recall ... */
        if ((i = nsub) < NREGS) {
          p = reg + i;
        } else {
          i -= NREGS;
          p = acc + i;
        }
        switch (nitem) {
          case 0:                               /* Recall */
            enter();
            stack[0] = *p;
            outStk();
            break;
          case 1:                               /* Recall + */
            x = stack[0] + *p;
rxs:        if (!MathError) {
              enter();
              stack[0] = x;
              outStk();
            }
            break;
          case 2:                               /* Recall - */
            x = stack[0] - *p;
            goto rxs;
          case 3:                               /* Recall * */
            x = stack[0] * *p;
            goto rxs;
          case 4:                               /* Recall / */
            x = stack[0] / *p;
            goto rxs;
        }
        break;
      case 6:
        switch (nitem) {
          case 0:                               /* Last X */
            enter();
            stack[0] = LastX;
            outStk();
            break;
          case 1:                               /* Fisher */
            x = regCoef();
            y = acc[4] - acc[3] * acc[3] / acc[0];
            x = sqrt(y * (1.0 - x * x) / (acc[0] - 2.0));
            if (!MathError) {
              impEnter();
              LastX = stack[0];
              stack[0] = x;
              outStk();
            }
            break;
        }
        break;
    }
    thisItem = (struct MenuItem *) ItemAddress(MenuStrip, code);
    code = thisItem->NextSelect;
  }
}

static void clearStk(void)
{/*---------------------------------*
  | Local function. Clear all stack |
  *---------------------------------*/

  int i;

  for (i=0; i<NSTACK; i++)       stack[i] = 0.0;
  outStk();
}

static void clearReg(void)
{/*-------------------------------------*
  | Local function. Clear all registers |
  *-------------------------------------*/

  int i;

  for (i=0; i<NREGS; i++) {
    reg[i] = 0.0;
    outReg(i);
  }
}

static void clearAcc(void)
{/*---------------------------*
  | Local function. Clear     |
  | all accumulator registers |
  *---------------------------*/

  int i;

  for (i=0; i<NACCS; i++) {
    acc[i] = 0.0;
    outAcc(i);
  }
}

static void vanity(void)
{/*-------------------------*
  | Local function: display |
  | 'About RPN' requester   |
  *-------------------------*/

  struct IntuiText IT5 = {
    BLUE_PEN, WHITE_PEN, JAM2, IT5X, IT5Y, NULL,
    "ITALY", NULL
  };

  struct IntuiText IT4 = {
    BLUE_PEN, WHITE_PEN, JAM2, IT4X, IT4Y, NULL,
    "35010 CADONEGHE (PD)", NULL
  };

  struct IntuiText IT3 = {
    BLUE_PEN, WHITE_PEN, JAM2, IT3X, IT3Y, NULL,
    "Via G. Donizetti, 6", NULL
  };
  
  struct IntuiText IT2 = {
    BLUE_PEN, WHITE_PEN, JAM2, IT2X, IT2Y, NULL,
    "by Maurizio LORETI (aka MLO or I3NOO)", NULL
  };
  
  struct IntuiText IT1 = {
    BLUE_PEN, WHITE_PEN, JAM2, IT1X, IT1Y, NULL,
    "This is RPN V1.00 900131", NULL
  };

  struct IntuiText ITOK = {
    BLUE_PEN, WHITE_PEN, JAM2, ITOKX, ITOKY, NULL,
    "OK", NULL
  };

  IT1.NextText = &IT2;
  IT2.NextText = &IT3;
  IT3.NextText = &IT4;
  IT4.NextText = &IT5;
  AutoRequest(Wrpn, &IT1, NULL, &ITOK, 0, 0, ITWID, ITHEI);
}
