/*
 *      ibmterm.c           IBM screen module             mak
 *
 *	Copyright (C) 1989 The Regents of the University of California
 *	This Software may be copied and distributed for educational,
 *	research, and not for profit purposes provided that this
 *	copyright and statement are included in all such copies.
 *
 */

#include "logo.h"
#include "globals.h"
#include "ibmterm.h"
#include <math.h>
#include <bios.h>
#include <graphics.h>
#include <conio.h>

extern x_margin, y_margin;
/************************************************************/

extern unsigned _stklen = 8000; /* 5000 for debugging, 65000 for real */

BOOLEAN in_graphics_mode = FALSE;
BOOLEAN have_been_in_graphics_mode = FALSE;
BOOLEAN in_erase_mode = FALSE;

int ibm_screen_top, ibm_turtle_top_max;
int current_write_mode = COPY_PUT;
int current_vis = 0;
int turtle_color;
int prev_color;
int texth;
int MaxX, MaxY;
void *window_image;
void erase_graphics_top();

void gr_mode()
{
    int gdriver = DETECT, gmode, errorcode,xasp,yasp,size;

    if (!in_graphics_mode) {
	x_coord = x_margin;
	y_coord = y_margin;
	if (have_been_in_graphics_mode) {
	    setgraphmode(getgraphmode());
	    in_graphics_mode = TRUE;
	    redraw_graphics();
	}
	else {
	    initgraph(&gdriver, &gmode, logolib);
	    errorcode = graphresult();
	    if (errorcode != grOk)
		err_logo(BAD_GRAPH_INIT, NIL);
	    else {
		in_graphics_mode = have_been_in_graphics_mode = TRUE;
		turtle_color = getcolor();
		MaxX = getmaxx();
		MaxY = getmaxy();
		window(1,1,80,4);
		getaspectratio(&xasp,&yasp);
		y_scale = (double)xasp/(double)yasp;
		if (MaxY == 479)
		    texth = 16;
		else
		    texth = (MaxY+1)/25;
		size = imagesize(0,0,MaxX,texth);
		if (size != -1)
		    window_image = malloc( size );
		else
		    window_image = NULL;
		ibm_screen_top = 4*texth+1;
		ibm_turtle_top_max = MaxY/2 - (4*texth+1);
		lclearscreen();
	   }
	}
    }
}

void ibm_prepare_to_draw_turtle()
{
    setviewport(0, ibm_screen_top, screen_right, screen_bottom, TRUE);
    turtle_y += ibm_screen_top;
}

void ibm_done_drawing_turtle()
{
    setviewport(0, 0, screen_right, screen_bottom, FALSE);
    turtle_y -= ibm_screen_top;
}

void nop()
{
}

void init_ibm_memory()
{
}

BOOLEAN check_ibm_stop()
{
    long base, top;
    int key;

/*    if (kbhit())
	getch();  */  /* allow DOS to test for control-C */
    base = (long)_SS << 4;
    top = ((long)_SS << 4) + _SP;
    if ((top - base) < 500) {
	err_logo(STACK_OVERFLOW, NIL);
	return(1);
    }

    if ((key = bioskey(1)) == (4113)) { /* control-q */
	getch();
	err_logo(STOP_ERROR,NIL);
	return(1);
    }
    if (key == (4375)) { /* control-w */
	getch();
	to_pending = 0;
	lpause();
    }
    return (0);
}

void term_init_ibm()
{
    tty_charmode = 0;
    x_max = 80;
    y_max = 24;
    x_coord = y_coord = 0;
    so_arr[0] = '\1'; so_arr[1] = '\0';
    se_arr[0] = '\2'; se_arr[1] = '\0';
}

void ibm_gotoxy(int x, int y)
{
    gotoxy(x + 1, y + 1);
}

void ibm_clear_text() {
    if (in_graphics_mode) {
	if (ibm_screen_top != 0)
	    erase_graphics_top();
    } else clrscr();
}

void ibm_clear_screen()
{
    ibm_prepare_to_draw_turtle();
    clearviewport();
    ibm_done_drawing_turtle();
}

char oldattr = 7; /* assume gray on black */

void ibm_plain_mode()
{
    textattr(oldattr); /* white on black */
}

void ibm_bold_mode()
{
    struct text_info ti;

    gettextinfo(&ti);
    oldattr = ti.attribute;
    textattr(15 + (7 << 4)); /* white on gray */
}

void erase_graphics_top()
{
    unsigned char pat[8];

    getfillpattern(pat);
    setfillstyle(0, getcolor());
    bar(0, 0, MaxX, 4*texth);
    setfillpattern(pat, getcolor());
}

/************************************************************/
/* These are the machine-specific graphics definitions.  All versions must
   provide a set of functions analogous to these. */

void save_pen(p)
pen_info *p;
{
    p->h = getx();
    p->v = gety();
    p->vis = current_vis;
    p->width = get_ibm_pen_width();
    p->color = getcolor();
    p->prev_color = prev_color;
    get_pen_pattern(p->pattern);
    p->mode = get_ibm_pen_mode();
}

void restore_pen(p)
pen_info *p;
{
    moveto(p->h, p->v);
    current_vis = p->vis;
    set_ibm_pen_width(p->width);
    set_ibm_pen_mode(p->mode);  /* must restore mode before color */
    setcolor(p->color);
    prev_color = p->prev_color;
    set_pen_pattern(p->pattern);
}

