/* umoria io.c for Linux */

#include <stdio.h>

#ifndef STDIO_LOADED
#define STDIO_LOADED
#endif

#include "BSDtoLinux.h"
#include <curses.h>
#include "config.h"
#include "constant.h"
#include "types.h"
#include "externs.h"
#include <ctype.h>
#include <termios.h>
#include <signal.h>

/* #define real_move(row,col)  mvcur(stdscr->_cury,stdscr->_curx,row,col) */
int curses_on;
WINDOW *savescr;


void exit();
void sleep();


static struct termio save_termio;

/* suspend doesn't work right.  Exit is ok, but reentering is messed up.  
The problem is in terminal i/o.  something isn't being restored, but I don't
know what */
int suspend() 
{
  struct termio tbuf;
  long time();

  py.misc.male |= 2;
  (void) ioctl(0,TCGETA,(char *)&tbuf);
  save_screen();
  restore_term();
  nocrmode();
  echo();
  (void) kill(0,SIGSTOP);
  curses_on=TRUE;
  restore_screen();
  crmode();
  noecho();
  (void) ioctl(0,TCSETA,(char *)&tbuf);
  wrefresh(curscr);
  py.misc.male &= ~2;
  return 0;
}

void init_curses()
{
  int i,x,y;

  (void) ioctl(0,TCGETA,(char *)&save_termio);
  if (initscr()==ERR)
    {
      (void)printf("Error allocating screen in curses package.\n");
      exit(1);
    }
  /* questinable, but why not */
  (void)signal(SIGTSTP, suspend);
  
  if ((savescr=newwin(0,0,0,0))==NULL)
    {
      printf("Out of memory in starting up curses.\n");
      exit_game();
    }
  clear();
  refresh();
  curses_on=TRUE;
  moriaterm();
/* forget about tab test */
}

void moriaterm()
{
  struct termio tbuf;

  crmode();
  noecho();
  (void)ioctl(0,TCGETA,(char *)&tbuf);
 
  tbuf.c_cc[VINTR] = (char)3;
  tbuf.c_cc[VSUSP] = (char)26;
  tbuf.c_cc[VERASE]= (char)-1; 
  tbuf.c_cc[VKILL] = (char)-1;
  tbuf.c_cc[VEOF]  = (char)-1;
/*  Linux doesn't like these.
  tbuf.c_cc[VEOL]  = (char)-1;  
  tbuf.c_cc[VEOL2] = (char)-1; 
*/
  tbuf.c_cc[VMIN]  = 1;
  tbuf.c_cc[VTIME] = 0;
  
  (void)ioctl(0,TCSETA,(char *)&tbuf); 
} 

void put_buffer(char *out_str, int row, int col)
{
  char *tmp_str;

  if (col>79) 
    col=79;
  mvaddstr(row,col,out_str);
  refresh();
}

void put_qio()
{
  screen_change=TRUE;
  refresh();
}

void restore_term()
{
  if (!curses_on)
    return;
  mvcur(stdscr->_cury,stdscr->_curx,LINES-1,0);
  endwin();
  fflush(stdout);
  (void)ioctl(0,TCSETA,(char *)&save_termio);
  curses_on=FALSE;
}

void shell_out()
{  

  struct termio tbuf;
  int val;
  char *str;

  save_screen();
  clear_screen();
  put_buffer("[Entering shell, type 'exit' to resume your game.]\n",0,0);
  put_qio();
  (void) ioctl(0,TCGETA,(char *)&tbuf);
  nocrmode();
  echo();
  ignore_signals();
  val=fork();
  if ((int)val==0) {
    default_signals();
    (void) ioctl(0,TCSETA,(char *)&save_termio);
    fclose(highscore_fp);
    if (str=getenv("SHELL"))
      execl(str,str,(char *)0);
    else
      execl("/bin/sh","sh",(char *)0);
    msg_print("Cannot execute shell.");
    exit(1);
  }
  if ((int)val==-1) {
    msg_print("Fork failed.  Try again.");
    return;
  }
  wait((int *)0);
  restore_signals();
  restore_screen();
  crmode();
  noecho();
  (void) ioctl(0,TCSETA,(char *)&tbuf);
  wrefresh(curscr);
} 

char inkey()
{
  char tmp;
  tmp=getch();
  msg_flag=FALSE;
  return tmp;
}

void flush()
{
/*  if (!eof_flag)
    while(check_input(0)); */
}

void erase_line(int row,int col)
{
  if (row==MSG_LINE && msg_flag)
    msg_print(CNIL);
  move(row,col);
  clrtoeol();
  refresh();
}

void clear_screen()
{
  if (msg_flag)
    msg_print(CNIL);
  clear();
  refresh();
}

