/*
	K‚perny“kezel“ fggv‚nyeket tartalmaz¢ k”nyvt r
	Copyright 1994-1997. White Falcon Software House and Sapikli TM.
	D”m”t”r kos, BME Villamosm‚rn”ki Kar
	All rights reserved. No modifications, please!
*/

#ifdef __MSDOS__
#include <dos.h>
#endif
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __cplusplus
    #define __CPPARGS ...
#else
    #define __CPPARGS void
#endif

#define FALSE 0
#define TRUE 1
#define LEN 75          /* Itt adhat¢ meg a stringek hossza */
#define SCREENS 5       /* Ez az elmenthet“ k‚perny“k maxim lis sz ma */
static char VERSION_STRING[]="Crt2 v3.0.1  08/01/1998";

typedef int boolean;

boolean kur=TRUE;       /* Be van-e kapcsolva a kurzor */
unsigned int scrbase;   /* A k‚perny“mem¢ria szegmensc¡me */
char background='±';    /* A DeskTop alapt‚rtelmezett karaktere */
char backgroundcolor=7; /* A DeskTop alapt‚rtelmezett sz¡ne */
int xsize=80,ysize=25;  /* Az aktu lis ablak m‚retei */
int xorig=1,yorig=1;    /* Az aktu lis ablak koordin t i */
void (*helpproc)(__CPPARGS)=NULL;		/* Help eset‚n megh¡vand¢ elj r s c¡me defini lhat¢.
                                          NULL eset‚n nincs help. */

int bill(void);			/* Ez a fggv‚ny megv r egy gombnyom st,
					  majd visszaadja a k¢dot. Kib“v¡tett
					  karakterk¢d eset‚n az ‚rt‚khez 1000-et ad,
					  ¡gy pl. ALT+X=1045. */
int gomb(void);			/* Mint a "bill" fggv‚ny, de ez a meghat rozott
					  k¢dok eset‚n nem r¡ti a puffert, ¡gy a
					  karaktert m s elj r s is kiolvashatja.
					  Ez pl. Turbo Vision-ben val¢ programoz sn l
					  lehet hasznos.
					  A jelenlegi k¢dok:  27=Esc, 1038=ALT+L,
					  1048=ALT+B, 1068=F10. */
void scrsave(int i);		/* Elmenti (i>0), illetve vissza ll¡tja
					  (i<0) a az i. k‚perny“ tartalm t, bele‚rtve
					  a kurzor poz¡ci¢j t, bekapcsolt volt t,
                                          ‚s az aktu lis ablakot is. */
void kurzor(boolean igen);	/* Ki- ill. bekapcsolja a kurzort. */
void highlight(int x, int y,int len);	/* Az (x,y) koordin t t¢l kezdve "len"
					  hossz£s gban kiemeli a sz”veget
					  (inverz ki¡r sba v lt). */
void print(char *s);		/* Ki¡r egy stringet, de a v‚g‚r“l
					  lehagyja a f”l”sleges sz¢k”z”ket.
					  Ez keretbe ¡r sn l hasznos. */
void println(char *s);		/* Mint "print", de a v‚g‚n sort is emel. */
void printhigh(char *s);		/* Norm lisan ki¡rja a stringet, de
					  k”zben kiemel‚sek is haszn lhat¢k, on-line.
					  A jelenlegi be ll¡t sok:
					  K‚t "~" karakter k”z”tti sz”veg f‚nyes
					  s rg val lesz ki¡rva, k‚t "@" k”z”tt
					  pedig inverz h tt‚rrel. Az alapsz¡n
					  a feh‚r. */
void printstatus(char *s);       /* A "printhigh"-hoz hasonl¢an ¡r a legals¢
                                          sorba. A sarokba is. */
void getstr(char *dest, char *def);   /* Beolvas egy stringet. A kezdeti ‚rt‚k a
                                          "def"-ben adhat¢ meg. A "scanf"-t“l
                                          elt‚r“en lehet mozogni a sz”vegben. */
