/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 15-Nov-85 | [1.30] Created
* 17-Nov-85 | [1.89] Upper limit of address switches is 15000 not 16000
* 24-Nov-85 | [1.98] redraw address lights in redraw operation
* 30-Dec-85 | [1.276] Wrap units, tens, hundreds switches around
* 24-Jan-86 | [1.325] Do not mark/unmark address if not showing_console
* 24-Jan-86 | [1.326] Properly store address light state across screen
*           | redraws; do update on redraw
* 22-Feb-86 | [1.364] Added color support
* 22-Feb-86 | [1.364] include <> => include ""
* 22-Feb-86 | [1.364] replaced all printfs with BIOS calls to support
*           | instantaneous pages
* 23-Feb-86 | [1.367] Separate out show_addr_values to get better screen
*           | performance; call it instead of whole box redraw to update
*           | values
* 23-Feb-86 | [1.368] Updated markscreen call for new args
* 23-Feb-86 | [1.370] Make digit active color light red
* 25-Feb-86 | [1.373] Display digits which are off on color display in black
*           | so they are invisible
* 25-Feb-86 | [1.374] Use color.h for certain color parametrizations
* 25-Feb-86 | [1.374] If address is zero, turn off all address lights
* 25-Feb-86 | [1.376] Added zap_address to clear entire address display
* 25-Feb-86 | [1.382] Display manual_address legend in legend color
* 29-Jul-86 | [1.385] Include mach.h
* 29-Jul-86 | [1.393] Mark only '1' bit for h/o address
* 31-Jul-86 | [1.406] Log all changes in console switches
* 18-Aug-86 | [1.414] screen.h -> bscreen.h
* 18-Aug-86 | [1.417] Write characters as invisible
* 20-Aug-86 | [1.427] Light up address light on lamp_test; always call
*           | mark_addr
* 20-Aug-86 | [1.427] Removed clear_addr
* 10-Nov-91 | [1.428] <jmn> converted for Microsoft C 6.0
*****************************************************************************/

/*****************************************************************************
				 1401 Emulator

		     Address Display Register Maintenance

This module draws the address display register on the panel.

*****************************************************************************/
#include "stdio.h"
#include "graph.h"

#include "btypes.h"
#include "scdspmsg.h"

#include "panel.h"
#include "boolean.h"
#include "hercules.h"
#include "disp.h"
#include "color.h"
#include "mach.h"
#include "diag.h"
#include "addr.h"
#include "display.h"
#include "1401.h"
#include "kb.h"
#include "scan.h"

static int last_address = 0;
static boolean addr_on = false;
static void lamp_address(boolean set);
static void  mark_addr(void);

/****************************************************************************
*			       draw_address_box
* Effect: 
*       Draws the address display box
****************************************************************************/

void draw_address_box()
    {
     attrib fore;
     attrib back;

     if(ismono())
        { /* mono */
	 fore = H_NORMAL;
	 back = 0;
	} /* mono */
     else
        { /* color */
	 fore = WHITE;
	 back = BLACK;
	} /* color */
	 
     scdspmsg(address_Y,address_X,fore,back,    "ÚÄÄ       ÄÄ¿");

     scdspmsg(address_Y+1,address_X,fore,back,  "³           ³");
     scdspmsg(address_Y+1,address_X+1,back,back, "   8 8 8 8 ");

     scdspmsg(address_Y+2,address_X,fore,back,  "³           ³");
     scdspmsg(address_Y+2,address_X+1,back,back, "   4 4 4 4 ");

     scdspmsg(address_Y+3,address_X,fore,back,  "³           ³");
     scdspmsg(address_Y+3,address_X+1,back,back, "   2 2 2 2 ");

     scdspmsg(address_Y+4,address_X,fore,back,  "³           ³");
     scdspmsg(address_Y+4,address_X+1,back,back, " 1 1 1 1 1 ");

     scdspmsg(address_Y+5,address_X,fore,back,"ÀÄÄÄÄÄÄÄÄÄÄÄÙ");

     zap_address();
     display_address(last_address);
     mark_addr();
    }

/****************************************************************************
*                                mark_address
* Inputs:
*       int digit: Digit position to display (0=units, 1=tens, etc.)
*	int value: Value to mark in position
*	boolean set: true to highlight, false to unhighlight
* Effect: 
*       Turns lights on and off in the address display
****************************************************************************/

void mark_address(short digit,short value,boolean set)
    {
     coord row;
     coord column;
     coord i;

     if(!showing_console()) 
	return;

     column = address_X + 10 - (2*digit);
     row = address_Y + 4;

     for(i=0;i<4;i++)
         {
	  if(value == 0) 
	     break;
	  if((value & 1) != 0)
	     { /* do it */
	      markscreen(row,column,set,digit_on,BLACK,digit_off,BLACK);
	     } /* do it */
	  row--;
	  value >>= 1;
	 }
    }