void clear_from(int row)
{
  move(row,0);
  clrtobot();
  refresh();
}

void print(char ch, int row, int col)
{
  vtype tmp_str;

  row -= panel_row_prt;
  col -= panel_col_prt;
/*  mvaddch(row,col,ch); */
  if (mvaddch(row,col,ch)==ERR) {
    abort();
    msg_flag=0;
    spritf(tmp_str,"error in print, row = %d, col = %d\n",row,col);
    prt(tmp_str,0,0);
    bell();
    sleep(2);
  }
}

void move_cursor_relative(int row, int col)
{
  vtype tmp_str;

  row -= panel_row_prt;
  col -= panel_col_prt;
/*  move(row,col); */
  if (move(row,col)==ERR) {
    abort();
    msg_flag=0;
    sprintf(tmp_str,"error in move_cursor_relative, row = %d, col = %d\n",row,col);
    prt(tmp_str,0,0);
    bell();
    sleep(2);
  }
  refresh();
}

void count_msg_print(char *p)
{
  int i;

  i=command_count;
  msg_print(p);
  command_count=i;
}

void prt(char *str_buff, int row, int col)
{
  if (row==MSG_LINE && msg_flag)
    msg_print(CNIL);
  move(row,col);
  clrtoeol();
  put_buffer(str_buff, row, col);
}

void move_cursor(int row, int col)
{
  move(row,col);
  refresh();
}

void msg_print(char *str_buff)
{
  int old_len;
  char ch='a';

  if (msg_flag)
    {
      old_len=strlen(old_msg[last_msg])+1;
      put_buffer(" -more -", MSG_LINE, old_len);
      while(ch != ' ' && ch!= ESCAPE && ch!='\n')  
	ch=inkey();
      wait_for_more=0;
    }
  move(MSG_LINE,0);
  clrtoeol();
  if (str_buff)
    {
      put_buffer(str_buff, MSG_LINE, 0);
      command_count=0;
      last_msg++;
      if (last_msg>=MAX_SAVE_MSG)
	last_msg=0;
      strncpy(old_msg[last_msg], str_buff, VTYPESIZ);
      old_msg[last_msg][VTYPESIZ-1]='\0';
      msg_flag=TRUE;
    }
  else
    msg_flag=FALSE;
}


/*  the next three routines get input from the user.  Usually, one would use 
echo() and noecho() to echo the input to the screen (Moria runs in noecho 
mode).  However, when echo is called, tcsh starts buffering characters.  You 
have to type four characters before the program receives any characters.  
This is a known tcsh shell bug.  To get around this, I just use lots of 
refreshes. */

int get_check(char *prompt)
{
  int res, y, x;

  prt(prompt, 0,0);
  getyx(stdscr,y,x);
  if (x>73)
    move (0,73);
  addstr(" [y/n]");
  refresh();
  do
    {
      res=inkey();
    }
  while(res==' ');
  refresh();
  erase_line(0,0);
  if(res=='Y' || res=='y')
    return TRUE;
  else
    return FALSE;
}


int get_com(char *prompt, char *command)
{
  int res;

  if (prompt)
    prt(prompt,0,0);
  *command=inkey();
  refresh();
  if (*command==ESCAPE)
    res=FALSE;
  else
    res=TRUE;
  erase_line(MSG_LINE,0);
  return(res);
}

int get_string(in_str, row, column, slen)
char *in_str;
int row, column, slen;
{
  register int start_col, end_col, i;
  char *p;
  int flag, aborted;

  aborted = FALSE;
  flag	= FALSE;

  (void) move(row, column);
  for (i = slen; i > 0; i--)
    (void) addch(' ');
  (void) move(row, column);

  start_col = column;
  end_col = column + slen - 1;
  if (end_col > 79)
    {
      slen = 80 - column;
      end_col = 79;
    }
  p = in_str;
  refresh();
  do
    {
      i = inkey();
      switch(i)
	{
	case ESCAPE:
	  aborted = TRUE;
	  break;
	case CTRL('M'): case CTRL('J'):
	  flag	= TRUE;
	  break;
	case DELETE: case CTRL('H'):
	  if (column > start_col)
	    {
	      column--;
	      put_buffer(" ", row, column);
	      move_cursor(row, column);
	      *--p = '\0';
	    }
	  break;
	default:
	  if (!isprint(i) || column > end_col)
	    bell();
	  else
	    {
	      mvaddch(row, column, (char)i);

	      *p++ = i;
	      column++;
	    }
	  break;
	}
      refresh();
    }
  while ((!flag) && (!aborted));
  if (aborted)
    return(FALSE);
  /* Remove trailing blanks	*/
  while (p > in_str && p[-1] == ' ')
    p--;
  *p = '\0';
  return(TRUE);
}