int getint(int def); /* Mint "getstr", csak eg‚sz sz mra. */
float getfloat(float def);      /* Mint "getstr", csak lebeg“pontos sz mra. */
void ablak(int x,int y, int szel, int mag, int keret, char *fejlec);
					/* Ablakot hoz l‚tre (x,y) balfels“ sarokkal,
					  (szel,mag) m‚retben, "fejlec" felirattal,
					  kerettel. A "keret" a keret t¡pus t adja meg.
					  0: res (' ')
					  1: szimpla
					  2: fgg. szimpla, v¡zsz. dupla
					  3: fgg. dupla, v¡zsz. szimpla
					  4: dupla.
                                          Negat¡v "keret" eset‚n nincs szeg‚ly. Ilyenkor
                                          fejlec='' eset‚n nincs t”rl‚s. */
void clearwindow(void);                  /* T”rli az adott ablakot ("background" karaktereket
                                          ¡r a hely‚re, ‚s a teljes k‚perny“t  ll¡tja be
                                          aktu lis ablaknak). */
int menu(int x, int y, char **items, int old, int esc, int keret, char *fejlec);
					/* Ment hoz l‚tre. A menpontok az "items"
					  string-t”mbben t rolhat¢k, a v‚g‚n NULL-lal. "old"=
					  a 'default', vagy el“z“ v laszt s ‚rt‚ke,
					  ide kerl kezdetben a kurzor. "esc" az
					  Esc gomb megnyom sa eset‚n visszaadand¢
					  k¢d. A kiv lasztott menpont sorsz ma
					  a visszat‚r‚si ‚rt‚k (ill. az "esc" k¢d).
					  Ha valamelyik koordin ta <=0, akkor abban
					  az ir nyban k”z‚pre kerl a men. Negat¡v
                                          sz mn l megfelel“ m‚ret– bal/fels“ marg¢hoz
                                          k‚pest lesz k”z‚pen az ablak. (0,0)-n l
                                          t”rl“dik a k‚perny“. A "keret" jelent‚se ua.,
                                          mint az "ablak" elj r sn l.

					  A vez‚rl‚sre a fel-le nyilak, a PgUp,
					  PgDn, Home, End ‚s sz¢k”z billenty–k
					  haszn lhat¢k, a kiv laszt s az Enter
					  gombbal t”rt‚nhet. A menpontnak megfelel“
					  sz m (1-9 ill. 0) megnyom sa eset‚n az
					  adott menpont r”gt”n kiv laszt sra kerl. */

static struct scrrec {
  char k[4000];
  char x,y;
  unsigned int wmin,wmax;
  boolean kurz;
} kep[SCREENS];
static unsigned int regbas;
static char cur,col;
static boolean inited=FALSE;

int bill(void) {
  char c;
  unsigned int w;

  asm {
    xor ah,ah
    int 0x16
    mov w,ax
  }
  if (w%256==0) {
    w>>=8;
    w+=1000;
  }
  else w%=256;
  if (w==1059 && helpproc!=NULL) helpproc();      /* F1 eset‚n HELP */
  return w;
}

int gomb(void)
{
  unsigned int w;

gomb_cikl:
  asm {
    mov ah,1
    int 0x16
    jz gomb_cikl
    mov w,ax
  }
  if (w%256==0) {
    w>>=8;
    w+=1000;
  }
  else w%=256;
  if (w!=1038 && w!=1048 && w!=27 && w!=1068) return bill();
  else return w;
}

static void crt2_init(void)
{
  int f;
  char mode;

  asm {
    mov ah,0x0F
    int 0x10
    mov mode,al
  }
  switch (mode) {
    case 0:
    case 2:
    case 7: {
      scrbase=0xb000;
      regbas=0x3b4;
//      cur=11;
      cur=6;
      col=7;
    } break;
    case 4:
    case 5:
    case 6: {                    /* If we are in a graphic mode we try to switch back to some text mode */
      for (f=3; f>=0; f--) {
        asm {
          mov ax,f
          int 0x10
          mov ah,0x0F
          int 0x10
          mov mode,al
        }
        if (mode==f) crt2_init();
      }
    }
    default: {
      scrbase=0xb800;
      regbas=0x3d4;
//      cur=12;
      cur=11;
      col=15;
    }
  }
  inited=TRUE;
}

void kurzor(boolean igen)
{
  if (!inited) crt2_init();
  kur=igen;
  outportb(regbas,10);
  outportb(regbas+1,igen ? cur:15);
  outportb(regbas,11);
  outportb(regbas+1,igen ? cur+1:14);
}

