/usr/local/CPAN/new.spirit/NewSpirit/SqlShell/Text.pm


package NewSpirit::SqlShell::Text;
use vars qw ( @ISA );

@ISA = qw( NewSpirit::SqlShell );

use strict;
use NewSpirit::SqlShell;
use Text::Wrap;

sub get_verbose			{ shift->{verbose}			}
sub set_verbose			{ shift->{verbose}		= $_[1]	}

sub new {
	my $class = shift;
	my %par = @_;
	my ($verbose) = @par{'verbose'};

	$verbose = 1 if not defined $verbose;

	my $self = $class->SUPER::new(@_);
	
	$self->set_verbose($verbose);
	
	return $self;
}

sub print_current_command {
	my $self = shift;

	return if not $self->{echo};

	print "\n";
	
	my $print_command = $self->{current_command};
	
	$print_command = "> $print_command";
	$print_command =~ s!\n!\n> !g;
	
	print "$print_command\n\n";

	1;
}

sub print_query_result_start {
	my $self = shift;
	
	my %par = @_;
	
	my $title_lref = $par{title_lref};
	
	$self->{__query_row_lref}     = [];
	$self->{__query_row_len_lref} = [];
	
	$self->add_query_row ($title_lref);
	
	1;
}

sub add_query_row {
	my $self = shift;
	
	my ($lref) = @_;
	
	push @{$self->{__query_row_lref}}, $lref;
	
	my $i = 0;
	foreach my $col (@{$lref}) {
		$self->{__query_row_len_lref}->[$i] = length($col)
			if length($col) > $self->{__query_row_len_lref}->[$i];
		++$i;
	}
}

sub print_query_result_row {
	my $self = shift;
	
	my %par = @_;
	
	my $row_lref = $par{row_lref};
	$self->add_query_row ($row_lref);
	
	1;
}

sub print_query_result_end {
	my $self = shift;
	
	#-------------------------------------------------------------
	# Ok, now - at the end - we print the whole collected
	# result set. We know the max width of all columns and
	# are able to produce a nice looking table layout.
	#
	# $self->{__query_row_len_lref}
	#	Holds the maximum widths of the corresponding
	#	columns
	#
	# $self->{__query_row_lref}
	#	Holds all the data. The titles of our columns
	#	are storied at index 0, the data begins with
	#	index 1.
	#-------------------------------------------------------------

	my $style = $self->get_preference ('display_style');
	
	if ( $style eq 'row' ) {
		$self->print_query_result_end_row_style;
	} elsif ( $style eq 'boxed' ) {
		$self->print_query_result_end_boxed_style;
	} elsif ( $style eq 'tab' ) {
		$self->print_query_result_end_tab_style;
	} else {
		# automatic detection
		my $length = 2;
		foreach my $l ( @{$self->{__query_row_len_lref}} ) {
			$length += $l + 3;
		}
		my $screen_width = $self->get_screen_width;
		if ( $length > $screen_width ) {
			$self->print_query_result_end_boxed_style;
		} else {
			$self->print_query_result_end_row_style;
		}
	}
}

sub print_query_result_end_row_style {
	my $self = shift;
	
	my $line   = '';

	my $len_lref = $self->{__query_row_len_lref};

	return if not $self->{__query_row_lref} or
	          not @{$self->{__query_row_lref}};

	foreach my $len ( @{$len_lref} ) {
		$line   .= "+-".("-" x $len)."-";
	}
	$line .= "-+\n";
	
	my $cnt = 0;
	foreach my $row ( @{$self->{__query_row_lref}} ) {
		print $line if $cnt == 0;
		my $i = 0;
		foreach my $col ( @{$row} ) {
			printf ("| %-$len_lref->[$i]s ", $col);
			++$i;
		}
		print " |\n";
		print $line if $cnt == 0;
		++$cnt;
	}

	print $line, "\n";
	
	$self->{__query_row_lref}     = [];
	$self->{__query_row_len_lref} = [];
	
	1;
}

