/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 12-Dec-85 | [1.175] Created by excising from mach.c
* 13-Dec-85 | [1.180] Check L for validity
* 30-Dec-85 | [1.279] Use new strategy for decoding I-cycles
* 11-Jan-86 | [1.290] clear_inst_length checks for showing_console
* 24-Jan-86 | [1.326] Properly handle length error across screen redraws
* 22-Feb-86 | [1.364] replace printf with scdspmsg for color support
* 23-Feb-86 | [1.364] include <> => include ""
* 23-Feb-86 | [1.368] Updated markscreen call
* 23-Feb-86 | [1.370] Make screen active color light red
* 25-Feb-86 | [1.377] Use color.h for new screen interface
* 29-Jul-86 | [1.394] Use lamp_test
* 18-Aug-86 | [1.414] screen.h -> bscreen.h
* 18-Aug-86 | [1.414] Write display characters in length box invisibly
*           | in background (improve appearance of lamp test mode)
* 20-Aug-86 | [1.426] mark_len now takes argument
* 20-Aug-86 | [1.426] and has been renamed to mark_inst_len
* 20-Aug-86 | [1.427] Properly draw "Length" so it is on for lamp_test
* 10-Nov-91 | [1.428] <jmn> converted to Microsoft C 6.0
*****************************************************************************/

/*****************************************************************************
				 1401 Emulator

				Length display

This module displays the instruction length

*****************************************************************************/
#include "stdio.h"
/* #include "graph.h" */

#include "btypes.h"
#include "scdspmsg.h"

#include "boolean.h"
#include "panel.h"
#include "icycle.h"
#include "hercules.h"
#include "disp.h"
#include "color.h"
#include "display.h"
#include "length.h"

extern void mark_inst_len();

extern int I_cycle;
extern boolean lamp_test;
int old_length;	/* Used by length display */

typedef struct { coord X; coord Y; int width;} chardesc;
chardesc offsets[] = { { 1,1,2},   /* OP */
		       { 4,1,1},   /* 1 */
		       { 6,1,1},   /* 2 */
		       { 8,1,1},   /* 3 */
		       {10,1,1},   /* 4 */
		       { 2,2,1},   /* 5 */
		       { 4,2,1},   /* 6 */
		       { 6,2,1},   /* 7 */
		       { 8,2,1}};  /* 8 */

static boolean length_on = false;


/****************************************************************************
*                                  draw_len
* Effect: 
*       Draws the instruction length box
****************************************************************************/

void draw_len()
    {
     unsigned char fore;
     unsigned char back;

     if(ismono())
        { /* mono */
	 fore = H_NORMAL;
	 back = 0;
	} /* mono */
     else
        { /* color */
	 fore = COLOR_WHITE;
	 back = COLOR_BLACK;
	} /* color */

     scdspmsg(ilength_Y,ilength_X,fore,back,  "ÚÄÄ      ÄÄ¿");
     scdspmsg(ilength_Y+1,ilength_X,fore,back,"³          ³");
     scdspmsg(ilength_Y+2,ilength_X,fore,back,"³          ³");
     scdspmsg(ilength_Y+3,ilength_X,fore,back,"ÀÄÄÄÄÄÄÄÄÄÄÙ");
     /* Now write in the "invisible" characters whose colors will be
	changed later
     */
     scdspmsg(ilength_Y+1,ilength_X+1,back,back,"OP 1 2 3 4");
     scdspmsg(ilength_Y+2,ilength_X+1,back,back," 5 6 7 8");
     zap_length();

     show_length(I_cycle);
     mark_inst_len(length_on);

    }

/****************************************************************************
*                                  mark_inst_len
* Inputs:
*	boolean set: Tells whether or not to turn the light on
*		true - turn it on
*		false - turn it off
* Effect: 
*       Turns the length error light on or off
****************************************************************************/

void mark_inst_len(boolean set)
    {
     if(ismono())
         mark_screen_color(ilength_X+3,ilength_Y,"Length",
		(boolean)(set || lamp_test),
		COLOR_BLACK,COLOR_WHITE,COLOR_WHITE,COLOR_BLACK);
     else
         mark_screen_color(ilength_X+3,ilength_Y,"Length",
		(boolean) (set || lamp_test),
		COLOR_LTRED,COLOR_BLACK,COLOR_WHITE,COLOR_BLACK);
    }

/****************************************************************************
*                               set_inst_length
* Effect: 
*       Turns on the instruction length light
****************************************************************************/

void set_inst_length()
    {
     length_on = true;
     if(!showing_console()) 
	return;
     mark_inst_len(false);
    }

/****************************************************************************
*                                  clear_len
* Effect: 
*       Turns off the 'length' error light
****************************************************************************/

static void clear_len()
    {
     mark_inst_len(false);
    }

/****************************************************************************
*                              clear_inst_length
* Effect: 
*       Clears the instruction length indicator
****************************************************************************/

void clear_inst_length()
    {
     length_on = false;
     if(!showing_console()) 
	return;
     clear_len();
    }

/****************************************************************************
*                                  markcycle
* Inputs:
*       short L: Cycle to display
*	boolean set: true to highlight, false to unhighlight
* Effect: 
*       Marks the cycle on the display.
****************************************************************************/

void markcycle(short L,boolean set)
    {
     chardesc * C;
     coord i;

     switch(L)
        { /* cycle decode */
	 case I3X1: L=3;
	 		break;
         case I3X10: L=3;
	 		break;
         case I3X100: L=3;
	 		break;
	
	 case I6X1: L=6;
	 		break;
         case I6X10: L=6;
	 		break;
         case I6X100: L=6;
	 		break;
	 default:
	 	if(L<0 || L > 8) L = 0;
		break;
	} /* cycle decode */

     C = &offsets[L];

     for(i=0;i<C->width;i++)
        { /* mark it */
	 markscreen((coord)(ilength_Y+C->Y),(coord)(ilength_X+C->X+i),
	 		(boolean)(lamp_test || set),
			digit_on,COLOR_BLACK,digit_off,COLOR_BLACK);
	} /* mark it */
    }

/****************************************************************************
*                                  show_length
* Inputs:
*       int L: Instruction length
* Effect: 
*       Displays the instruction length
*	Updates old_length in order to erase previous value
****************************************************************************/

void show_length(short L)
    {
     if(!showing_console()) 
	 return;
     markcycle(old_length,false);
     markcycle(L,true);
     old_length = L;
    }

/****************************************************************************
*                                 zap_length
* Effect: 
*       Clears all the length indicators
****************************************************************************/

void zap_length()
    {
     int i;

     for(i=0;i<9;i++)
     	markcycle(i,false);

    }
