#include "windows.h"

struct window_def_struc *win_table;
struct window_usage_struc *dis_table;

/******************************************************************************/
/* Initialize windows reads the parameters for a set of windows and builds    */
/* those windows on the screen.  The windows consist of four horizontal border*/
/* lines (three at top of the window for "heading" data and one at the bottom */
/* to close the window) and two vertical border lines (to delimit the right   */
/* and left edges of the window).  Thus, from the window information given,   */
/* four lines and two columns will be unusable.  This just defines the borders*/
/* of the windows.							      */
/*									      */
/* Enter:   wdw_table		= table using window_def_struc that defines   */
/*				all of the window areas 		      */
/*	    dsp_table		= table using window_usage_struc that defines */
/*				all of the display areas		      */
/*	    max_windows 	= number of windows to setup		      */
/*									      */
/* Enter:   nothing							      */
/*									      */
/* Call:    initialize_windows (wdw_table, dsp_table, max_windows)	      */
/*									      */
/* Return:  nothing		(screen initialized with the borders of the   */
/*				windows)				      */
/******************************************************************************/

initialize_windows (wdw_table, dsp_table, max_windows, string, args)
struct window_def_struc *wdw_table;
struct window_usage_struc *dsp_table;
int max_windows;
unsigned char *string;
unsigned int args;

{
    int window;
    int ctr;
    int x;
    int y;
    int lines;
    int columns;
    int attr;

    unsigned char *line_buffer [128];

    win_table = wdw_table;
    dis_table = dsp_table;

    video_clear_screen ();

    attr = win_table [0].border_attr;


    /* draw outer border area */

    video_write_char (1, 1, 1, attr, 201);
    video_write_char (1, 2, 78, attr, 205);
    video_write_char (1, 80, 1, attr, 187);

    for (x = 2; x < 25; x++)
    {
	video_write_char (x, 1, 1, attr, 186);
	video_write_char (x, 80, 1, attr, 186);
    }

    video_write_char (25, 1, 1, attr, 200);
    video_write_char (25, 2, 78, attr, 205);
    video_write_char (25, 80, 1, attr, 188);


    format_string (&line_buffer [0], string, &args);

    if (strlen (line_buffer))
    {
	video_write_char (25, (40 - (strlen (line_buffer) / 2)) - 1, 1, attr, 181);
	video_write_char (25, (40 - (strlen (line_buffer) / 2)) + (strlen (line_buffer)), 1, attr, 198);
	video_write_string (25, (40 - (strlen (line_buffer) / 2)), attr, line_buffer);
    }
}


/******************************************************************************/
/* Setup window intializes the header area for a given window specified by a  */
/* display.  It centers the displayable information centerd in the header     */
/* line and will also support a split header line with two seperate headings. */
/*									      */
/* Require: dis_table		= table using window_usage_struc that defines */
/*				all of the possible displays for all windows  */
/*									      */
/* Enter:   display		= display information to use		      */
/*									      */
/* Call:    setup_window (display)					      */
/*									      */
/* Return:  nothing		(window heading information set to display    */
/*				table)					      */
/******************************************************************************/

setup_window (display)
int display;

{
    int window;
    int x;
    int y;
    int lines;
    int columns;
    int center;
    int attr;
    int ctr;

    window = dis_table [display].display_window;
    x = win_table [window].win_x_upper;
    y = win_table [window].win_y_upper;
    lines = win_table [window].win_x_lower - win_table [window].win_x_upper + 1;
    columns = win_table [window].win_y_lower - win_table [window].win_y_upper + 1;
    center = columns / 2;

    attr = win_table [window].border_attr;
    video_write_char (x, y, 1, attr, 213);
    video_write_char (x, y + columns - 1, 1, attr, 184);
    video_write_char (x, y + 1, columns - 2, attr, 205);
    video_write_char (win_table [window].win_x_lower, y + 1, columns - 2, attr, 196);
    video_write_char (x + lines - 1, y, 1, attr, 192);
    video_write_char (x + lines - 1, y + columns - 1, 1, attr, 217);

    /* vertical borders */
    for (ctr = 0; ctr < lines - 2; ctr++)
    {
	video_write_char (x + ctr + 1, y, 1, attr, 179);
	video_write_char (x + ctr + 1, y + columns - 1, 1, attr, 179);
    }

    video_write_char (x, y + (center - (strlen (dis_table [display].window_title) / 2)) - 1, 1, attr, 17);
    video_write_char (x, y + (center - (strlen (dis_table [display].window_title) / 2)) + (strlen (dis_table [display].window_title)), 1, attr, 16);
    attr = ((attr >> 4) + (attr << 4)) & 0x77;
    video_write_string (x, y + (center - (strlen (dis_table [display].window_title) / 2)), attr, dis_table [display].window_title);

    clear_window (display);

    win_table [window].active_menu = display;
    win_table [window].border_left_length = 0;
    win_table [window].border_center_length = 0;
    win_table [window].border_right_length = 0;
}

