#!/afs/athena/contrib/perl/perl

$debug = 1;
@pnums = (1, 2, 3, 4);
require 'sys/socket.ph';
($port) = @ARGV;
$port = 2345 unless $port;

$AF_INET = 2;
$SOCK_STREAM = 1;

$sockaddr = 'S n a4 x8';

($name, $aliases, $proto) = getprotobyname('tcp');
if ($port !~ /^\d+$/) {
    ($name, $aliases, $port) = getservbyport($port, 'tcp');
}

print "Port = $port\n";

$this = pack($sockaddr, $AF_INET, $port, "\0\0\0\0");

select(NS); $| = 1; select(stdout);

socket(S, &AF_INET, &SOCK_STREAM, $proto) || die "socket: $!";
bind(S,$this) || die "bind: $!";
listen(S,5) || die "connect: $!";

select(S); $| = 1; select(stdout);

$fn = fileno(S);
print("Base socket fileno: $fn\n");

$con = 0;
$fh = 'AA';
$fhs = 'S ';
$bitn=1;
$fha[0]='S';
$maxid = 0;

print "Listening for connection 1....\n";
$/ = "\n";
for(;;) {
    chop($fhs);
    $rin = &fhbits($fhs);
    $orin = $rin;
    #Get bitmask

    $fhs .= ' ';
    $ein = $rin;
    $nfound = select($rin, undef, undef, 1);
    #Do select


#   That line above needs to be fixed.
#   Disconections change it.

    if(vec($rin, fileno(S), 1)){
	&new_connection();
    }

    while($nfound){


	print("There are $nfound pending ports.Bitmask: ($rin)\n") if $debug;


	for $f (reverse(1..$#fha)){

	    print("Checking port $f in bitmask $rin\n") if $debug;

	    if(vec($rin,fileno($fha[$f]),1)){
		$foo = $fha[$f];
		print("Reading from $f,$foo...\n") if $debug;
		$nbread = sysread($foo, $output, 128);
		$fhs = join(' ', @fha);
		$fhs .=' ';
		chop($output);    #chop linefeed
		if(substr($output, length($output)-1, 1) eq "\r"){
		    chop($output);} #chop CR
		print("Read from $f,$foo: [$output] (cleaned up)\n") if $debug;
		#say hello
		if(!$nbread){
		    #Dead connection
		    $ofh = splice(@fha, $f,1);
		    splice(@everyone, $f,1);
		    $fhs = join(' ', @fha);
		    $fhs .=' ';
		    $name = splice(@name, $f, 1);
		    &tell("leftgame: $name $f\n", @everyone);
		    for $i (1..4){
			if($sequence[$i] == $f){
			    $sequence[$i]=0;
			    unshift(@pnums, $f);
			}
		    }
		    $sequence[$f] = 0;
		    print("Connection port $f dead.  Removing name and fh entry.\n") if $debug;
		}
		&user_input($f, $output);

		print("\n") if $debug;
	    }
	}
	print("Done.  Doing select again.\n") if $debug;
	&myselect();
    }

}

sub fhbits {
    local(@fhlist) = split(' ',$_[0]);
    local($bits);
    for (@fhlist) {
	vec($bits,fileno($_),1) = 1;
	$obits = ord($bits);
	$fno = fileno($_);
	print(",$_($bits)($obits)($fno),") if $debug;
    }
    print("\n") if $debug;
    $bits;
}

sub new_connection {
    if($#fha >=4){
	&disconnect(fileno($fh));
	return;
    }
    ($addr = accept($fh,S)) || die $!;
    push(@fha, $fh);
    push(@everyone, $fh);
    $fhs =join(' ', @fha).' ';
    $fh++;
    ($af,$port,$inetaddr) = unpack($sockaddr,$addr);
    $date = time;
    ($hostname,$aliases,$addrtype,$length,@addrs) = gethostbyaddr($inetaddr, 2);
    $fn = fileno($fha[$#fha]);
    $hostname[fileno($fha[$#fha])] = $hostname;
    print("Connection made from $hostname($fn) at $date. ($fhs)\n") if $debug;
    select(@fha[$#fha]); $|=1;
    print("Connect please\n");
    select(stdout);
}

#
#  Player info
#
#  Players 1&3 and 2&4 are partners
#  Each player has a hand, $hand[playernum] eg, "4h 4s 5s 8s qs"
#  A bid, $bid[playernum], a number of tricks $tricks[playernum]

#
#  Protocol
#

#  Client->Server messages
#
#  joingame: name
#  playcard: card #
#  taketrick
#  tabletalk: message ...
#  bid: bid
#  status

#  Server->Client messages
#
#  joinedgame: name #
#  leftgame: name #
#  havecards: card1 card2 ...
#  tabletalk: # message ...
#  announce: message ...


sub user_input {
    local($num, $text)=@_;

    $text =~ s/[\e\b\cg\ch\ci\cj\ck\cl\cm\cn\co]//g;
    ($command, @opts) = split(' ', $text);
    if($command eq 'joingame:'){
	&joingame($num, @opts);
    }
    elsif($command eq 'playcard:'){
	&playcard($num, @opts);
    }
    elsif($command eq 'tabletalk:'){
	&ttalk($num, @opts);
    }

    print("($#fha: $num//$text//\n");
}

sub ttalk {
    local($num, @opts) = @_;

    &tell("tabletalk: $num @opts\n", @everyone);
}

sub joingame {
    local($num, @opts)= @_;

    if(!$name[$num]){
	$name[$num] = $opts[0];
	$sequence[shift(@pnums)] = $num;
	&tell("joinedgame: $name[$num] $num\n", @everyone);
    }
    else{
	&tell("error: You have already joined the game as $name[$num]\n", $fha[$num]);
    }
}

sub tell {
	local($message, @handles)=@_;
	for $h (@handles) {
	    select($h); $|=1;
	    print($message);
	    select(stdout);
	}
}

sub myselect{

    chop($fhs);
    $rin = &fhbits($fhs);
    $orin = $rin;
    #Get bitmask

    $fhs .= ' ';
    $ein = $rin;
    $nfound = select($rin, undef, undef, 1);
    #Do select


    if(vec($rin, fileno(S), 1)){
	&new_connection();
    }


}

sub disconnect {
    local($f) = @_;
    print("Disconnecting F = $f\n");
	close($fha[$f]);
	splice(@fha, $f,1);
	$fhs = join(' ', @fha);
	$fhs .=' ';
	print("Connection port $f dead.  Removing name and fh entry.\n") if $debug;
    $name = $name[$f];
	splice(@name, $f, 1);
    splice(@everyone, $f, 1);
#	$contents[$here] =~ s/$id{$name}//;
    &tell("leftgame: $name\n", @everyone);
}


__END__

