#!/usr/bin/perl -w

# use strict;
use IO::Socket;

# clientsarray: xno, yno, conn, host, port, cols, rows, x1, x2, y1, y2
my @clients = ( [
		 { xno => 0, yno => 0,
		   conn => undef,
		   host => "localhost",
		   port => "2342",
		   cols => undef, rows => undef,
		   x1 => undef, x2 => undef,
		   y1 => undef, y2 => undef
		   } ,
		 { xno => 1, yno => 0,
		   conn => undef,
		   host => "localhost",
		   port => "2343",
		   cols => undef, rows => undef,
		   x1 => undef, x2 => undef,
		   y1 => undef, y2 => undef
		   }
		 ],
		[
		 { xno => 0, yno => 1,
		   conn => undef,
		   host => "localhost",
		   port => "2344",
		   cols => undef, rows => undef,
		   x1 => undef, x2 => undef,
		   y1 => undef, y2 => undef
		   }
		 ]
	     );

my ( $gcols, $grows ) = ( 0, 0 );

sub connect_client {
    my ( $remote, $port );
    my ( $iaddr, $paddr, $proto, $line );
    
    $remote  = shift || 'localhost';
    $port    = shift || 2342;  # random port

    my $conn_hand = IO::Socket::INET->new(
				    Proto    => "tcp",
				    PeerAddr => $remote,
				    PeerPort => $port
				       )
	or die "ERROR: connect_client: Cannot connect to port $port at $remote\n";

    $conn_hand->autoflush(1);
    print $conn_hand "get termsize\n";
    # send( SOCK, "get termsize\n", 0);
    my ( $cols, $rows ) = ( 0, 0 );
    if (defined(my $line = <$conn_hand>)) {
	print $line;
	if ( $line =~ /^cols:\s(\d*?),\srows:\s(\d*?)$/ ) {
	    $cols = $1;
	    $rows = $2;
	    print "termsize: ok $cols $rows\n";
	    return(0, $conn_hand, $cols, $rows);
	} else {
	    print "termsize: error";
	    return(1);
	}
    }
}


sub disconnect_client{
    close ($_[0])            || die "close: $!";
}

sub connect_clients {
# clientsarray: xno, yno, conn, host, port, cols, rows, x1, x2, y1, y2
    my ( $xtmp, $ytmp ) = ( 0, 0 );
    foreach my $y (0..$#clients) {
	my $ymin = 0;
	foreach my $x (0.. $#{$clients[$y]}) {
	    # print "init $x $y\n";
	    my $client = \%{ $clients[$y]->[$x] };
	    my ( $retval, $conn_hand, $cols, $rows ) = connect_client( $client->{host}, $client->{port} );
	    if ( $retval != 0 ) {
		die "ERROR: Couldn't establish a connection.\n";
		return(1);
	    } else {
		$client->{conn} = $conn_hand;
		$client->{cols} = $cols;
		$client->{rows} = $rows;
		$client->{x1} = $xtmp;
		$xtmp += $cols;
		$client->{x2} = $xtmp - 1;
		$client->{y1} = $ytmp;
		# $ytmp += $rows;
		$client->{y2} = $ytmp + $rows - 1;
		if ( $xtmp > ( $gcols - 1 ) ) {
		    $gcols = $xtmp - 1;
		}
		if ( ( $ytmp + $rows - 1 )  > ( $grows - 1 ) ) {
		    $grows = $ytmp + $rows - 1;
		}
		if ( ( $ymin == 0 ) || ( ( $rows -1 ) < $ymin ) ) {
		    $ymin = $rows - 1;
		}
	    }
	}
	$xtmp = 0;
	$ytmp = $ytmp + $ymin;
    }
    return(0);
}

sub show_client_info {
    my %client = %{ $_[0] };

    print "client info:\n";
    # foreach my $key (keys %client) {
    foreach my $key ( "xno", "yno", "conn", "host", "port", "cols", "rows", "x1", "x2", "y1", "y2" ) {
	print "\t$key -> ", $client{$key}, "\n";
    }
}

sub all_clients{
    my $funcref = $_[0];
    foreach my $y (0..$#clients) {
	foreach my $x (0.. $#{$clients[$y]}) {
	    &$funcref( $clients[$y]->[$x] );
	}
    }
}

sub show_clients_info {
    all_clients( sub{ show_client_info( $_[0] ) } );
}

sub disconnect_clients {
    all_clients( sub{ disconnect_client( $_[0]->{conn} ) } );
}

sub clrscr_core {
    print {$_[0]} "\e[H\e[J";
}

sub clrscr {
    all_clients( sub{ clrscr_core( $_[0]->{conn} ) } );
}

sub home_core {
    print {$_[0]} "\e[H";
}

sub home {
    all_clients( sub{ home_core( $_[0]->{conn} ) } );
}

sub gotoxy_core { 
    print {$_[0]} "\e[".$_[2].";".$_[1]."H";
}

sub gotoxy {
    my ( $xx, $yy ) = @_;
    my $found = 0;
    foreach my $y (0..$#clients) {
	foreach my $x (0.. $#{$clients[$y]}) {
	    my $client = \%{ $clients[$y]->[$x] };
	    if ( ( $client->{x1} <= $xx ) && ( $xx <= $client->{x2} ) &&
		 ( $client->{y1} <= $yy ) && ( $yy <= $client->{y2} ) ) {
		gotoxy_core( $client->{conn},
			     $xx - $client->{x1},
			     $yy - $client->{y1} );
		$found = $client->{conn};
	    }
	}
    }
    if ( $found == 0 ) {
	print "ERROR: gotoxy: couldn't goto $xx, $yy.\n";
	return(1);
    } else {
	return( $found );
    }
}

sub printxy {
    my ( $xx, $yy, $mesg ) = @_;
    if ( ( my $hand = gotoxy( $xx, $yy ) ) != 1 ) {
	print $hand $mesg;
    }
}

sub printallxy{
    my ( $xx, $yy, $mesg ) = @_;
	all_clients( sub{ gotoxy_core( $_[0]->{conn}, $xx, $yy );
			  print {$_[0]->{conn}} $mesg} );
}

sub printallcenter{
    my $mesg = $_[0];
	all_clients( sub{ gotoxy_core( $_[0]->{conn},
				       int( ( $_[0]->{cols} - 1 ) / 2 ),
				       int( ( $_[0]->{rows} - 1 ) / 2 ) );
			  print {$_[0]->{conn}} $mesg} );
}

connect_clients();
show_clients_info();

clrscr();
printxy( 3, 45, "world" );
printallxy( 10, 10, "foo" );
printallcenter( "hello" );

# print {$clients[0]->[0]->{conn}} "\e[H\e[J";
# print {$clients[0]->[1]->{conn}} "hello, world";

disconnect_clients();
