/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 24-Dec-85 | [1.231] Created
* 28-Dec-85 | [1.269] Added ALU button
* 29-Dec-85 | [1.270] Draw diagnostic key after each alteration of state
* 30-Dec-85 | [1.283] Added 'slow' display button
* 31-Dec-85 | [1.288] Actually draw and check slow button!
* 11-Jan-86 | [1.293] Use cursor keys
* 23-Jan-86 | [1.301] Use vmouse interface
* 24-Jan-86 | [1.314] Rewrote using new 'scan' interface
* 24-Jan-86 | [1.321] Save cursor around screen draw
* 25-Jan-86 | [1.332] Added mouse tracking button
* 27-Jan-86 | [1.349] Save cursor position around activation
* 27-Jan-86 | [1.350] Added last parm to scan call
* 22-Feb-86 | [1.360] Added colors to buttons
* 22-Feb-86 | [1.361] Color changes; use "brown" as on-color
* 23-Feb-86 | [1.365] include <> => include ""
*           | all printfs go to scdspmsg for color support
* 23-Feb-86 | [1.370] Call draw_current_screen to get instantaneous display
* 30-Jul-86 | [1.404] Added console event logging for buttons
*           | Also, noticed ALU button wasn't polled; fixed this
* 31-Jul-86 | [1.405] Made chars unsigned
* 31-Jul-86 | [1.406] Remove implicit calls to log_push, just set log status
*           | and redraw button (avoids having push event erroneously logged)
*  6-Aug-86 | [1.410] cast arg of toggle_selective_trace call to correct type
*  6-Aug-86 | [1.411] If show button hit, make sure diagnostics_on is set
* 18-Aug-86 | [1.414] screen.h -> bscreen.h
* 10-Nov-91 | [1.428] <jmn> converted to Microsoft C 6.0
* 21-Nov-91 | [1.436] <jmn> fixed old strncpys to be ANSI-compatible
* 21-Nov-91 | [1.437] <jmn> since coords are now unsigned, use proper test
* 20-Dec-94 |   JRJ   Added wait_for_mouse_up in ce_panel() (bug fix)
* 24-Dec-94 | [1.600J] Added assert before copy of opcode
*****************************************************************************/

/*****************************************************************************
				    select

This implements the "customer engineering" panel that lets us turn on
various instruction diagnostic traces while we are debugging.

*****************************************************************************/

#include <stdlib.h>
#include <assert.h>
/* #include "graph.h" */
#include "boolean.h"

#include "btypes.h"
#include "scdspmsg.h"
#include "mouse.h"

#include "diag.h"
#include "button.h"
#include "ce.h"
#include "dispatch.h"
#include "display.h"
#include "panel.h"
#include "disp.h"
#include "hercules.h"
#include "color.h"
#include "string.h"
#include "kb.h"
#include "kbd.h"
#include "scan.h"
#include "select.h"
#include "arith.h"
#include "1401.h"

boolean selective_on = false;
boolean slow = false;
boolean tracking = false;

boolean select_trace[64] = 
    { false,false,false,false,false,false,false,false,	/* 0..7 */
      false,false,false,false,false,false,false,false,  /* 8..15 */
      false,false,false,false,false,false,false,false,  /* 16..23 */
      false,false,false,false,false,false,false,false,  /* 24..31 */
      false,false,false,false,false,false,false,false,  /* 32..39 */
      false,false,false,false,false,false,false,false,  /* 40..47 */
      false,false,false,false,false,false,false,false,  /* 48..55 */
      false,false,false,false,false,false,false,false   /* 56..64 */
    };

extern void log_push(void);
extern void show_push(void);
extern void select_push(void);
extern void ALU_push(void);
extern void slow_push(void);
extern void track_push(void);

button log_button =   { log_X,    log_Y,    " Log ", false, log_push,
	COLOR_RED,COLOR_RED,COLOR_RED};
button show_button =  { show_X,   show_Y,   " Show", false, show_push,
	COLOR_YELLOW,COLOR_BROWN,COLOR_YELLOW};
button select_button ={ select_X, select_Y, "Selec", false, select_push,
	COLOR_YELLOW,COLOR_BROWN,COLOR_YELLOW};
