# TextServerClient.pm
# 
# Copyright (c) 2010 Accenture. All rights reserved.
# This component and the accompanying materials are made available
# under the terms of the "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
# 
# Initial Contributors:
# Accenture - Initial contribution
#
package FShell::TextServerClient;

use strict;
use Carp;
use Pcons;

sub new {
        my $proto = shift;
        my $class = ref($proto) || $proto;
	my $self = {
		PCONS_NAME	=> undef,
		SERVER_PROCESS	=> undef,
		SERVER_PROMPT	=> 'ok',
		PCONS_READER	=> undef,
		PCONS_WRITER	=> undef,
	};
	bless ($self, $class);
	return $self;
}

sub Connected {
	my ($self) = @_;
	return (defined $self->{PCONS_READER}) && (defined $self->{PCONS_WRITER});
}

sub PconsName {
	my ($self, $name) = @_;
	if (defined $name) {
		croak "Cannot change pcons name while connected" if ($self->Connected());
		$self->{PCONS_NAME} = $name;
	}
	return $self->{PCONS_NAME};
}

sub ServerProcess {
	my ($self, $proc) = @_;
	if (defined $proc) {
		croak "Cannot set server process while connected" if ($self->Connected());
		$self->{SERVER_PROCESS} = $proc;
	}
	return $self->{SERVER_PROCESS};
}

sub Disconnect {
	my ($self) = @_;
	undef $self->{PCONS_READER};
	undef $self->{PCONS_WRITER};
}

sub Connect {
	my ($self) = @_;
	croak "Cannot connect to server before process has been set" if (!defined $self->ServerProcess());
	croak "Cannot connect to server becore persisten console name has been set" if (!defined $self->PconsName());
	return if (Connected());

	my $reader = Pcons::OpenReader($self->{PCONS_NAME});
	if (!defined $reader) {
		$self->{SERVER_PROCESS} =~ s|^\s*||;
		my ($procName, @procArgs) = split(/\s/, $self->{SERVER_PROCESS});
		Pcons::Create($self->{PCONS_NAME}, $procName, join(' ', @procArgs)) or croak "Cannot create persistent console $self->{PCONS_NAME} with process $procName: $!";
		$reader = Pcons::OpenReader($self->{PCONS_NAME}) or croak ("Cannot open pcons reader to '$self->{PCONS_NAME}': $!");
		$self->WaitPrompt($reader) or croak ("Prompt $self->{SERVER_PROMPT} not received from server");
	}
	my $writer = Pcons::OpenWriter($self->{PCONS_NAME});
	croak ("Cannot open pcons writer to '$self->{PCONS_NAME}': $!") unless defined $writer;
	$self->{PCONS_WRITER} = $writer;
	$self->{PCONS_READER} = $reader;
	return 1;
}

sub WaitPrompt {
	my ($self, $reader) = @_;
	my @lines;
	$reader = $self->{PCONS_READER} unless defined $reader;
	while (my $line = <$reader>) {
		chomp $line;
		return \@lines if ($line eq $self->{SERVER_PROMPT});
		push @lines, $line;
	}
	return undef;
}

sub Execute {
	my ($self, $command) = @_;
	croak "Not connected to server" unless $self->Connected();
	croak "No command specified" unless (defined $command);
	my $writer = $self->{PCONS_WRITER};
	print $writer "$command\n";
	return $self->WaitPrompt();
}

1;

__END__

=head1 NAME

FShell::TextServerClient - perl interface to Fshell server commands

=head1 SYNOPSIS

	use FShell::TextServerClient;

	my $client = new Fshell::TextServerClient;
	$client->PconsName('server_console');
	$client->ServerProcess('server_executable --arguments');
	$client->Connect();

	my $output = $client->Execute('command');
	foreach (@$output) {
		process_line($_);
	}

=head1 DESCRIPTION

This module provides a perl interface to FShell command servers, i.e. those FShell commands the derive from
class C<CServerCommandBase>. This module is analgous to the C++ class C<CClientBase>, providing similar
functionality in perl.

=head1 COPYRIGHT

Copyright (c) 2009-2010 Accenture. All rights reserved.

=head1 VERSION

Version 0.01 (April 1st, 2009)

=head1 SEE ALSO

perl(1)
Pcons

=cut