void plain_xor_pen()
{
    set_ibm_pen_width(1);
    setcolor(turtle_color);
    setwritemode(XOR_PUT);
    current_write_mode = XOR_PUT;
    in_erase_mode = FALSE;
}

void ibm_pen_down()
{
    setwritemode(COPY_PUT);
    current_write_mode = COPY_PUT;
    if (in_erase_mode) {
	setcolor(prev_color);
	in_erase_mode = FALSE;
    }
}

void ibm_pen_xor()
{
    setwritemode(XOR_PUT);
    current_write_mode = XOR_PUT;
    if (in_erase_mode) {
	setcolor(prev_color);
	in_erase_mode = FALSE;
    }
}

void ibm_pen_erase()
{
    if (!in_erase_mode) {
	setwritemode(COPY_PUT);
	current_write_mode = COPY_PUT;
	prev_color = getcolor();
	setcolor(0);
	in_erase_mode = TRUE;
    }
}

int get_ibm_pen_mode()
{
    if (in_erase_mode)
	return 2;
    else
	return current_write_mode;
}

void set_ibm_pen_mode(int m)
{
    switch (m) {
	case 2: ibm_pen_erase(); break;
	case COPY_PUT: ibm_pen_down(); break;
	case XOR_PUT: ibm_pen_xor(); break;
    }
}

int get_ibm_pen_width()
{
    struct linesettingstype ls;

    getlinesettings(&ls);
    return ls.thickness;
}

void set_ibm_pen_width(int w)
{
    setlinestyle(SOLID_LINE, 0xFFFF, w);
}

void set_pen_pattern(char *pat)
{
    setfillpattern(pat, getcolor());
}

void set_list_pen_pattern(NODE *arg)
{
    unsigned char pat[8];
    NODE *cur_num, *temp;
    int count;

    cur_num = arg;
    for (count = 0 ; count <= 7 ; count++) {
	temp = cnv_node_to_numnode(car(cur_num));
	pat[count] = (char)getint(temp);
	if (cdr(cur_num) != NIL)
	    cur_num = cdr(cur_num);
	gcref(temp);
    }
    setfillpattern(pat, getcolor());
}

void get_pen_pattern(char *pat)
{
    getfillpattern(pat);
}

NODE *Get_node_pen_pattern()
{
    unsigned char pat[8];

    getfillpattern(pat);
    return(cons(make_intnode((FIXNUM)(pat[0])),
	    cons(make_intnode((FIXNUM)(pat[1])),
	     cons(make_intnode((FIXNUM)(pat[2])),
	      cons(make_intnode((FIXNUM)(pat[3])),
	       cons(make_intnode((FIXNUM)(pat[4])),
		cons(make_intnode((FIXNUM)(pat[5])),
		 cons(make_intnode((FIXNUM)(pat[6])),
		  cons(make_intnode((FIXNUM)(pat[7])),
		   NIL)))))))));
}

NODE *Get_node_pen_mode()
{
    if (in_erase_mode)
	return(make_static_strnode("erase"));
    if (current_write_mode == XOR_PUT)
	return(make_static_strnode("reverse"));
    return(make_static_strnode("paint"));
}

void label(char *s)
{
    gr_mode();
    moveto(round(screen_x_coord), round(screen_y_coord));
    outtext((char far *)s);
}

void logofill()
{
    floodfill(screen_x_coord, screen_y_coord, getcolor());
}

void erase_screen()
{
    ibm_clear_screen();
}

void t_screen()
{
    if (in_graphics_mode) {
	restorecrtmode();
	window(1,1,80,24);
	in_graphics_mode = FALSE;
    }
}

void s_screen()
{
    int save_vis;

    ibm_turtle_top_max = MaxY/2 - (4*texth+1);
    if (in_graphics_mode && ibm_screen_top == 0) {
	if (turtle_shown) {
	    save_vis = current_vis;
	    current_vis = -1;
	    lhome();
	    current_vis = save_vis;
	}
	erase_graphics_top();
    }
    ibm_screen_top = 4*texth+1;
    gr_mode();
}

void f_screen()
{
    if (in_graphics_mode && ibm_screen_top != 0)
	erase_graphics_top();
    ibm_screen_top = 0;
    ibm_turtle_top_max = MaxY/2;
    gr_mode();
}

FIXNUM mickey_x()
{
    return 0;
}

FIXNUM mickey_y()
{
    return 0;
}

BOOLEAN Button()
{
    return FALSE;
}

void tone(pitch, duration)
FIXNUM pitch, duration;
{
    sound(pitch);
    delay(duration);
    nosound();
}

FIXNUM t_height()
{
    return 18;
}

FLONUM t_half_bottom()
{
    return 6.0;
}

FLONUM t_side()
{
    return 19.0;
}

void check_scroll(void) /*routine*/
{
   int wx,wy,i;

   fflush(stdout);

   wx = wherex();
   wy = wherey();

   if ((wy > 4) && in_graphics_mode) {
      setviewport(0, 0, MaxX, texth*4, 1);
      for (i=1;i<4;i++) {
	 getimage(0, texth*i, MaxX, texth*(i+1), window_image);
	 putimage(0, texth*(i-1), window_image, COPY_PUT);
      }
      getimage(0, texth*3, MaxX, texth*4, window_image);
      putimage(0, texth*3, window_image, XOR_PUT);
      gotoxy(wx, 4);
      setviewport(0, 0, MaxX, MaxY, 1);
   }
}