button ALU_button    ={ ALU_X,    ALU_Y,    "ALU  ", false, ALU_push,
	COLOR_YELLOW,COLOR_BROWN,COLOR_YELLOW};
button slow_button   ={ slow_X,   slow_Y,   "Slow ", false, slow_push,
	COLOR_MAGENTA,COLOR_MAGENTA,COLOR_MAGENTA};
button track_button  ={ track_X,  track_Y,  "Track", false, track_push,
	COLOR_MAGENTA,COLOR_MAGENTA,COLOR_MAGENTA};

button op_buttons[64];
extern unsigned char lastkey;

boolean ddone;

void activate_ce(mouse_coord mX,mouse_coord mY);
void ce_nop(mouse_coord mX,mouse_coord mY);

static keybindings kb =
	   { 
	    activate_ce,	/* mouse left */
	    ce_nop,		/* mouse middle */
	    ce_nop,	/* mouse right */
	    ins_key,		/* INS */
	    del_key,		/* DEL */
	    move_y_up,		/* uparrow */
	    move_y_down,	/* downarrow */
	    move_x_left,	/* leftarrow */
	    move_x_right,	/* rightarrow */
	    pr_go,		/* pgup */
	    pr_go,		/* pgdn */
	    NULL,		/* home */
	    NULL,		/* end */
	    NULL,		/* c-left */
	    NULL,		/* c-right */
	    {
	     NULL,		/* 000 */
	     NULL,		/* ^A */
	     NULL,		/* ^B */
	     ctlc,		/* ^C */
	     NULL,		/* ^D */
	     NULL,		/* ^E */
	     NULL,		/* ^F */
	     NULL,		/* ^G */
	     NULL,		/* ^H */
	     NULL,		/* ^I */
	     NULL,		/* ^J */
	     NULL,		/* ^K */
	     draw_current_screen,/* ^L */
	     ins_key,		/* ^M */
	     NULL,		/* ^N */
	     NULL,		/* ^O */
	     ctlp,		/* ^P */
	     ctlq,		/* ^Q */
	     NULL,		/* ^R */
	     ctls,		/* ^S */
	     NULL,		/* ^T */
	     NULL,		/* ^U */
	     NULL,		/* ^V */
	     NULL,		/* ^W */
	     NULL,		/* ^X */
	     NULL,		/* ^Y */
	     NULL,		/* ^Z */
	     ctlc,		/* ^[ */
	     NULL,		/* ^\ */
	     NULL,		/* ^] */
	     NULL,		/* ^^ */
	     NULL		/* ^_ */
	    }
	   };


/****************************************************************************
*                               init_op_buttons
* Effect: 
*       Initializes all the op buttons
****************************************************************************/

void init_op_buttons()
    {
     short i;
     short BX;
     short BY;

     BX = op_X;
     BY = op_Y;

     for(i=0; i < 64;i++)
        { /* init loop */
	 if(strcmp(opcodes[i],"?") != 0)
	    { /* real opcode */
	     op_buttons[i].X = BX;
	     op_buttons[i].Y = BY;
	     /*
		We want to make the legend exactly 5 characters long
	     */
	     op_buttons[i].legend = malloc((unsigned) (5+1));
	     /*
		"$$$"
	     */
	     assert(strlen(opcodes[i]) < 6);
	     strcpy(op_buttons[i].legend,opcodes[i]);
	     /*
		"_____"

	     */
	     strcat(op_buttons[i].legend, &"     "[strlen(opcodes[i])]);
	     op_buttons[i].active = false;
	     op_buttons[i].border = COLOR_YELLOW;
	     op_buttons[i].on = COLOR_BROWN;
	     op_buttons[i].off = COLOR_YELLOW;
	     select_trace[i] = false;

	     BX += op_spacing_X;
	     if(BX > 80 - button_width)
		{ /* next row */
		 BX = op_X;
		 BY += op_spacing_Y;
		} /* next row */
	    } /* real opcode */
	 else
	    { /* non opcode */
	     op_buttons[i].X = (coord)(-1);
	    } /* non opcode */
	     
	} /* init loop */
	 
    }

/****************************************************************************
*                            draw_selective_buttons
* Effect: 
*       Draws the selective trace buttons
****************************************************************************/

