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

package W3C::Rdf::TkVisualizer::Graph;

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

use W3C::Rdf::TkVisualizer::HidableMainWindow;

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

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

my ($X, $Y, $TS, $AW, $AH) = (300, 300, 10, 5, 8);

Construct Tk::Widget 'Graph';

sub Populate
{
    require W3C::Rdf::TkVisualizer::HidableMainWindow;
    require W3C::Rdf::TkVisualizer::GraphMaster;
    my($cw, $args) = @_;
    $cw->SUPER::Populate($args);

    my $frame = $cw->Frame(-relief => 'groove', -bd => 2)->pack(-fill => 'x', -side => 'top');
    # control buttons
    ($cw->{GRAPH_MASTER} = $frame->GraphMaster(-windowSet => $args->{-windowSet}))
	->pack(-side => 'top', -fill => 'x', -expand => 1);
    $cw->{CANVAS} = $cw->Scrolled('Canvas', -width=>$X, -height=>($Y * 5)/4) ->pack(-fill => 'both', -expand => 1);
    $cw->{CANVAS}->Subwidget('canvas')->Tk::bind("<Button-1>", sub {$cw->graphPick});
    $cw->ConfigSpecs(-statementSet => ['PASSIVE', undef, undef, undef]);
}

# overloaded virtuals
sub getTitle {return 'Graph';}

# support functions
sub clearCanvas {$_[0]->{CANVAS}->delete('stuff');}
sub getLastCurrent {$_[0]->{LAST_CURRENT};}
sub graphPick {
    my ($self, $overrideCurrent) = @_;
    my @current = $self->{CANVAS}->gettags('current');
    @current = @$overrideCurrent if ($overrideCurrent);
    $self->{LAST_CURRENT} = \@current;
    return if ($current[0] !~ m/\A(triple|node|nav)_(.*)\Z/);
    if ($1 eq 'triple') {
	# statements->findTriple(index of the selected statement (may be undef))
	$self->cget(-windowSet)->findTriple($self->cget(-statementSet)->getTripleBy999($current[0])->[0]);
    } elsif ($1 eq 'node') {
	$self->graphNode($self->{STR_TO_OBJ}{$current[0]});
    } elsif ($1 eq 'nav') {
	$self->{GRAPH_MASTER}->onArrow($2 eq 'back' ? -1 : 1)
    }
}

sub graphStatement { # for ClientWindow::triplesPick
    my ($self, $statement) = @_;
    my ($enabled, $segments) = $self->cget(-windowSet)->renderStatement($statement);
    my $rendered = '('.$segments->[2].' '.$segments->[3].' '.$segments->[4].')';
    my $view = new W3C::Rdf::TkVisualizer::GraphStatementView(-windowSet => $self->cget(-windowSet), 
							      -string => $rendered, 
							      -statement => $statement, 
							      -graph => $self);
    $self->{GRAPH_MASTER}->add($view);
    $view->renderGraphView;
}

sub graphNode {
    my ($self, $node, $attribution) = @_;
    my $rendered = $self->cget(-windowSet)->renderNode($node, $attribution);
    my $view = $self->{GRAPH_MASTER}->getByString($rendered);
    if (!$view) {
	$view = new W3C::Rdf::TkVisualizer::GraphNodeView(-windowSet => $self->cget(-windowSet), 
							  -string => $rendered, 
							  -node => $node, 
							  -graph => $self);
	$self->{GRAPH_MASTER}->add($view);
    }
    $view->renderGraphView;
}

sub graphTriples { # for Graph{Statement,Node}View::renderGraphView
    my ($self, $triples, $fullScreen, $top) = @_;
    my $graph = $self->{CANVAS};
    my $tripleCount = $#$triples - $[ + 1;
    my $step = $X / ($tripleCount + 1);
    my $x = $step;
    my ($yTop, $yMid, $yBot) = $fullScreen ? ($TS+1, $Y/2, $Y-$TS) : $top ? ($TS+1, $Y/4, $Y/2) : ($Y/2, (3*$Y)/4, $Y-$TS);
    for (my $i = 0; $i < $tripleCount; $i++) {
	my $triple = $triples->[$i];
	my ($predicate, $subject, $object, $attrib) = 
	    ($triple->getPredicate, $triple->getSubject, $triple->getObject, $triple->getAttribution);
	my ($predicateShort, $subjectShort, $objectShort, $sourceAttrib) = 
	    ($self->cget(-windowSet)->renderNode($predicate, $attrib), 
	     $self->cget(-windowSet)->renderNode($subject, $attrib), 
	     $self->cget(-windowSet)->renderNode($object, $attrib, {-stringTrunc => 30, -truncFlag => '...'}), 
	     $attrib);
#	$objectShort = $self->cget(-windowSet)->renderNode($object, $attrib);
#	$objectShort = substr($objectShort, 0, 20);
	my $node = $top ? $subject : $object;
	my $entryNode = $self->{GRAPH_MASTER}->getPrevious->matchesNode($node);
	my $exitNode  = $self->{GRAPH_MASTER}->getNext->matchesNode($node);
	my $lineColor = $entryNode ? 'red' : $exitNode ? 'green' : 'black';
	my $lineTag = $entryNode ? 'nav_back' : $exitNode ? 'nav_forward' : 'inert';
#	$graph->createOval(60,1, 140,31);
	my $xSubjCenter = ($fullScreen||!$top)?$X/2:$x;
	my $xPredCenter = ($fullScreen)?$X/2:$x;
	my $xObjCenter = ($fullScreen||$top)?$X/2:$x;
	my ($subjectTag, $objectTag, $tripleTag) = ('node_'.$subject, 'node_'.$object, 'triple_'.$triple);
	$self->{STR_TO_OBJ}{$subjectTag} = $subject;
	$self->{STR_TO_OBJ}{$objectTag} = $object;
	$self->{STR_TO_OBJ}{$tripleTag} = $triple;
	# subject
	$graph->createText($xSubjCenter,$yTop, 
			   -justify => 'center', 
			   -text => $subjectShort, 
			   -fill => 'blue', 
			   -tags => [$subjectTag, 'stuff']);
	$graph->createLine($xSubjCenter,$yTop+$TS, $xPredCenter,$yMid-$TS, 
			   -tags => [$lineTag, 'stuff'], 
			   -fill => $lineColor);
	# predicate
	$graph->createText($xPredCenter,$yMid, 
			   -justify => 'left', 
			   -text => $predicateShort, 
			   -tags => [$tripleTag, 'stuff']);
	$graph->createLine($xPredCenter,$yMid+$TS, $xObjCenter,$yBot-$TS, 
			   -tags => [$lineTag, 'stuff'], 
			   -fill => $lineColor);
	# arrow
	$graph->createLine($xObjCenter-$AW,$yBot-$TS-$AH, $xObjCenter,$yBot-$TS, 
			   -tags => [$lineTag, 'stuff'], 
			   -fill => $lineColor);
	$graph->createLine($xObjCenter+$AW,$yBot-$TS-$AH-1, $xObjCenter,$yBot-$TS, 
			   -tags => [$lineTag, 'stuff'], 
			   -fill => $lineColor);
	# object
	$graph->createText($xObjCenter,$yBot, 
			   -justify => 'center', 
			   -text => $objectShort, 
			   -fill => 'blue', 
			   -tags => [$objectTag, 'stuff']);
#	$graph->createOval(60,170, 140,199);
	$x += $step;
	if (!$fullScreen) {
	    if ($top) {
		$yTop+=$TS;
	    } else {
		$yBot+=$TS;
	    }
	    $yMid+=$TS;
	}
    }
}

1;

