#Copyright Massachusetts Institute of technology, 2000.
#Written by Eric Prud'hommeaux for the World Wide Web Consortium

package W3C::Rdf::TkVisualizer::StatementListWidget;

use strict;
use base  qw(W3C::Rdf::TkVisualizer::WindowSetClient);
use Tk::widgets qw(Frame Label Entry);

use W3C::Rdf::TkVisualizer::PromptHistory;
use W3C::Rdf::TkVisualizer::WindowSetClient;

use vars qw($VERSION $DSLI @ISA @EXPORT @EXPORT_OK @TODO);

@EXPORT = qw();
@EXPORT_OK = qw();
$VERSION = 0.01;
$DSLI = 'adpO';
@TODO = ('write');

Construct Tk::Widget 'StatementListWidget';

sub Populate
{
    require W3C::Rdf::TkVisualizer::WindowSetClient;
    my($cw, $args) = @_;
    $cw->SUPER::Populate($args);
    use W3C::Util::Exception;
    &throw(new W3C::Util::Exception(-message => 'widget factory not defined')) if (!defined $args->{-matrixWidget});
    &throw(new W3C::Util::Exception(-message => 'search frame not defined')) if (!defined $args->{-searchFrame});

    my $self = $cw;
    my $searchFrame = delete $args->{-searchFrame};
    my $listFrame = $cw;

    # search prompt
    $searchFrame->Label(-text => 'Look for: ')->pack(-side => 'left');
    $self->{SEARCH} = $searchFrame->Scrolled('Entry', -scrollbars => 'os')
	->pack(-side => 'left', -anchor => 'w', -fill => 'x', -expand => 1);
    $self->{SEARCH}->bind("<Return>", sub {$self->search(0)});
    $self->{SEARCH}->bind("<Up>", sub {$self->search(1)});
    $self->{SEARCH}->bind("<Down>", sub {$self->search(0)});

    # statement list
    my $matrixWidget = $args->{-matrixWidget};
    $self->{TRIPLE_LIST} = $cw->$matrixWidget(-command => sub {$self->triplesPick(@_);}, 
					      -columnLabels => ['#','attrib','','predicate',
								'subject','object','','reifId','in']);
    $self->{TRIPLE_LIST}->pack(-fill => 'both', -expand => 1);
    $self->{TRIPLE_LIST}->bind("<Control-Alt-Up>", sub {$self->search(1)});
    $self->{TRIPLE_LIST}->bind("<Control-Alt-Down>", sub {$self->search(0)});

    $cw->ConfigSpecs(-matrixWidget => ['PASSIVE', undef, undef, undef], 
		     -statementSet => ['PASSIVE', undef, undef, undef]);
}

sub refreshList {
    my ($self) = @_;
    $self->{TRIPLE_LIST}->startRows;
    my $i = 0;
    $self->cget(-statementSet)->clearRenderedStatements;
    $self->{BY_INDEX} = undef;
    my @statements = $self->sortStatements($self->cget(-windowSet)->getStatements);
    for (my $i = 0; $i < @statements; $i++) {
	my $statement = $statements[$i];
	my ($enabled, $segments) = $self->cget(-windowSet)->renderStatement($statement);
	next if (!$enabled);
	$self->{TRIPLE_LIST}->addRow([$i, @$segments, '', '']);
	$self->cget(-statementSet)->addRenderedStatement('triple_'.$statement, $i, $statement);
	$self->{BY_INDEX}[$i] = [join (' ', @$segments), $statement];
    }
    my $windowWidth = $self->{TRIPLE_LIST}->endRows;
#    $self->{WINDOW}->configure('-width' => $windowWidth); # @@@ - no worky
}

sub search {
    my ($self, $up) = @_;
    my $search = $self->{SEARCH};
    my $searchString = $search->get;
    return if ($searchString eq '');
    my $lb = $self->{TRIPLE_LIST};
    if (!$up) {
	my $start = $self->{SEARCH_INDEX} == $lb->size - 1 || !defined $self->{SEARCH_INDEX} ? 0 : $self->{SEARCH_INDEX}+1;
	my $end = $lb->size - 1;
	my $i;
      SEARCH_DOWN:
	for ($i = $start; $i <= $end; $i++) {
	    my $entry = $lb->get($i);
	    if ($entry =~ m/$searchString/) {
		$lb->highlight($i);
		$self->{SEARCH_INDEX} = $i;
		$self->triplesPick($i, 0);
		return;
	    }
	}
	if ($i == $lb->size) {
	    $start = 0;
	    $end = $self->{SEARCH_INDEX};
	    goto SEARCH_DOWN;
	}
    } else {
	my $start = $self->{SEARCH_INDEX} == 0 || !defined $self->{SEARCH_INDEX} ? $lb->size - 1 : $self->{SEARCH_INDEX}-1;
	my $end = 0;
	my $i;
      SEARCH_UP:
	for ($i = $start; $i >= $end; $i--) {
	    my $entry = $lb->get($i);
	    if ($entry =~ m/$searchString/) {
		$lb->highlight($i);
		$self->{SEARCH_INDEX} = $i;
		$self->triplesPick($i,0);
		return;
	    }
	}
	if ($i == -1) {
	    $start = $lb->size - 1;
	    $end = $self->{SEARCH_INDEX}+1;
	    goto SEARCH_UP;
	}
    }
    $lb->bell;
#    $search->flash; # find a button to do the flashing
#    print "not found\n";
}

sub sortStatements {
    my ($self) = (shift);
    return @_;
    eval { # perl 5.004_04 seems to have a prob with this:
	return sort {$self->cget(-windowSet)->renderNode($a->getPredicate, $a->getAttribution) cmp 
			 $self->cget(-windowSet)->renderNode($b->getPredicate, $b->getAttribution);} @_;
    }; # so I provide this alternative:
    return @_;
}

sub triplesPick {
    my ($self, $row, $col) = @_;
    $self->{SEARCH_INDEX} = $row;
    my $statement = $self->{BY_INDEX}[$row]->[1];
    if ($col == 4) {
	$self->cget(-windowSet)->graphNode($statement->getSubject);
    } elsif ($col == 5) {
	$self->cget(-windowSet)->graphNode($statement->getObject);
    } else {
	$self->cget(-windowSet)->graphStatement($statement, 1);
    }
    $self->cget(-windowSet)->showGraphWindow;
}

sub findTriple { # used by Graph::graphPick
    my ($self, $index) = @_;
    $self->{TRIPLE_LIST}->highlight($index);
}

sub getCurrentStatement {
    my ($self) = @_;
    my $index = $self->{TRIPLE_LIST}->curselection;
    return defined $index ? $self->cget('-statementSet')->getTripleByIndex($index) : undef;
}

sub hilightStatement {
    my ($self, $statementHandle) = @_;
    my $tmp = $self->cget('-statementSet')->getStatementDetails($statementHandle);
    if ($tmp) {
	$self->findTriple($tmp->[0]);
    }
}

1;
