#include <bios.h>
#include <stdio.h>
#define COM1 0
#define COM2 1

#define THISLONG 250
#define DATA_READY 0x100
#define NOT_SENT 0x8000

class LASER {
unsigned char *buffer;
unsigned char start,end;
int port;
int count;
int chan;
void fillbuffer(){
	for(int a=0;a<THISLONG;++a) if (bioscom(3,0,port)& DATA_READY) {
		buffer[end++]=bioscom(2,0,port);
		a=0;
		}
	}
int receive(){
	fillbuffer();
	if (start!=end) return buffer[start++]&0x7F;
	return -1;
	}
void flush(){
	fillbuffer();
	start=end;
	}
int receiveraw(){
	fillbuffer();
	if (start!=end) return buffer[start++];
	return -1;
	}
void send(char c){
	int a;
	while (bioscom(1,c,port) & NOT_SENT) fillbuffer();
	fillbuffer();
	}
void sendstring(char *s){
	while (*s)send (*(s++));
	}
int waitfor(char c){
	for (int a=0;a<THISLONG;++a){
		int b=receive();
		if (b==29) return 0;
		if (b==c) return 1;
		}
	return -1;
	}
int sendncheck(char c){
	int a;
	flush();
	send(c);
	a=waitfor(c);
	if (a>=0) return a;
	reset();
	flush();
	send(c);
	return waitfor(c)==1;
	}

public:
LASER(int p){
	int a;
	port=p;
	start=0;
	end=0;
	count=0;
	chan=3;
	bioscom(0,0xE3,port);
	buffer=new unsigned char[256];
	for (a=0;a<THISLONG;++a){
		send('h');
		if (receive()=='h') break;
		send('A');
		}
	flush();
	}
~LASER(){
	for (int a=0;a<THISLONG;++a){
		send('m');
		if (receive()=='m') break;
		send('A');
		}
	flush();
	delete buffer;
	}
int stop(){
	send('/');
	for (int a=0;a<THISLONG;++a){
		int b=waitfor('/');
		if (b>0) return b;
		}
	return waitfor('/');
	}
int play(){
	send('%');
	for (int a=0;a<THISLONG;++a){
		int b=waitfor('%');
		if (b>0) return b;
		}
	return waitfor('%');
	}
int back3x(){
	return sendncheck('&');
	}
int backscan(){
	return sendncheck('\'');
	}
int backslow(){
	return sendncheck('(');
	}
int backstep(int s=-1){
	char n[20];
	if (s==-1) return sendncheck(')');
	sprintf(n,"E%i\0",s);
	sendstring(n);
	return sendncheck('A') && (waitfor('E')==1);
	}
int pause(){
	return sendncheck('*');
	}
int backplay(){
	return sendncheck('B');
	}
int counter(int c=-1){
	if (c<0) count=(count+1)%3;
	else count=c;
	flush();
	switch(count){
		case 0:
			return sendncheck('M') && sendncheck('O');
		case 1:
			return sendncheck('O') && sendncheck('L');
		case 2:
			return sendncheck('M') && sendncheck('N');
		}
	}

int channel(int c=-1){
char next[4]={2,0,3,1};
int result=1;
if (c==-1) c=next[chan];
if ((c&1) != (chan&1)){
	if (c&1) result&=sendncheck('H');
	else result&=sendncheck('I');
	}
if ((c&2) != (chan&2)){
	if (c&2) result&=sendncheck('J');
	else result&=sendncheck('K');
	}
if (result) chan=c;
return result;
}

int status(){
while (!sendncheck('j'));
send(0x7F);
return receiveraw()|(receiveraw()<<8);
}

int framenumber(){
while (!sendncheck('k'));
return (receiveraw()<<8)|receiveraw();
}

int fore3x(){
return sendncheck('!');
}

int forescan(){
return sendncheck('\"');
}

int foreslow(){
return sendncheck('#');
}

int forestep(int a=-1){
char n[20];
if (a==-1) return sendncheck('$');
sprintf(n,"D%i\0",a);
sendstring(n);
return sendncheck('A') && (waitfor('D')==1);
}

int foreskip(int a){
char n[20];
sprintf(n,"F%i\0",a);
sendstring(n);
return sendncheck('A') && (waitfor('F')==1);
}

int backskip(int a){
char n[20];
sprintf(n,"G%i\0",a);
sendstring(n);
return sendncheck('A') && (waitfor('G')==1);
}

int gotoframe(int a){
char n[20];
sprintf(n,"+:%i\0",a);
sendstring(n);
if (sendncheck('A')){
	int a=framenumber();
	for (int b=0;b<10;++b){
		if (a!=framenumber() || a>65000){
			b=0;
			a=framenumber();
			}
		}
	return 1;
	}
return 0;
}

int gotochapter(int a){
char n[20];
sprintf(n,"+,%i\0",a);
sendstring(n);
if (sendncheck('A')){
	int a=framenumber();
	for (int b=0;b<10;++b){
		if (a!=framenumber() ||  a>65000){
			b=0;
			a=framenumber();
			}
		}
	return 1;
	}
return 0;
}

void reset(){
int c;
send('A');
send('m');
send('h');
c=count;
count=0;
counter(c);
c=chan;
chan=3;
channel(c);
}
};