/******************************************************************************/
/* Clear window clears the usable area of a window specified by a display.    */
/* The usable area is cleared to all spaces.				      */
/*									      */
/* Require: dis_table		= table using window_usage_struc that defines */
/*				all of the possible displays for all windows  */
/*									      */
/* Enter:   display		= display information to use		      */
/*									      */
/* Call:    clear_window (display)					      */
/*									      */
/* Return:  nothing		(window usable area cleared)		      */
/******************************************************************************/

clear_window (display)
int display;

{
    int window;
    int attr;

    window = dis_table [display].display_window;
    attr = win_table [window].window_attr;

    video_scroll (win_table [window].win_x_upper + 1,
    win_table [window].win_y_upper + 1,
    win_table [window].win_x_lower - 1,
    win_table [window].win_y_lower - 1,
    0,
    attr);
}

/******************************************************************************/
/* Clear window lines clears a line relative to the start of the usable area. */
/*									      */
/* Require: dis_table		= table using window_usage_struc that defines */
/*				all of the possible displays for all windows  */
/*									      */
/* Enter:   display		= display information to use		      */
/*	    line		= line number relative to start of usable area*/
/*				to be cleared				      */
/*									      */
/* Call:    clear_window_line (display, line)				      */
/*									      */
/* Return:  nothing		(window heading information set to display    */
/*				table)					      */
/******************************************************************************/

clear_window_line (display, line)
int display;
int line;

{
    int window;
    int attr;

    window = dis_table [display].display_window;
    attr = win_table [window].window_attr;

    video_write_char (win_table [window].win_x_upper + line,
    win_table [window].win_y_upper + 1,
    win_table [window].win_y_lower - win_table [window].win_y_upper - 1, attr, ' ');
}

/******************************************************************************/
/* Write window border writes a string either Centered, Left justified or     */
/* Right justified onto a relative line within a window specified by a	      */
/* display.  This allows a formatted string like printf ().		      */
/*									      */
/* Require: dis_table		= table using window_usage_struc that defines */
/*				all of the possible displays for all windows  */
/*									      */
/* Enter:   display		= display information to use		      */
/*	    rel_line		= line relative to top of usable window to    */
/*				write string				      */
/*	    justify		= type of justification for string	      */
/*	    string		= formatted string to display		      */
/*	    args		= list of arguments to for formatted string   */
/*									      */
/* Call:    write_window_border (display, justify, string, args)	      */
/*									      */
/* Return:  nothing		(relative line in window written with string) */
/******************************************************************************/

write_window_border (display, justify, string, args)
int display;
int justify;
unsigned char *string;
unsigned int args;

{
    int window;
    int x;
    int y;
    int length;
    int columns;
    int clear_offset;
    int offset;
    int attr;
    unsigned char line_buffer [128];

    window = dis_table [display].display_window;
    x = win_table [window].win_x_lower;
    y = win_table [window].win_y_upper;
    attr = win_table [window].border_attr;
    columns = win_table [window].win_y_lower - win_table [window].win_y_upper + 1;

    format_string (&line_buffer [0], string, &args);

    switch (justify)
    {
	case 'C':
	{
	    offset = (columns - strlen (line_buffer)) / 2;
	    length = win_table [window].border_center_length;
	    clear_offset = (columns - length) / 2;
	    win_table [window].border_center_length = strlen (line_buffer);

	    break;
	}

	case 'L':
	{
	    offset = 2;
	    length = win_table [window].border_left_length;
	    clear_offset = 2;
	    win_table [window].border_left_length = strlen (line_buffer);

	    break;
	}

	case 'R':
	{
	    offset = columns - strlen (line_buffer) - 2;
	    length = win_table [window].border_right_length;
	    clear_offset = columns - length - 2;
	    win_table [window].border_right_length = strlen (line_buffer);

	    break;
	}
    }

    if (length == 0)
    {
	video_write_char (x, y + offset - 1, 1, attr, 17);
	video_write_char (x, y + offset + (strlen (line_buffer)), 1, attr, 16);
    }
    else
    {
	if (strlen (line_buffer) != length)
	{
	    video_write_char (x, y + clear_offset - 1, length + 2, attr, 196);

	    if (strlen (line_buffer) > 0)
	    {
		video_write_char (x, y + offset - 1, 1, attr, 17);
		video_write_char (x, y + offset + (strlen (line_buffer)), 1, attr, 16);
	    }
	}
    }


    if (strlen (line_buffer) > 0)
    {
	attr = ((attr >> 4) + (attr << 4)) & 0x77;
	video_write_string (x, y + offset, attr, line_buffer);
    }
}