static char scrmem_r(unsigned int addr)
{
  char c;

  asm {
    mov bx,addr
    mov ax,scrbase
    mov es,ax
    mov al,es:[bx]
    mov c,al
  }
  return c;
}

static void scrmem_w(unsigned int addr, char d)
{
  asm {
    mov bx,addr
    mov ax,scrbase
    mov es,ax
    mov al,d
    mov es:[bx],al
  }
}

void scrsave(int i)
{
  unsigned int f;
  struct text_info ti;

  if (!inited) crt2_init();
  if (abs(i)>SCREENS || i==0) return;
  if (i>0) {
    for (f=0; f<4000; f++) kep[i].k[f]=scrmem_r(f);
    kep[i].x=wherex();
    kep[i].y=wherey();
    kep[i].kurz=kur;
    gettextinfo(&ti);
    kep[i].wmin=ti.winleft+256*ti.wintop;
    kep[i].wmax=ti.winright+256*ti.winbottom;
  }
  else {
    window(1+kep[-i].wmin%256,1+kep[-i].wmin>>8,1+kep[-i].wmax%256,1+kep[-i].wmax>>8);
    clrscr();
    for (f=0; f<4000; f++) scrmem_w(f,kep[-i].k[f]);
    gotoxy(kep[-i].x,kep[-i].y);
    kurzor(kep[-i].kurz);
  }
}

void highlight(int x, int y, int len)
{
  int f;
  unsigned int addr;
  char v,w;

  if (!inited) crt2_init();
  if (x+len>81) len=81-x;
  for (f=1; f<=len; f++) {
    addr=1+(x-2+f)*2+(y-1)*160;
    v=scrmem_r(addr);
    asm {
      push ax
      mov al,v
      and al,248
      mov ah,v
      shr ah,4
      and ah,7
      or al,ah
      and al,143
      mov ah,v
      and ah,7
      shl ah,4
      or al,ah
      mov v,al
      pop ax
    }
    scrmem_w(addr,v);
  }
}

void print(char *s)
{
  char *p;

  for (p=s; p!=NULL; p=strchr(p,' ')) if (*(p+1)==' ') {
    *(p+1)='\0';
    break;
  }
  printf("%s",s);
}

void println(char *s)
{
  print(s);
  printf("\r\n");
}

void printhigh(char *s)
{
  boolean flag2,flag3;
  int f;

  if (!inited) crt2_init();
  flag2=FALSE;
  flag3=FALSE;
  textcolor(col);
  textbackground(0);
  for (f=0; f<strlen(s); f++) {
    switch(s[f]) {
      case '~': {
        flag2=!flag2;
        textcolor(flag2 ? 14:col);
      } break;
      case '@': {
        flag3=!flag3;
        textbackground(flag3 ? col:0);
        textcolor(flag3 ? 0:col);
      } break;
      default: cprintf("%c",s[f]);
    }
  }
  textcolor(col);
  textbackground(0);
}

void printstatus(char *s)
{
  boolean flag2=FALSE,flag3=FALSE;
  int f,g;
  char s1[80];
  char cols[80];
  char actcol;

  if (!inited) crt2_init();
  flag2=FALSE;
  flag3=FALSE;
  actcol=col;
  *s1='\0';
  for (f=0; f<80; f++) cols[f]=backgroundcolor;
  g=1;
  for (f=0; f<strlen(s); f++) {
    switch (s[f]) {
      case '~': {
        flag2=!flag2;
        if (flag2) actcol=(flag3 ? (col-1)*(col+1):14);
        else actcol=(flag3 ? col*8:col);
      } break;
      case '@': {
        flag3=!flag3;
        if (flag3) actcol=(flag2 ? (col-1)*(col+1):col*8);
        else actcol=(flag2 ? 14:col);
      } break;
      default: {
        s1[g]=s[f];
        cols[g]=actcol;
        g++;
      }
    }
  }
  for (;g<80; g++) s1[g]=' ';
  for (f=0; f<80; f++) {
    scrmem_w(f*2+3838,s1[f]);
    scrmem_w(f*2+3839,cols[f]);
  }
}

