#o!/usr/bin/perl
use strict;
use POSIX;

#open(VMSTAT, "-|", "cat", "/home/dave/garbage/testvmstat");
open(VMSTAT, "-|", "vmstat", @ARGV);

my @header_names;
my $in_header_len;
my $out_header_len;
my $header_cols;
my $out_col_size;

my $longpad = "-----------------------------------------------------------------------------------------------------------";

# copy hash ref
sub chref
{
	my $href = shift;
	my %tmp = %$href;
	return \%tmp;
}

sub pad
{
	my $str = shift;
	my $len = shift;
	my $to_pad = $len - length($str);
	my $pad_len_r = POSIX::floor($to_pad / 2.0);
	my $pad_len_l = POSIX::ceil($to_pad / 2.0);
	my $pad_l = substr($longpad, 0, $pad_len_l);
	my $pad_r = substr($longpad, 0, $pad_len_r);
	return sprintf("%s%s%s", $pad_l, $str, $pad_r);
}

sub process_header
{
	my $header = shift;
	my @headers = split(/\s/, $header);
	return if (defined $out_header_len);
	#printf "HEADER\n";
	@header_names = ();
	foreach my $h (@headers) {
		(my $h_name = $h) =~ s/-//g;
		#printf "name: $h_name width: %d\n", length($h);
		push @header_names, $h_name;
		$in_header_len->{$h_name} = length($h);
	}
	if (! defined $out_header_len) {
		$out_header_len = chref($in_header_len);
	}
}

sub col_names
{
	my @ret = ();
	foreach my $h (@header_names) {
		foreach my $col (@{$header_cols->{$h}}) {
			push @ret, $h."_".$col;
		}
	}
	return @ret;
}

my $need_header = 0;
sub print_header
{
	#printf "HEADER OUT\n";
	foreach my $h (@header_names) {
		printf " " if $h ne $header_names[0];
		print pad($h, $out_header_len->{$h});
	}
	#printf "COLS OUT\n";
	printf "\n";
	my @col_names = col_names();
	while (scalar(@col_names)) {
		my $cn = shift @col_names;
		my $sz = $out_col_size->{$cn};
		$cn =~ s/.*_//;
		printf "%".$sz."s", $cn;
		printf " " if scalar(@col_names);
	}
	printf "\n";
	#printf "HEADER DONE\n";
	$need_header = 0;
}

sub print_data
{
	my @data = @_;
	my @col_names = col_names();
	while (scalar(@col_names)) {
		my $cn = shift @col_names;
		my $sz = $out_col_size->{$cn};
		$cn =~ s/.*_//;
		printf "%".$sz."s", shift(@data);
		printf " " if scalar(@col_names);
	}
	printf "\n";
}

sub process_cols
{
	my $rest_cols = shift;
	return if defined $out_col_size;
	printf "COLS\n";
	foreach my $h (@header_names) {
		my $cols = substr($rest_cols, 0, $in_header_len->{$h});
		$rest_cols = substr($rest_cols, $in_header_len->{$h} + 1);
		#rintf("these cols: ->%s<-\n", $cols);
		#printf("rest  cols: ->%s<-\n", $rest_cols);
		my @col_array_tmp = split(/ /, $cols);
		my $col_pad = 0;
		my @col_array;
		while (scalar(@col_array_tmp)) {
			my $col = shift @col_array_tmp;
			if (! length($col)) {
				$col_pad++;
				next;
			}
			#printf "col: '%s' left: %d\n", $col, scalar(@col_array_tmp);
			$out_col_size->{$h."_".$col} = $col_pad + length($col);
			push @col_array, $col;
			$col_pad = 0;
		}
		$header_cols->{$h} = \@col_array;
		#printf("cols: (%s)\n", join(",", @col_array));
	}
}

sub process_data
{
	my $line = shift;
	my @data = split(/\s+/, $line);
	# pull blanks from leading spaces off
	while (scalar(@data) && ! length($data[0])) {
		shift @data;
	}
	my @orig_data = @data;
	foreach my $h (@header_names) {
		my $header_total = 0;
		foreach my $col (@{$header_cols->{$h}}) {
			my $cn = $h."_".$col;
			my $col_data = shift(@data);
			if (length($col_data) >  $out_col_size->{$cn}) {
				$out_col_size->{$cn} = length($col_data);
			}
			$header_total += $out_col_size->{$cn};
			#printf("added %d to total for $col\n", $out_col_size->{$cn});
		}
		# add room for the spaces.  If two columns, need once space
		$header_total += scalar(@{$header_cols->{$h}}) - 1;
		if ($out_header_len->{$h} != $header_total) {
			$out_header_len->{$h} = $header_total;
			$need_header = 1;
		}
		#printf("total for $h: %d\n", $header_total);
	}
	#$need_header = 1;
	print_header() if $need_header;
	print_data(@orig_data);
}
while (my $line = <VMSTAT>) {
	chomp $line;
	#printf "%s\n", $line;
	if ($line =~ /[-\s]*procs/) {
		process_header($line);
		$need_header = 1;
       	} elsif ($line =~ /\s*[a-z]+/i) {
		process_cols($line);
	} else {
		process_data($line);
#		die "data";
	}
}
