#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
#include "uselect.h"

static int lastFd=-1;
static struct termios atts;
static int echo=1;

void sys_keys_on(void) {
  int iret;
  
  struct termios attr;
  if (echo) {
    iret=tcgetattr(STDIN_FILENO,&attr);
    atts=attr; /* save term. attr. */
    if (iret!=0) { perror("***\n");}
    attr.c_lflag &= ~(ICANON) & ~(ECHO); /* canonical mode off, echo off */
    attr.c_cc[VMIN]=0;
    attr.c_cc[VTIME]=1; /* 0.1 sec */
    iret= tcsetattr(STDIN_FILENO,TCSANOW,&attr);
    if (iret!=0) {perror("***\n");}
    echo=0;
  }
}

void sys_keys_off(void) {
  int iret;

  if (!echo) {
    iret=tcsetattr(STDIN_FILENO,TCSANOW,&atts); /* restore term. attributes */
    if (iret!=0) {perror("***\n");};
    echo=1;
  }
}

static int getChar(void) {
  unsigned char c;
  int rt;
  
  rt = read(STDIN_FILENO, &c, 1);
  if (rt<=0) {
    return EOF;
  } else {
    return c;
  }
}

int sys_select_or_key(fd_set *mask, int msecTmo, int *key) {
  int fd, iret, fd1, chr;
  struct timeval tmo, tmo0={0,0};
  fd_set rmask;
  
  sys_keys_on();
  rmask=*mask;
  iret=uselect(FD_SETSIZE, &rmask, NULL, NULL, &tmo0);
  if (iret<0) {
    FD_ZERO(&rmask);
    perror("error in select");
  }
  fd1=STDIN_FILENO;
  /* chr=fgetc(stdin); */
  chr = getChar();
  if (chr == EOF && iret==0) { /*  */
    rmask=*mask;
    FD_SET(STDIN_FILENO, &rmask);
    if (msecTmo>=0) {
      if (msecTmo>100) { /* reduce 100 ms for the 1 tenth second in fgetc */
	msecTmo=msecTmo-100;
      } else {
	msecTmo=1;
      }
      tmo.tv_sec=msecTmo / 1000;
      tmo.tv_usec=(msecTmo%1000)*1000;
      iret=uselect(FD_SETSIZE, &rmask, NULL, NULL, &tmo);
    } else {
      iret=uselect(FD_SETSIZE, &rmask, NULL, NULL, NULL);    
    }
    if (iret<0) {
      FD_ZERO(&rmask);
      perror("error in select");
    }
    if (FD_ISSET(STDIN_FILENO, &rmask)) {
      chr = getChar();
      /* chr=fgetc(stdin); */
    }
    FD_CLR(STDIN_FILENO, &rmask);
  }
  if (chr==EOF) {
    chr=0;
    fd1=-1;
    for (fd=1; fd<FD_SETSIZE; fd++) {
      if (FD_ISSET(fd, &rmask)) {
	if (fd1<0) {
	  fd1=fd; /* first fd */
	} else if (fd>lastFd) {
	  fd1=fd; break;
	}
      }
    }
  }
  *mask=rmask;
  *key=chr;
  return(fd1);
}