void getstr(char *dest, char *def)
{
  int f,x,ox,oy;
  char s[256];

  if (!inited) crt2_init();
  printstatus("  ~Ctrl+BackSpace~ A teljes mez“ t”rl‚se  ~\033\032~ Mozg s  ~Enter~, ~Tab~ OK  ~Esc~ Kil‚p‚s");
  kurzor(TRUE);
  strcpy(s,def);
  x=strlen(s);
  ox=wherex();
  oy=wherey();
  printf("%s",s);
  for (f=0; f!=27; ) {
    gotoxy(ox+x+1,oy);
    f=bill();
    switch (f) {
      case 9:
      case 13: {
        strcpy(dest,s);
        return;
      }
      case 27: {
        strcpy(dest,def);
        return;
      }
      case 127: {
        gotoxy(ox,oy);
        for (x=0; x<strlen(s); x++) printf(" ");
        *s='\0';
        x=0;
      } break;
      case 1071: x=0; break;
      case 1079: x=strlen(s); break;
      case 1075: if (x>0) x--; break;
      case 1077: if (x<strlen(s)) x++; break;
      case 1083: {
        strcpy(s+x,s+x+1);
        gotoxy(ox,oy);
        printf("%s ",s);
      } break;
      case 8: {
        if (x>0) {
          strcpy(s+x-1,s+x);
          x--;
          gotoxy(ox,oy);
          printf("%s ",s);
        }
      } break;
      default: {
        if (f<256) {
          strcpy(s+x+1,s+x);
          s[x]=f;
          gotoxy(ox,oy);
          printf("%s",s);
          x++;
        }
      }
    }
  }
}

int getint(int def)
{
  int x,y,i,code;
  char s[256],s2[10];

  if (!inited) crt2_init();
  x=wherex();
  y=wherey();
  for (code=0; code>0; ) {
    if (def==0) getstr(s,"");
    else {
      sprintf(s2,"%d",def);
      getstr(s,s2);
    }
    if (*s=='\0') {
      i=0;
      printf("0");
      code=1;
    }
    else {
      code=sscanf(s,"%d",&i);
      if (code<1) {
#ifdef __MSDOS__
        sound(1000);
        delay(5);
        nosound();
#endif
        gotoxy(x,y);
        for (code=0; code<strlen(s); code++) printf(" ");
        gotoxy(x,y);
      }
    }
  }
  return i;
}

float getreal(float def)
{
  float a;
  int x,y,code;
  char s[256],s2[32];

  if (!inited) crt2_init();
  x=wherex();
  y=wherey();
  for (code=0; code>0; ) {
    if (def==0) getstr(s,"");
    else {
      sprintf(s2,"%15.5f",def);
      for (; s[strlen(s)-1]=='0'; s[strlen(s)-1]='\0');
      if (s[strlen(s)-1]=='.') s[strlen(s)-1]='\0';
      for (; s[1]==' '; strcpy(s,s+1));
      getstr(s,s2);
    }
    if (*s=='\0') {
      a=0.0;
      printf("0");
      code=1;
    }
    else {
      for (code=0; code<strlen(s); code++) if (s[code]==',') s[code]='.';
      code=sscanf(s,"%f",&a);
      if (code<1) {
#ifdef __MSDOS__
        sound(1000);
        delay(5);
        nosound();
#endif
        gotoxy(x,y);
        for (code=0; code<strlen(s); code++) printf(" ");
        gotoxy(x,y);
      }
    }
  }
  return a;
}