sub print_query_result_end_boxed_style {
	my $self = shift;
	
	my $len_lref   = $self->{__query_row_len_lref};
	my $data_lref  = $self->{__query_row_lref};
	my $title_lref = $data_lref->[0];

	return if not $self->{__query_row_lref} or
	          not @{$self->{__query_row_lref}};
	
	# first compute max length of column titles
	my $title_length = 0;
	foreach my $l ( @{$data_lref->[0]} ) {
		$title_length = length($l) if length($l) > $title_length;
	}
	
	# now compute max length of data columns
	my $data_length = 0;
	foreach my $l ( @{$len_lref} ) {
		$data_length = $l if $l > $data_length;
	}

	my $screen_width = $self->get_screen_width;

	if ( $screen_width < $title_length+$data_length+7 ) {
		$data_length = $screen_width - $title_length - 7;
	}

	my $line   = '';
	foreach my $len ( $title_length, $data_length ) {
		$line   .= "+-".("-" x $len)."-";
	}
	$line .= "+\n";
	
	my $cnt = 0;
	foreach my $row ( @{$data_lref} ) {
		++$cnt;
		next if $cnt == 1;	# skip titles

		print $line;
		my $i = 0;
		foreach my $col ( @{$row} ) {
			if ( length($col) > $data_length ) {
				my $title = $title_lref->[$i];
				while ( $col =~ m/(.{0,$data_length})\n?/g and $1 ) {
					printf (
						"| %-${title_length}s | %-${data_length}s |\n",
						$title, $1
					);
					$title = '';
				}
			} else {
				printf (
					"| %-${title_length}s | %-${data_length}s |\n",
					$title_lref->[$i], $col
				);
			}
			++$i;
		}
		print $line;
		print "\n";
		++$cnt;
	}

	$self->{__query_row_lref}     = [];
	$self->{__query_row_len_lref} = [];
	
	1;
}

sub print_query_result_end_tab_style {
	my $self = shift;
	
	return if not $self->{__query_row_lref} or
	          not @{$self->{__query_row_lref}};

	foreach my $row ( @{$self->{__query_row_lref}} ) {
		print join ("\t", map { s/\t/\\t/g; s/\n/\\n/g; $_ } @{$row}),"\n";
	}
	
	$self->{__query_row_lref}     = [];
	$self->{__query_row_len_lref} = [];
	
	1;
}

sub print_error {
	my $self = shift;

	my ($msg, $comment) = @_;

	print STDERR "ERROR: $msg\n";
	print STDERR "       $comment\n" if $comment;
	
	1;
}

sub info {
	my $self = shift;
	return if not $self->get_verbose;	
	my @p = @_;
	print STDERR "% ", join ("\n%> ", map { s/\n/\n%> /g; $_ } @p ), "\n";
	1;
}

sub error_summary {
	my $self = shift;
	
	return if not @{$self->{errors}};

	$self->info ("Error Summary:",
		     "--------------");
	$self->info ("Found ".@{$self->{errors}}." errors!");
	print "\n";
	
	my $num = 0;
	foreach my $err ( @{$self->{errors}} ) {
		++$num;
		$self->info (
			wrap ("CMD:\t", "\t",$err->{command}."\n"),
			wrap ("MSG:\t", "\t",$err->{msg})
		);
		print "\n";
	}
}

sub print_help_header {
	my $self = shift;
	
	print "Help Page:\n";
	print "==========\n\n";
}

sub print_help_footer {
	my $self = shift;
	
	print "\n";
}

sub cmd_reload {
	my $self = shift;
	
	$self->SUPER::cmd_reload;

	$self->info ("reloading NewSpirit::SqlShell::Text");
	do "NewSpirit/SqlShell/Text.pm";
}

sub get_screen_width {
	my $self = shift;
	
	# $data_length must be smaller than pref:screen_width
	my $screen_width = $self->get_preference('screen_width');
	
	if ( not $screen_width ) {
		# autosize
		eval {
			require Term::ReadKey;
			($screen_width) = Term::ReadKey::GetTerminalSize();
		};
		if ( $@ ) {
			$self->info ("Warning: could not determine screen width! Set to 79.");
			$screen_width = 79;
		}
	}

	return $screen_width;
}