/******************************************************************************/
/* Write window writes a string either Centered, Left justified or Right      */
/* justified onto a relative line within a window specified by a display.     */
/* This allows a formatted string like printf ().			      */
/*									      */
/* Require: dis_table		= table using window_usage_struc that defines */
/*				all of the possible displays for all windows  */
/*									      */
/* Enter:   display		= display information to use		      */
/*	    rel_line		= line relative to top of usable window to    */
/*				write string				      */
/*	    justify		= type of justification for string	      */
/*	    string		= formatted string to display		      */
/*	    args		= list of arguments to for formatted string   */
/*									      */
/* Call:    write_window (display, rel_line, justify, string, args)	      */
/*									      */
/* Return:  nothing		(relative line in window written with string) */
/******************************************************************************/

write_window (display, rel_line, justify, string, args)
int display;
int rel_line;
int justify;
unsigned char *string;
unsigned int args;

{
    int window;
    int x;
    int y;
    int columns;
    int attr;
    unsigned char line_buffer [128];

    window = dis_table [display].display_window;
    x = win_table [window].win_x_upper;
    y = win_table [window].win_y_upper;
    attr = win_table [window].window_attr;

    columns = win_table [window].win_y_lower - win_table [window].win_y_upper + 1;

    format_string (&line_buffer [0], string, &args);

    switch (justify)
    {
	case 'C':
	{
	    video_write_string (x + rel_line, y + ((columns - strlen (line_buffer)) / 2), attr, line_buffer);

	    break;
	}

	case 'L':
	{
	    video_write_string (x + rel_line, y + 1, attr, line_buffer);

	    break;
	}

	case 'R':
	{
	    video_write_string (x + rel_line, y + ((columns - 2) - strlen (line_buffer)), attr, line_buffer);

	    break;
	}
    }
}

/******************************************************************************/
/* Write string to window border specified by display with string starting at */
/* relative cursor position supplied in respect to the justified position.    */
/* This allows a formatted string like printf ().			      */
/*									      */
/* Require: dis_table		= table using window_usage_struc that defines */
/*				all of the possible displays for all windows  */
/*									      */
/* Enter:   display		= display information to use		      */
/*	    justify		= which justify area to use		      */
/*	    rel_column		= column relative to left hand border of      */
/*				justified area				      */
/*	    string		= formatted string to display		      */
/*	    args		= list of arguments to for formatted string   */
/*									      */
/* Call:    pos_write_window (display, rel_line, rel_column, string, args)    */
/*									      */
/* Return:  nothing		(relative line and column in window written   */
/*				with string)				      */
/******************************************************************************/

pos_write_window_border (display, justify, rel_column, string, args)
int display;
int rel_column;
int justify;
unsigned char *string;
unsigned int args;

{
    int window;
    int x;
    int y;
    int offset;
    int columns;
    int attr;
    unsigned char line_buffer [128];

    window = dis_table [display].display_window;
    x = win_table [window].win_x_lower;
    y = win_table [window].win_y_upper;
    columns = win_table [window].win_y_lower - win_table [window].win_y_upper + 1;
    attr = win_table [window].border_attr;

    format_string (&line_buffer [0], string, &args);

    switch (justify)
    {
	case 'C':
	{
	    offset = (columns - win_table [window].border_center_length) / 2;

	    break;
	}

	case 'L':
	{
	    offset = 2;

	    break;
	}

	case 'R':
	{
	    offset = columns - win_table [window].border_right_length - 1;

	    break;
	}
    }

    attr = ((attr >> 4) + (attr << 4)) & 0x77;
    video_write_string (x, y + offset + rel_column, attr, line_buffer);
}

