# Simple class to hold a returned record
package Easy::Item;

use strict;
use POSIX;
use Text::Autoformat;
#use lib "/u/n/m/nmueller/lib";
use CSL::W3MImg;
use W3MImg;

sub new
{
    my ($class, %opts) = @_;

    # Get the module name
    ($opts{package}) = caller;
    $opts{package} =~ s/.*:://;

    bless \%opts, $class;
}

sub render
{
    my ($this, $width) = @_;

    # Easy if raw
    return $this->{raw} if exists $this->{raw};

    # Do the preprocessing
#    $this->preprocess_newline();

    # Start with a header
    my $text = &header($this->{package}, $this->{title}, $width);

    # Render attributes
    if ($this->{attributes})
    {
	my @attributes;
	if ($this->{attributes_order})
	{
	    @attributes = map { $this->{attributes}{$_} =~ s/^\s+//; 
				"$_: $this->{attributes}{$_}" }
	    @{$this->{attributes_order}};
	}
	else
	{
	    @attributes = map { $this->{attributes}{$_} =~ s/^\s+//; 
				"$_: $this->{attributes}{$_}" } keys %{$this->{attributes}};
	}
	    
	# Figure out how many columns and rows to have
	my $ave;
	foreach (@attributes)
	{
	    $ave += length($_);
	}
	$ave /= @attributes;
	my $columns = floor($width*.75/$ave) || 1;
	# To preserve backwords compatibility with old scripts
	$columns = 2 if $columns > 2;
	my $rows = ceil(@attributes/$columns);
	
	# Split the attributes up into columns
	my @columns;
	foreach (1 .. $columns)
	{
	    $columns[$_-1] = [ splice(@attributes, 0, $rows) ];
	}
	
	# Justify within columns
	foreach my $column (@columns)
	{
	    my $max;
	    foreach (@$column)
	    {
		/([^:]+)/;
		$max = length($1) if length($1) > $max;
	    }
	    
	    foreach my $attribute (@$column)
	    {
		$attribute =~ /([^:]+)/;
		my $padding = $max - length($1);
		$attribute = (" " x $padding) . $attribute;
	    }
	}
	
	# Find the max width of all columns
	my @width;
	foreach my $column (@columns)
	{
	    my $max;
	    foreach (@$column)
	    {
		$max = length($_) if length($_) > $max;
	    }
	    
	    push @width, $max;
	}
	
	# Place columns on the page
	# Hold the outside columns $padding from the edges
	# Center other columns between
	my $padding = 2;
	my $space_available = $width - 2*$padding;
	foreach (@width)
	{
	    $space_available -= $_;
	}
	
	# If it's too long then truncate the longest column
	if ($space_available < $#columns*$padding)
	{
	    my $max;
	    my $max_col;
	    foreach (0 .. $#width)
	    {
		next unless $width[$_] > $max;
		
		$max = $width[$_];
		$max_col = $_;
	    }

	    # Make space at the ends
	    my $final = $max + $space_available - $#columns*$padding-1;
	    $width[$max_col] = $final+1;
	    foreach (@{$columns[$_]})
	    {
		s/(.{$final}).*/$1</;
	    }

	    $space_available = $#columns*$padding;
	}

	my $sep = $#columns ? floor($space_available/$#columns) : 0;
	$sep = $padding if $sep < $padding;
	my @offset = (0, ($sep) x $#columns);
	
		# Render the attribute columns
		foreach my $row (0 .. $rows-1)
		{
		    foreach my $column (0 .. $columns-1)
	    	{
				$text .= " " x $offset[$column];
				$text .= $columns[$column]->[$row];
				$text .= " " x ($width[$column] - length($columns[$column]->[$row]))
				    if $column != $columns - 1;
		    }
		    $text .= "\n";
		}
    }

    # Render picture
    if ($this->{picture})
    {
	system("/s/std/bin/imecho $this->{picture}");
    }

    $text .= $this->generate_list("headings", "list", $width) if ($this->{list});
    $text .= $this->generate_list("auxheadings", "auxlist", $width) if ($this->{auxlist});

    # Render text
    if ($this->{text})
    {
	$text .= autoformat $this->{text}, { left => 3,
					     right => $width-2,
					     all => 1 };
    }

    # Slap on a footer
    $text .= &footer($width);
    
    return $text;
}

sub generate_list {

	my ($this, $headers, $list, $width) = @_;

	$this->preprocess_newline($list);

	# Figure out spacing for the list, same method as above
	$this->{$headers} ||= [];
	my @width = map { length($_) } @{$this->{$headers}};
	foreach my $row (@{$this->{$list}})
	{
	    foreach (0 .. @$row-1)
	    {
		$row->[$_] =~ s/^\s+//;
		$width[$_] = length($row->[$_]) if length($row->[$_]) > $width[$_];
	    }
	}
	my $space_available = $width;
	foreach (@width)
	{
	    $space_available -= $_;
	}
	
	my $padding = 2;
	my $sep = $#width ? floor($space_available/$#width) : 0;
	$sep = $padding if $sep < $padding;
	my @offset = (0, ($sep) x $#width);
	
	# Render column headers
	my $text = "\n";
	my $column_underline = "";
	foreach (0 .. $#width)
	{
	    $text .= " " x $offset[$_];
	    $text .= $this->{$headers}[$_];
	    $text .= " " x ($width[$_] - length($this->{$headers}[$_]));

		$column_underline .= " " x $offset[$_];
		$column_underline .= "-" x $width[$_];
	}
	$text .= "\n$column_underline\n";
	
	# Render columns
	foreach my $column (@{$this->{$list}})
	{
	    foreach (0 .. $#width)
	    {
		$text .= " " x $offset[$_];
		$text .= $column->[$_];
		$text .= " " x ($width[$_] - length($column->[$_]))
		    if $_ != $#width;
	    }
	    $text .= "\n";
	}    
	return $text;
    }


# This pre-processes the list items for \n characters:
# If any \n's appear in a given row, it will get split into multiple rows
# so that the resultant list items contain NO \n chars
#
# -ajkunen
sub preprocess_newline
{
    my ($this, $list) = @_;	
    
    return if !$this->{$list};
    my @oldlist = @{$this->{$list}};
    my @newlist;
    
    # parse the lines
    while(my $rowptr = shift @oldlist)
    {
	# split each cell into a list of cells
	my @columns;
	foreach my $x (@$rowptr)
	{	
	    my @list = split "\n", $x;
	    push @columns, \@list;
	}
	
	# rejoin into at least one row 
	my $done;
	while(!$done)
	{
	    my @row;
	    $done = 1;
	    
	    foreach my $col (@columns)
	    {
		my $x = shift @$col;
		$done = 0 if $x;
		$x = "" unless defined $x;
		push @row, $x;
	    }
	    
	    push @newlist, \@row unless $done;
	}
    }
    
    # save the new list
    $this->{$list} = \@newlist;
}

sub header
{
    my ($pack, $title, $width) = @_;

    my $header = "-" x $width . "\n";
    my $center_space = floor($width - length($title))/2;
    $header .= $pack . " " x ($center_space - length($pack)) . $title 
	. " " x ($center_space - length(strftime("%R %D", localtime)))
	    . strftime("%R %D", localtime) . "\n";
    $header .= "-" x $width . "\n";

    return $header;
}

sub footer
{
    my ($width) = @_;

    return "-" x $width . "\n";
}

1;