/****************************************************************************
*                                zap_address
* Result: void
*       
* Effect: 
*       Turns all address lamps off
****************************************************************************/

void zap_address()
    {
     lamp_address(false);
	
    }

/****************************************************************************
*                                 lamp_address
* Inputs:
*	boolean set: Turn all lamps on or off
* Effect: 
*       Initializes the address display by turning all the digits 
****************************************************************************/

void lamp_address(boolean set)
    {
     int pos;

     for(pos = 0;pos < 5; pos++)
        { /* zap  */
	 int vv;
	 if(pos==4)
	    mark_address(pos,1,set);
	 else
	 for(vv = 8; vv != 0; vv>>=1)
	    mark_address(pos, vv, set);
	} /* zap  */

    }

/****************************************************************************
*                               update_address
* Inputs:
*       short addr: Address to updated
*	boolean set: Mode in which to update it 
*			true to mark
*			false to unmark
* Effect: 
*       Causes the address to be updated on the screen
****************************************************************************/

void update_address(short addr,boolean set)
    {
     int v;
     int pos;

     if(lamp_test)
        { /* turn lamps on */
	 lamp_address(true);
	 return;
	} /* turn lamps on */


     v = addr;
     pos = 0;

     if(v == 0)
        { /* clear it */
	 zap_address();
	 return;
	} /* clear it */

     while(v != 0)
        { /* decode it */
	 int vv;

	 vv = v % 10;
	 if (vv == 0) vv = 10;	/* BCD represents '0' as '8 2' */

	 mark_address(pos, vv, set);

	 pos++;
	 v = v / 10;
	} /* decode it */
    }

/****************************************************************************
*                                clear_address
* Inputs:
*       short addr: Address value to clear
* Effect: 
*       Unmarks the values in the address register
****************************************************************************/

void clear_address(short addr)
    {
     update_address(addr,false);
    }

/****************************************************************************
*                                 set_address
* Inputs:
*       short addr: Address to set
* Effect: 
*       Marks the bits for the address in the display register
****************************************************************************/

void set_address(short addr)
    {
     update_address(addr,true);
    }

/****************************************************************************
*                               display_address
* Inputs:
*       short addr: Address to display on the address display
* Effect: 
*	Updates the address displayed in the box
*	The last address displayed is stored in last_address
****************************************************************************/

void display_address(short addr)
    {
     clear_address(last_address);
     set_address(addr);
     last_address = addr;
    }

/****************************************************************************
*                            get_address_switches
* Result: int
*       Contents of manual address entry switches (0..15999)
****************************************************************************/

static int addr_switches = 0;	/* address switches */

short get_address_switches()
    {
     return addr_switches;	
    }

/****************************************************************************
*                              show_addr_values
* Effect: 
*       Updates the values in the manual address switches
****************************************************************************/

void show_addr_values()
    {
     char msg[10];
     unsigned char fore;
     unsigned char back;

     if(ismono())
        { /* mono */
	 fore = H_NORMAL;
	 back = 0;
	} /* mono */
     else
        { /* color */
	 fore = WHITE;
	 back = BLACK;
	} /* color */

     sprintf(msg,"%2d",addr_switches/1000);
     scdspmsg(manual_Y+2,manual_X+1,fore,back,msg);
     sprintf(msg,"%2d",(addr_switches/100) % 10);
     scdspmsg(manual_Y+2,manual_X+6,fore,back,msg);
     sprintf(msg,"%2d",(addr_switches/10) % 10);
     scdspmsg(manual_Y+2,manual_X+11,fore,back,msg);
     sprintf(msg,"%2d",addr_switches % 10);
     scdspmsg(manual_Y+2,manual_X+16,fore,back,msg);
    }

/****************************************************************************
*                           draw_manual_address_box
* Effect: 
*       Draws the manual address switches box
****************************************************************************/

void draw_manual_address_box()
    {
     unsigned char fore;
     unsigned char back;
     unsigned char h_fore;
     unsigned char h_back;

     if(ismono())
        { /* mono */
	 fore = H_NORMAL;
	 back = 0;
	 h_fore = H_NORMAL;
	 h_back = 0;
	} /* mono */
     else
        { /* color */
	 fore = control_fore;
	 back = control_back;
	 h_fore = legend_fore;
	 h_back = legend_back;
	} /* color */
	 
     scdspmsg(manual_Y,manual_X,fore,back,  "ÖÄÄ              Ä·");
     scdspmsg(manual_Y+1,manual_X,fore,back,"ÌÍÍ» ÉÍÍ» ÉÍÍ» ÉÍÍ¹");
     scdspmsg(manual_Y+2,manual_X,fore,back,"º  º º  º º  º º  º");
     scdspmsg(manual_Y+3,manual_X,fore,back,"ÈÍÍ¼ ÈÍÍ¼ ÈÍÍ¼ ÈÍÍ¼");
     scdspmsg(manual_Y,manual_X+3,h_fore,h_back,"Manual Address");

     show_addr_values();
    }