/******************************************************************************/
/* Write string to window specified by display with string starting at	      */
/* relative cursor position supplied.  This allows a formatted string like    */
/* printf ().								      */
/*									      */
/* Require: dis_table		= table using window_usage_struc that defines */
/*				all of the possible displays for all windows  */
/*									      */
/* Enter:   display		= display information to use		      */
/*	    rel_line		= line relative to top of usable window to    */
/*				write string				      */
/*	    rel_column		= column relative to left hand border of      */
/*				window to write string			      */
/*	    string		= formatted string to display		      */
/*	    args		= list of arguments to for formatted string   */
/*									      */
/* Call:    pos_write_window (display, rel_line, rel_column, message)	      */
/*									      */
/* Return:  nothing		(relative line and column in window written   */
/*				with string)				      */
/******************************************************************************/

pos_write_window (display, rel_line, rel_column, string, args)
int display;
int rel_line;
int rel_column;
unsigned char *string;
unsigned int args;

{
    int window;
    int x;
    int y;
    int columns;
    int attr;
    unsigned char line_buffer [128];

    window = dis_table [display].display_window;
    x = win_table [window].win_x_upper;
    y = win_table [window].win_y_upper;
    attr = win_table [window].window_attr;
    columns = win_table [window].win_y_lower - win_table [window].win_y_upper + 1;

    format_string (&line_buffer [0], string, &args);
    video_write_string (x + rel_line, y + rel_column, attr, line_buffer);
}

/******************************************************************************/
/* Scroll window scrolls the active area up or down lines in the window and   */
/* with the active area specified by display.				      */
/*									      */
/* Require: dis_table		= table using window_usage_struc that defines */
/*				all of the possible displays for all windows  */
/*									      */
/* Enter:   display		= display information to use		      */
/*	    lines		= number of lines to scroll.  Active area will*/
/*				scroll up if positive and scroll down if      */
/*				negative.				      */
/*									      */
/* Call:    scroll_window (display, lines)				      */
/*									      */
/* Return:  nothing		(active area of window scrolled up or down    */
/*				so many lines)				      */
/******************************************************************************/

scroll_window (display, lines)
int display;
int lines;

{
    int window;
    int x_upper;
    int y_upper;
    int x_lower;
    int y_lower;
    int attr;

    window = dis_table [display].display_window;
    attr = win_table [window].window_attr;
    x_upper = win_table [window].win_x_upper + dis_table [display].act_x_upper;
    y_upper = win_table [window].win_y_upper + dis_table [display].act_y_upper;
    x_lower = win_table [window].win_x_upper + dis_table [display].act_x_lower;
    y_lower = win_table [window].win_y_upper + dis_table [display].act_y_lower, lines;

    video_scroll (x_upper, y_upper, x_lower, y_lower, lines, attr);
}

/******************************************************************************/
/* Video write character.  Writes count number of character to line and column*/
/* position on the screen. This uses an extension to the normal C routines    */
/* and was so located in the event that the target machine needs to be	      */
/* written.								      */
/*									      */
/* Enter:   line		= line on screen to start write 	      */
/*	    column		= column on screen to start write	      */
/*	    count		= number of characters to write 	      */
/*	    character		= character value to write		      */
/*									      */
/* Call:    video_write_char (line, column, count, character)		      */
/*									      */
/* Return:  nothing		(count number of character written starting at*/
/*				line and column position on screen)	      */
/******************************************************************************/

video_write_char (line, column, count, attribute, character)
int line;
int column;
int count;
int attribute;
unsigned char character;

{
    crt_pos_cursor (line - 1, column - 1, 0);
    crt_wr_char_att (0, count, character, attribute);
}

/******************************************************************************/
/* Video write string.	Write a string starting at the specified line and     */
/* column position to the screen. This uses an extension to the normal C      */
/* routines and was so located in the event that the target machine needs to  */
/* be written.								      */
/*									      */
/* Enter:   line		= line on screen to start write 	      */
/*	    column		= column on screen to start write	      */
/*	    string		= string to display			      */
/*									      */
/* Call:    video_write_char (line, column, count, character)		      */
/*									      */
/* Return:  nothing		(count number of character written starting at*/
/*				line and column position on screen)	      */
/******************************************************************************/

video_write_string (line, column, attribute, string)
int line;
int column;
int attribute;
unsigned char *string;

{
    while (*string)
    {
	crt_pos_cursor (line - 1, (column++) - 1, 0);
	crt_wr_char_att (0, 1, *string++, attribute);
    }

    crt_pos_cursor (line - 1, (column) - 1, 0);
}