void draw_selective_buttons()
    {
     short i;
     for(i=0;i<64;i++)
     	if(op_buttons[i].X != (coord)(-1))
		draw_button(&op_buttons[i]);
    }

/****************************************************************************
*                             toggle_selective_trace
* Inputs:
*       unsigned char opcode: BCD opcode to trace
* Effect: 
*	Toggles the selective trace button
****************************************************************************/

void toggle_selective_trace(unsigned char opcode)
    {
     boolean set;

     set = op_buttons[opcode].active = !op_buttons[opcode].active;
     select_trace[opcode] = set;
     draw_button(&op_buttons[opcode]);
     if(set)
        { /* set trace */
	 selective_on = true;
	 return;
	} /* set trace */
     else
        { /* clear trace */
	 short i;
	 selective_on = false;
	 for(i=0;i<64;i++)
	 	selective_on |= select_trace[i];
	} /* clear trace */

     select_button.active = selective_on;
     draw_button(&select_button);

    }

/****************************************************************************
*                                draw_warning
* Effect: 
*       Draws the warning logo
****************************************************************************/

void draw_warning()
    {
     attrib fore;
     attrib back;

     if(ismono())
        { /* mono */
	 fore = H_NORMAL;
	 back = 0;
	} /* mono */
     else
        { /* color */
	 fore = COLOR_LTRED;
	 back = COLOR_BLACK;
	} /* color */

scdspmsg(warn_Y,warn_X,fore,back,  "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿");
scdspmsg(warn_Y+1,warn_X,fore,back,"³ CUSTOMER ENGINEER FIELD SERVICE PANEL ³");
scdspmsg(warn_Y+2,warn_X,fore,back,"³       AUTHORIZED PERSONNEL ONLY       ³");
scdspmsg(warn_Y+3,warn_X,fore,back,"ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ");
    }

/****************************************************************************
*                                draw_ce_panel
* Effect: 
*       Draws the customer engineering control panel
****************************************************************************/

void draw_ce_panel()
    {
     coord x;
     coord y;

     sccurpos(&y, &x);
     hide_mouse_cursor();

     sccurset(0,0);
     sc_clearscreen();
     draw_warning();
     draw_button(&log_button);
     draw_button(&show_button);
     draw_button(&select_button);
     draw_button(&ALU_button);
     draw_button(&slow_button);
     draw_button(&track_button);
     draw_selective_buttons();
     draw_diagnostic_key();

     sccurset(y, x);
     show_mouse_cursor();

    }

/****************************************************************************
*                                   ce_nop
* Inputs:
*       mouse_coord mX: mouse X-coordinate of hit
*	mouse_coord mY: mouse Y-coordinate of hit
* Effect: 
*       None; dummy routine
****************************************************************************/
/*ARGSUSED */

void ce_nop(mouse_coord mX,mouse_coord mY)
    {
     return;
    }

/****************************************************************************
*                                 activate_ce
* Inputs:
*       mouse_coord mX: mouse coordinate of mouse hit
*	mouse_coord mY: mouse coordinate of mouse hit
* Effect:
*       Polls all the buttons on the CE panel and activates them
*	Sets ddone true if we are to stop CE panel scan
****************************************************************************/

void activate_ce(mouse_coord mX,mouse_coord mY)
    {
     short i;
     coord X;
     coord Y;
     coord old_x;
     coord old_y;

     sccurpos(&old_y, &old_x);

     X = mouse_to_screen_x(mX);
     Y = mouse_to_screen_y(mY);

     if(in_button(X,Y,&log_button))
     		log_push();
     else
     if(in_button(X,Y,&show_button))
     		show_push();
     else
     if(in_button(X,Y,&select_button))
     		select_push();
     else
     if(in_button(X,Y,&slow_button))
     		slow_push();
     else
     if(in_button(X,Y,&track_button))
		track_push();
     else
     if(in_button(X,Y,&ALU_button))
		ALU_push();

     for(i=0;i<64;i++)
         if(op_buttons[i].X != (coord)(-1))
	     if(in_button(X,Y,&op_buttons[i]))
	     	toggle_selective_trace((unsigned char)i);

     if(bounded(X,Y,
		diag_key_X,diag_key_Y,
		diag_key_X+diag_key_width,diag_key_Y+diag_key_height))
        { /* hit diagnostic key */
	 ddone = true;
	} /* hit diagnostic key */

     sccurset(old_y, old_x);
    }

