#!/usr/bin/perl -w

use strict;
use IO::Select;
use IPC::Open2;
use IO::Handle;

@ARGV == 2
	or die "syntax: $0 number command\n";

my $n = shift;
my $command = "@ARGV";

my (@reads, @writes);

for my $i (1..$n) {
	my ($read, $write);
	open2($read, $write, $command);
	push @reads, $read;
	push @writes, $write;
}

#open SWITCH_WRITE, ">switch_file"
#	or die "open: $!\n";
#open SWITCH_READ, "tail -n +1 -f switch_file |"
#	or die "open: $!\n";

pipe (SWITCH_READ, SWITCH_WRITE) or die "pipe: $!\n";
SWITCH_WRITE->autoflush(1);

my $pid;
if ($pid = fork()) { #XXX
	# parent - will handle output
	output();
} elsif (defined $pid) {
	# child - will handle input
	input();
} else {
	die "fork: $!\n";
}

exit 0;

sub input {
	close SWITCH_READ;
	for (@reads) {
		close $_;
	}
	undef @reads;
	my $select = IO::Select->new;
	my $i = 0;
	my %index_by_write;
	for (@writes) {
		$select->add($_);
		$index_by_write{$_} = $i++;
	}
	my $line;
	while (defined ($line = <STDIN>)) {
		my ($fh) = $select->can_write;
		print $fh $line;
		my $switch = $index_by_write{$fh};
		print SWITCH_WRITE "$switch\n";
	}
	close SWITCH_WRITE;
	for (@writes) {
		close $_;
	}
}

sub output {
	close SWITCH_WRITE;
	for (@writes) {
		close $_;
	}
	my $select = IO::Select->new;
	$select->add(\*SWITCH_READ);
	undef @writes;
	my $switch;
	my @queue;
	my $fh;
	while ($select->count) {
		($fh) = $select->can_read;
		if ($fh == \*SWITCH_READ) {
			my $switch = <SWITCH_READ>;
			if (defined $switch) {
				my $read = $reads[$switch];
				unless (@queue) {
					$select->add($read);
				}
				push @queue, $read;
			} else {
				$select->remove(\*SWITCH_READ);
			}
		} else {
			my $read = shift @queue;
			if ($read != $fh) {
				die "ohno!";
			}
			$select->remove($read);
			if (@queue) {
				$select->add($queue[0]);
			}
			my $line = <$fh>;
			print $line;
		}
	}
	for (@reads) {
		close $_;
	}
	close SWITCH_READ;
}