/******************************************************************************/
/* Video scroll.  Scrolls a window area defined by x_upper / y_upper to       */
/* x_lower / y_lower plus or minus line_cnt lines.  This uses an extension to */
/* the normal C routines and was so located in the event that the target      */
/* machine needs to be written. 					      */
/*									      */
/* Enter:   x_upper		= upper left line of window		      */
/*	    y_upper		= upper left column of window		      */
/*	    x_lower		= lower right line of window		      */
/*	    y_lower		= lower right column of window		      */
/*	    line_cnt		= lines to scroll up (> 0) or lines to scroll */
/*				down (< 0)				      */
/*									      */
/* Call:    video_scroll (x_upper, y_upper, x_lower, y_lower, line_cnt)       */
/*									      */
/* Return:  nothing (window scrolled n lines)				      */
/******************************************************************************/

video_scroll (x_upper, y_upper, x_lower, y_lower, line_cnt, attr)
int x_upper;
int y_upper;
int x_lower;
int y_lower;
int line_cnt;
int attr;

{
    if (line_cnt >= 0)
    {
	crt_scroll_up (line_cnt, x_upper - 1, y_upper - 1, x_lower - 1, y_lower - 1, attr);
    }
    else
    {
	crt_scroll_down (-line_cnt, x_upper - 1, y_upper - 1, x_lower - 1, y_lower - 1, attr);
    }
}

/******************************************************************************/
/* Video set cursor position.  Sets the cursor position to that specified by  */
/* line and column.  This uses an extension to the normal C routines and was  */
/* so located in the event that the target machine needs to be written.       */
/*									      */
/* Enter:   line		= line to put cursor on 		      */
/*	    column		= column to put cursor on		      */
/*									      */
/* Call:    video_set_cursor (line, column)				      */
/*									      */
/* Return:  nothing (cursor positioned on screen)			      */
/******************************************************************************/

video_set_cursor (line, column)
int line;
int column;

{
    crt_pos_cursor (line - 1, column - 1, 0);
}

/******************************************************************************/
/* Video clear screen.	Clears the entire video display and puts the cursor   */
/* home.  This uses an extension to the normal C routines and was  so located */
/* in the event that the target machine needs to be written.		      */
/*									      */
/* Enter:   nothing							      */
/*									      */
/* Call:    video_clear_screen ()					      */
/*									      */
/* Return:  nothing (screen cleared and cursor home)			      */
/******************************************************************************/

video_clear_screen ()
{
    crt_scroll_up (0, 0, 0, 24, 79, 0x07);
}

/* PCPRO function(s) */
init_pcpro_windows (wdw_table, dsp_table, max_windows, string, args)
struct window_def_struc *wdw_table;
struct window_usage_struc *dsp_table;
int max_windows;
unsigned char *string;
unsigned int args;

{
    int window;
    int ctr;
    int x;
    int y;
    int lines;
    int columns;

    unsigned char *line_buffer [128];

    win_table = wdw_table;
    dis_table = dsp_table;

    video_clear_screen ();

    for (window = 0; window < max_windows; window++)
    {
	x = win_table [window].win_x_upper;
	y = win_table [window].win_y_upper;
	lines = win_table [window].win_x_lower - win_table [window].win_x_upper + 1;
	columns = win_table [window].win_y_lower - win_table [window].win_y_upper + 1;

	video_write_char (x, y, 1, 0x07, 213);
	video_write_char (x, y + 1, columns - 2, 0x07, 205);
	video_write_char (x, y + columns - 1, 1, 0x07, 184);

	for (ctr = 0; ctr < lines - 2; ctr++)
	{
	    video_write_char (x + ctr + 1, y, 1, 0x07, 179);
	    video_write_char (x + ctr + 1, y + columns - 1, 1, 0x07, 179);
	}

	video_write_char (x + lines - 1, y, 1, 0x07, 192);
	video_write_char (x + lines - 1, y + 1, columns - 2, 0x07, 196);
	video_write_char (x + lines - 1, y + columns - 1, 1, 0x07, 217);
    }

    format_string (&line_buffer [0], string, &args);

    if (strlen (line_buffer))
    {
	video_write_char (1, (40 - (strlen (line_buffer) / 2)) - 1, 1, 0x07, 181);
	video_write_char (1, (40 - (strlen (line_buffer) / 2)) + (strlen (line_buffer)), 1, 0x07, 198);
	video_write_string (1, (40 - (strlen (line_buffer) / 2)), 0x07, line_buffer);
    }
}




get_window_attr (display, attr)
{
    int window;
    int norm_attr;

    window = dis_table [display].display_window;
    norm_attr = win_table [window].window_attr & 0xff;

    if ((attr & 0x70) == 0x70)
    {
	norm_attr = ((norm_attr >> 4) | (norm_attr << 4)) & 0x77;
    }
    return (norm_attr | (attr & 0x88));
}