/****************************************************************************
*                                  ce_panel
* Effect:
*       Instantiates the ce panel
****************************************************************************/

void ce_panel()
    {
     short old_display;

     clear_off();

     old_display = set_display(CEPANEL);

     draw_current_screen();

     /* process control for CE panel */

     show_mouse_cursor();

     ddone = false;

     wait_for_mouse_up();

     scan(&ddone,&kb,false);

     clear_off();

     set_display(old_display);
     draw_current_screen();
    }

/****************************************************************************
*                               log_push
* Effect: 
*       Toggles the diagnostic mode
****************************************************************************/

void log_push()
    {
     log_button.active = !log_button.active;

     /* DO NOT CHANGE THE ORDER OF THE FOLLOWING THREE STATEMENTS! */

     if(diagnostics_on) log_console_event("LOG (OFF)");
     diagnostics_on = log_button.active;
     if(diagnostics_on) log_console_event("LOG (ON)");
     
     /* */

     draw_diagnostic_key();

     wait_for_mouse_up();
     draw_button(&log_button);
    }

/****************************************************************************
*                               slow_push
* Effect: 
*       Toggles the slow display mode
****************************************************************************/

void slow_push()
    {
     slow_button.active = !slow_button.active;
     slow = slow_button.active;
     if(diagnostics_on) 
	if(slow) log_console_event("SLOW (ON)");
	   else  log_console_event("SLOW (OFF)");
     draw_button(&slow_button);

     wait_for_mouse_up();
    }

/****************************************************************************
*                               track_push
* Effect: 
*       Toggles the mouse tracking mode
****************************************************************************/

void track_push()
    {
     track_button.active = !track_button.active;
     draw_button(&track_button);
     tracking = track_button.active;
     if(diagnostics_on) 
	if(tracking) log_console_event("TRACK (ON)");
	   else  log_console_event("TRACK (OFF)");

     wait_for_mouse_up();
    }

/****************************************************************************
*                                  show_push
* Effect: 
*       Toggles the display mode.  If log mode is off, turns in on as well
****************************************************************************/

void show_push()
    {
     show_button.active = !show_button.active;
     draw_button(&show_button);
     if(show_button.active && !log_button.active)
        { /* log on */
	 log_button.active = true;
	 diagnostics_on = true;
	 draw_button(&log_button);
	} /* log on */
     display_on = show_button.active;
     if(diagnostics_on) 
	if(display_on) log_console_event("SHOW (ON)");
	   else  log_console_event("SHOW (OFF)");
     draw_diagnostic_key();
     wait_for_mouse_up();
    }

/****************************************************************************
*                                  select_push
* Effect: 
*       Handles the selective trace facility
****************************************************************************/

void select_push()
    {
     select_button.active = !select_button.active;
     selective_on = select_button.active;
     draw_button(&select_button);
     if(select_button.active && !log_button.active)
        { /* log on */
	 log_button.active = true;
	 draw_button(&log_button);
	} /* log on */
     if(diagnostics_on) 
	if(selective_on) log_console_event("SELECT (ON)");
	   else  log_console_event("SELECT (OFF)");

     draw_diagnostic_key();
     wait_for_mouse_up();
     
    }

/****************************************************************************
*                                  ALU_push
* Effect: 
*       Handles the ALU trace facility
****************************************************************************/

void ALU_push()
    {
     ALU_button.active = !ALU_button.active;
     draw_button(&ALU_button);
     set_ALU_trace(ALU_button.active);
     if(ALU_button.active && !log_button.active)
        { /* log on */
	 log_button.active = true;
	 draw_button(&log_button);
	} /* log on */
     if(diagnostics_on) 
	if(ALU_button.active) log_console_event("ALU (ON)");
	   else  log_console_event("ALU (OFF)");
     draw_diagnostic_key();
     wait_for_mouse_up();
     
    }

/****************************************************************************
*                                   setslow
* Inputs:
*       boolean set: Value to set button to
* Effect: 
*       Sets the slow_button.active state.
****************************************************************************/

void setslow(boolean set)
    {
     slow = slow_button.active = set;
    }