void ablak(int x, int y, int szel, int mag, int keret, char *fejlec)
{
  char s[256];
  int f;
  char box[6];

  if (!inited) crt2_init();
  if (keret>=0) {
    switch (keret) {
      case 0: strcpy(box,"      "); break;
      case 1: strcpy(box,"Ú¿³ÀÙÄ"); break;
      case 2: strcpy(box,"Õ¸³Ô¾Í"); break;
      case 3: strcpy(box,"Ö·ºÓ½Ä"); break;
      case 4: strcpy(box,"É»ºÈ¼Í"); break;
    }
    s[szel]='\0';
    for (f=1; f<szel-1; f++) s[f]=box[5];
    s[0]=box[0];
    s[szel-1]=box[1];
    gotoxy(x,y);
    cprintf("%s",s);
    for (f=y+1; f<y+mag; f++) {
      gotoxy(x,f);
      putch(box[2]);
      gotoxy(x+szel-1,f);
      putch(box[2]);
    }
    gotoxy(x,y+mag-1);
    s[0]=box[3];
    s[szel-1]=box[4];
    cprintf("%s",s);
    textcolor(14);
    gotoxy(x+(szel-strlen(fejlec))/2-1,y);
    if (*fejlec!='\0') cprintf(" %s ",fejlec);
    textcolor(col);
    xsize=szel-2;
    ysize=mag-2;
    xorig=x+1;
    yorig=y+1;
    window(x+1,y+1,x+xsize,y+ysize);
    clrscr();
  }
  else {
    xsize=szel;
    ysize=mag;
    xorig=x;
    yorig=y;
    window(x,y,x+xsize-1,y+ysize-1);
    if (*fejlec!='\0') clrscr();
  }
  gotoxy(1,1);
}

void clearwindow()
{
  int a,b,c,d,f,g;

  if (!inited) crt2_init();
  window(1,1,80,25);
  gotoxy(1,1);
  a=yorig+ysize;
  b=yorig-1;
  c=xorig-1;
  d=xorig+xsize;
  if (a>80) a=80;
  if (d>80) d=80;
  if (b<1) b=1;
  if (c<1) c=1;
  for (g=a; g>=b; g--) for (f=c; f<=d; f++) {
    scrmem_w(f*2+g*160-162,background);
    scrmem_w(f*2+g*160-161,backgroundcolor);
  }
  xsize=80;
  ysize=25;
  xorig=1;
  yorig=1;
}

int menu(int x, int y, char **items, int old, int esc, int keret, char *fejlec)
{
  int valaszt,choice,len,f,g,item;
  boolean flag;

  if (!inited) crt2_init();
  kurzor(FALSE);
  window(1,1,80,25);
  if (x==0 && y==0) clrscr();
  len=0;
  for (item=0; items[item]!=NULL; item++);
  for (f=0; f<item; f++) if (len<strlen(items[f])) len=strlen(items[f]);
  if (item>9) len++;
  len+=4;
  if (x<=0) {
    x=(82-len-x)/2;
    if (strlen(fejlec)>len) x=(82-strlen(fejlec))/2;
  }
  if (y<=0) y=(24-item-y)/2;
  if (len>strlen(fejlec)) ablak(x-1,y,len+2,item+2,keret,fejlec);
  else ablak(x-2,y,strlen(fejlec)+4,item+2,keret,fejlec);
  window(1,1,80,25);
  for (f=0; f<item;f ++) {
    gotoxy(x,y+f+1);
    if (f<10 && item>9) printf(" ");
    textcolor(12);
    cprintf("%d.",f+1);
    textcolor(col);
    cprintf(" %s",items[f]);
  }
  choice=old;
  highlight(x+(item<10 ? 3:4),y+choice,len-4);
  for (flag=TRUE; flag; ) {
    f=bill();
    if (f>1000 || f==' ') highlight(x+(item<10 ? 3:4),y+choice,len-4);
    switch (f) {
      case 1071: choice=1; break;
      case 1079: choice=item; break;
      case 1073: {
        choice-=5;
        if (choice<1) choice=1;
      } break;
      case 1081: {
        choice+=5;
        if (choice>item) choice=item;
      } break;
      case 1072: {
        if (choice>1) choice--;
        else choice=item;
      } break;
      case 1080:
      case 32: {
        if (choice<item) choice++;
        else choice=1;
      } break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9': {
        if (f-'0'<=item && !(f=='0' && item<10)) {
          valaszt=(f=='0' ? 10:f-'0');
          if (f!=choice) {
            highlight(x,y+choice,len);
            highlight(x+(item<10 ? 3:4),valaszt,len-4);
          }
          flag=FALSE;
        }
      } break;
      case 13: {
        valaszt=choice;
        flag=FALSE;
      } break;
      case 27: {
        valaszt=esc;
        flag=FALSE;
      } break;
    }
    if (f>1000 || f==' ') highlight(x+(item<10 ? 3:4),y+choice,len-4);
  }
  kurzor(TRUE);
  clearwindow();
  return valaszt;
}