/****************************************************************************
*                             check_addr_switches
* Inputs:
*       int X: current X screen position
*	int Y: current Y screen position
*	int dir: +1 or -1
* Result: boolean
*	true if address switch hit (modified or not!)
*	false if not in address switch
* Effect: 
*       modifies the address switch if in one
****************************************************************************/

boolean check_addr_switches(coord X,coord Y,short dir)
    {
     if(bounded(X,Y, manual_X,
     		     (coord)(manual_Y+1),
     		     (coord)(manual_X+manual_width-1),
		     (coord)(manual_Y+manual_height)))
       { /* thousands */
	if(dir > 0 && addr_switches >= 15000) 
	   goto exit;
	if(dir < 0 && addr_switches < 1000) 
	   goto exit;
	addr_switches += 1000 * dir;
	show_addr_values();
	goto exit;
       } /* thousands */
		        
    if(bounded(X,Y,   (coord)(manual_X+manual_width+manual_spacing),
    		      (coord)(manual_Y+1),
		      (coord)(manual_X+manual_width+manual_spacing-1+manual_width),
		      (coord)(manual_Y+manual_height)))
         { /* hundreds */
	  int v;
	  v = addr_switches % 1000;
	  if(dir > 0 && v >= 900) 
	     { /* wrap to 0 */
	      addr_switches -= 900;
	      show_addr_values();
	      goto exit;
	     } /* wrap to 0 */
	  if(dir < 0 && v < 100) 
	     { /* wrap to 9 */
	      addr_switches += 900;
	      show_addr_values();
	      goto exit;
	     } /* wrap to 9 */
	  addr_switches += 100 * dir;
	  show_addr_values();
	  goto exit;
	 } /* hundreds */

    if(bounded(X,Y,   (coord)(manual_X+2*(manual_width+manual_spacing)),
    		      (coord)(manual_Y+1),
		      (coord)(manual_X+2*(manual_width+manual_spacing)-1+manual_width),
		      (coord)(manual_Y+manual_height)))
         { /* tens */
	  int v;
	  v = addr_switches % 100;
	  if(dir > 0 && v >= 90) 
	     { /* wrap to 0 */
	      addr_switches -= 90;
	      show_addr_values();
	      goto exit;
	     } /* wrap to 0 */
	  if(dir < 0 && v < 10) 
	     { /* wrap to 9 */
	      addr_switches += 90;
	      show_addr_values();
	      goto exit;
	     } /* wrap to 9 */
	  addr_switches += 10 * dir;
	  show_addr_values();
	  goto exit;
	 } /* tens */
			  
    if(bounded(X,Y,   (coord)(manual_X+3*(manual_width+manual_spacing)),
    		      (coord)(manual_Y+1),
		      (coord)(manual_X+3*(manual_width+manual_spacing)-1+manual_width),
		      (coord)(manual_Y+manual_height)))
         { /* ones */
	  int v;
	  v = addr_switches % 10;
	  if(dir > 0 && v >= 9) 
	     { /* wrap to 0 */
	      addr_switches -= 9;
	      show_addr_values();
	      goto exit;
	     } /* wrap to 0 */
	  if(dir < 0 && v < 1) 
	     { /* wrap to 0 */
	      addr_switches += 9;
	      show_addr_values();
	      goto exit;
	     } /* wrap to 0 */
	  addr_switches += dir;
	  show_addr_values();	/* see above */
	  goto exit;
	 } /* ones */

      return false;

exit:
	if(diagnostics_on)
	   { /* log it */
	    char msg[40];
	    sprintf(msg,"Addr selected: %d",addr_switches);
	    log_console_event(msg);
	   } /* log it */
	wait_for_mouse_up();
	return true;
    }

/****************************************************************************
*                                  mark_addr
* Effect: 
*       Turns on the address light
****************************************************************************/

static void  mark_addr()
    {
     if(ismono())
	mark_screen_color(address_X+3,address_Y,"Address",(boolean)(addr_on || lamp_test),
			BLACK,WHITE,WHITE,BLACK);
     else
	mark_screen_color(address_X+3,address_Y,"Address",(boolean)(addr_on || lamp_test),
			LTRED,BLACK,WHITE,BLACK);
    }

/****************************************************************************
*                               set_address_light
* Effect: 
*       Turns on the address register light
****************************************************************************/

void set_address_light()
    {
     addr_on = true;
     if(!showing_console()) return;
     mark_addr();
    }

/****************************************************************************
*                              clear_address_light
* Effect: 
*       Clears the address indicator
****************************************************************************/

void clear_address_light()
    {
     addr_on = false;
     if(!showing_console()) return;
     mark_addr();
    }
