/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 16-Nov-85 | [1.42] Created
* 24-Jan-86 | [1.324] Allow mode switch to be hit in outer border
* 22-Feb-86 | [1.362] Added color
* 30-Jul-86 | [1.403] Added log_console_event call
* 18-Aug-86 | [1.414] screen.h -> bscreen.h
* 10-Nov-91 | [1.428] <jmn> converted to Microsoft C 6.0
*****************************************************************************/

/*****************************************************************************
				 1401 Emulator

			      Mode Switch Module

This module manipulates the 'mode' switch settings

*****************************************************************************/
#include "stdio.h"
#include "boolean.h"

#include "btypes.h"
#include "scdspmsg.h"

#include "panel.h"
#include "hercules.h"
#include "disp.h"
/* #include "graph.h" */
#include "diag.h"
#include "display.h"
#include "color.h"
#include "1401.h"
#include "button.h"

#include "mode.h"

mode_state modes[NMODES] = {
/* S-X, S-Y, B-X, B-Y  id           code           active */
/* ---  ---  ---  ---  -----------  ----           ------ */
{    0,   0,   0,   0, " Run     ", mode_run,      true},
{    0,   0,   0,   1, " Adr Stop", mode_adr_stop, false},
{    0,   0,   1,   0, " I/EX    ", mode_i_ex,     false},
{    0,   0,   1,   1, " Sing Cyc", mode_sing_cyc, false},
{    0,   0,   2,   0, " Stg Prnt", mode_stg_prt,  false},
{    0,   0,   2,   1, " Char Dsp", mode_char_dsp, false},
{    0,   0,   3,   0, " Alter   ", mode_alter,    false}
			   };

void show_mode(mode_state * M);

/****************************************************************************
*                                  show_mode
* Inputs:
*       mode_state * M: Mode state to show
* Effect: 
*       Displays the mode on the screen according to its 'active' state
****************************************************************************/

void show_mode(mode_state * M)
    {
     mark_screen(M->X,M->Y,M->id,M->active);
    }

/****************************************************************************
*                              clear_active_mode
* Effect: 
*       Clears the current active mode, and turns off its screen rep
****************************************************************************/

void clear_active_mode()
    {
     short i;
     for(i=0;i<NMODES;i++)
        { /* find and kill */
	 if(modes[i].active)
	    { /* kill */
	     modes[i].active = false;
	     show_mode(&modes[i]);
	     break;
	    } /* kill */
	} /* find and kill */
	 
    }

/****************************************************************************
*                                draw_mode_box
* Effect: 
*       Draws the mode switch box on the screen
****************************************************************************/

short current_mode = mode_run;

void draw_mode_box()
    {
     short i;
     coord base_row;
     coord base_column;
     attrib fore;
     attrib back;

     if(ismono())
        { /* mono */
	 fore = H_NORMAL;
	 back = 0;

	} /* mono */
     else
        { /* color */
	 fore = COLOR_BLUE;
	 back = COLOR_BLACK;
	} /* color */
	     
     sccurset(mode_Y,mode_X);
     scdspmsg(mode_Y,mode_X,fore,back,
     				"MÉÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍ»");
     scdspmsg((coord)(mode_Y+1),mode_X,fore,back,
     				"oº         º         º         º         º");
     scdspmsg((coord)(mode_Y+2),mode_X,fore,back,
     				"dÌÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍ¹");
     scdspmsg((coord)(mode_Y+3),mode_X,fore,back,
     				"eº         º         º         º         º");
     scdspmsg((coord)(mode_Y+4),mode_X,fore,back,
     				" ÈÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍ¼");

     /* Now print the legends.  We also establish the absolute X-Y
        co-ordinates for the boxes
     */

     base_row = mode_Y + 1;
     base_column = mode_X + 2;

     for(i=0;i<NMODES;i++)
        { /* where is it and print it */
	 modes[i].X = base_column + modes[i].box_X * mode_width;
	 modes[i].Y = base_row + modes[i].box_Y * (mode_height - 1);
	 show_mode(&modes[i]);

	 if(modes[i].active) current_mode = modes[i].code;

	} /* where is it and print it */
	 
    }

/****************************************************************************
*                                 check_mode
* Inputs:
*       short X: screen X position of mouse hit
*	short Y: screen Y position of mouse hit
* Effect: 
*       Sets the current mode if the mouse hit was within a mode area
****************************************************************************/

void check_mode(coord X,coord Y)
    {
     short i;
     coord base_row;
     coord base_column;

     base_row = mode_Y + 1;
     base_column = mode_X + 2;

     for(i=0;i<NMODES;i++)
        { /* scan */
	 coord X0;
	 coord X1;
	 coord Y0;
	 coord Y1;
	 short previous_mode = current_mode;

	 X0 = base_column + modes[i].box_X * mode_width;
	 Y0 = base_row + modes[i].box_Y * (mode_height - 1);
	 X1 = X0 + mode_width - 2;
	 Y1 = Y0 + mode_height - 3;

	 /* Adjust for outer border (this depends on 2xN layout! */
	 if(modes[i].box_Y == 0) Y0--; else Y1++;

	 if(bounded(X,Y,X0,Y0,X1,Y1))
	    { /* hit mode */
	     clear_off();
	     if(modes[i].active) return;  /* do nothing */
	     clear_active_mode();
	     modes[i].active = true;
	     if(diagnostics_on) log_console_event(modes[i].id);
	     show_mode(&modes[i]);
	     current_mode = modes[i].code;
	    } /* hit mode */
	} /* scan */
    }
