# This package contains some handy code for working with text.

package Text;
use strict;
use Error;

# Pass it a string, it returns an array of all words in the string. 
sub SplitWords {
	$_=shift;
	
	my @words;
	# If this regexp is modified, be sure to modify the similar one in
	# Person::verb_sayto as well.
	while (m/"([^"\\]*(\\.[^"\\]*)*)"\s*|([^\s]+)\s*/g) {
		push(@words,defined($1) ? $1 : $3);
	}	
	
	return @words;
}

# Pass it a list of words, it returns them all
# seperated by commas, etc.
sub MakeList {
	my $ret="";
	
	if ($#_ > 1) {
		my $c;
		for ($c=0; $c< $#_; $c++) {
			$ret.=$_[$c];
			$ret.="," if $#_ > 1;
			$ret.=" ";
		}
		$ret.="and $_[$#_]";
	}
	elsif ($#_ == 1) {
		$ret="$_[0] and $_[1]";
	}
	elsif ($#_ == 0) {
		$ret=$_[0];
	}

	return $ret;
}

# Pass it a string and a hash reference. It takes every key in the 
# hash and pretends they are variables, substituting them in the string.
# You can use \ to escape out $ if need be, you can also use ${var} syntax
# to disambiguate.
#
# Originally by Chris Johnsen <chris_johnsen@yahoo.com>.
sub subst ($%) {
	my $string = shift;
	my $vars = shift;

	my ($result, $rest, $key);
	$result = '';
	$rest = $string;
	while ($rest =~ m/^(.*?)(\$|\\)(.*)$/sg) {
		$result .= $1;  # copy anything before the var
		if ($2 eq '\\') {
			$result .= substr( $3, 0, 1 );
			$rest = substr( $3, 1 );
			next;
		}
		$rest = $3;
		if ($rest =~ /^\{/) { # } keep matching happy
			if ($rest =~ /^\{([_a-zA-Z]\w*)\s}(.*)$/) {
				$key = $1;
				$rest = $2;
			}
			else {
				return Error->new("Unterminated/bad delimited subst key: '$rest'");
			}
		}
		elsif ($rest =~ /^([_a-zA-Z]\w*)(.*)$/s) {
			$key = $1;
			$rest = $2;
		}
		else {
			return Error->new("Invalid subst key: '$rest'");
		}
		
		if (exists $vars->{$key}) {
			$result .= $vars->{$key};
		}
		else {
			return Error->new("Unknown subst key: $key");
		}
	}
	$result .= $rest;

	return $result;
}

# Takes a number of seconds, and turns it into an english
# representation. The second parameter is an (optional) integer that specifies
# precision - that many time elements will be returned.
#
# If called in a scalar context, returns a scalar with the time in it.
# If called in a list context, returns a list of how ever many elements
# you asked for (some may be null).
sub prettytime { 
	my $seconds = shift;
	my $numelts = shift || 2;
	
	my ($thestring, $parts);
	my @strparts;
 
	my %units = (
		'decades' => 315576000, 
		'years', => 31557600, 
#		'seasons', => 7889400, 
		'days' => 86400, 
		'hours' => 3600, 
		'minutes', => 60, 
		'seconds', => 1); 

	foreach (sort {$units{$b}<=>$units{$a}} keys %units) {
		last if ($parts >= $numelts);
		if ($seconds>=$units{$_}) {
			my $unitname = $_;
			my $amount = int($seconds/$units{$_});
			$seconds -= $amount*$units{$_};
			if($amount==1) {
				chop($unitname);
		        }
			push(@strparts,"$amount $unitname");
			$parts++;
		}
	}

	if (wantarray) {
		# Make sure there are enough elts.
		foreach ($#strparts .. $numelts - 2) { push @strparts, undef }
		return @strparts;
	}
	else {
		if ($strparts[1]) {
			return join(", ",@strparts); 
		}
		else {
			return $strparts[0];
		}
	}
} 

# The table-maker takes two arguments. A line to go at the top of
# the table, and then an array of arrays. Each item in the first
# array will become its own line. Each item within the second
# array will be its in own column.
sub tablemaker {
	my ($titlestr,@data) = @_;
	my ($columns,$width,@colwidth,$formpiece,
	    $formline,$returndata,@returnlines,$title);

	for (0..$#data) {
		my (@foo) = @{$data[$_]};
		foreach (0..$#foo) {
			if (length($foo[$_]) > $colwidth[$_]) {
				$colwidth[$_] = length($foo[$_]);
			}	
		}
	}

	for (0..$#colwidth) {
		$width += ($colwidth[$_]+1);
		$colwidth[$_] = "@" . "<" x $colwidth[$_];
	}
	$width--;
	$formline = join('',@colwidth);

	if ($titlestr) {
		$title = " " x (($width-length($titlestr))/2) . $titlestr;
	}

	for (0..$#data) {
		my (@foo) = @{$data[$_]};
		$ = "";
		# And you thought this was just a relic nobody used!
		formline($formline,@foo);
		push(@returnlines,$);
	}

	return $title,@returnlines;
}

1