/* Pauses for user response before returning		-RAK-	*/
void pause_line(prt_line)
int prt_line;
{
  prt("[Press any key to continue.]", prt_line, 23);
  (void) inkey();
  erase_line(prt_line, 0);
}


/* Pauses for user response before returning		-RAK-	*/
/* NOTE: Delay is for players trying to roll up "perfect"	*/
/*	characters.  Make them wait a bit.			*/
void pause_exit(prt_line, delay)
int prt_line;
int delay;
{
  char dummy;

  prt("[Press any key to continue, or Q to exit.]", prt_line, 10);
  dummy = inkey();
  if (dummy == 'Q')
    {
      erase_line(prt_line, 0);
      /* prevent message about delay unused */
      dummy = delay;
      exit_game();
    }
  erase_line(prt_line, 0);
}


void save_screen()
{
  overwrite(stdscr, savescr);
}

void restore_screen()
{
  overwrite(savescr, stdscr);
  touchwin(stdscr);
}

void bell()
{
  put_qio();

  /* The player can turn off beeps if he/she finds them annoying.  */
  if (! sound_beep_flag)
    return;
/*  (void) write(1, "\007", 1); */
}

/* definitions used by screen_map() */
/* index into border character array */
#define TL 0	/* top left */
#define TR 1
#define BL 2
#define BR 3
#define HE 4	/* horizontal edge */
#define VE 5

/* character set to use */
#ifdef MSDOS
# ifdef ANSI
#   define CH(x)	(ansi ? screen_border[0][x] : screen_border[1][x])
# else
#   define CH(x)	(screen_border[1][x])
# endif
#else
#   define CH(x)	(screen_border[0][x])
#endif

  /* Display highest priority object in the RATIO by RATIO area */
#define	RATIO 3

void screen_map()
{
  register int	i, j;
  static int8u screen_border[2][6] = {
    {'+', '+', '+', '+', '-', '|'},	/* normal chars */
    {201, 187, 200, 188, 205, 186}	/* graphics chars */
  };
  int8u map[MAX_WIDTH / RATIO + 1];
  int8u tmp;
  int priority[256];
  int row, orow, col, myrow, mycol = 0;
  char prntscrnbuf[80];
  
  for (i = 0; i < 256; i++)
    priority[i] = 0;
  priority['<'] = 5;
  priority['>'] = 5;
  priority['@'] = 10;
#ifdef MSDOS
  
#else
#ifndef ATARI_ST
  priority['#'] = -5;
#else
  priority[(unsigned char)240] = -5;
#endif
  priority['.'] = -10;
#endif
  priority['\''] = -3;
  priority[' '] = -15;

  save_screen();
  clear_screen();

  mvaddch(0, 0, CH(TL));
  for (i = 0; i < MAX_WIDTH / RATIO; i++)
    (void) addch(CH(HE));
  (void) addch(CH(TR));

  orow = -1;
  map[MAX_WIDTH / RATIO] = '\0';
  for (i = 0; i < MAX_HEIGHT; i++)
    {
      row = i / RATIO;
      if (row != orow)
	{
	  if (orow >= 0)
	    {
	      /* can not use mvprintw() on ibmpc, because PC-Curses is horribly
		 written, and mvprintw() causes the fp emulation library to be
		 linked with PC-Moria, makes the program 10K bigger */
	      (void) sprintf(prntscrnbuf,"%c%s%c",CH(VE), map, CH(VE));
	      mvaddstr(orow+1, 0, prntscrnbuf);
	    }
	  for (j = 0; j < MAX_WIDTH / RATIO; j++)
	    map[j] = ' ';
	  orow = row;
	}
      for (j = 0; j < MAX_WIDTH; j++)
	{
	  col = j / RATIO;
	  tmp = loc_symbol(i, j);
	  if (priority[map[col]] < priority[tmp])
	    map[col] = tmp;
	  if (map[col] == '@')
	    {
	      mycol = col + 1; /* account for border */
	      myrow = row + 1;
	    }
	}
    }
  if (orow >= 0)
    {

      (void) sprintf(prntscrnbuf,"%c%s%c",CH(VE), map, CH(VE));
      mvaddstr(orow+1, 0, prntscrnbuf);

    }

  mvaddch(orow + 2, 0, CH(BL));
  for (i = 0; i < MAX_WIDTH / RATIO; i++)
    (void) addch(CH(HE));
  (void) addch(CH(BR));


  mvaddstr(23, 23, "Hit any key to continue");
  if (mycol > 0)
    (void) move(myrow, mycol);

  (void) inkey();
  restore_screen();
}
