#!/usr/bin/perl -w
# Author:  Chao-Kuei Hung
# For more info, including license, please see doc/index.html

use strict;
use Getopt::Std;
use lib '/usr/local/libdata/perl5/site_perl/algotutor';

BEGIN {
    my ($path) = $0 =~ m#(.*/)#;
    $path = "." unless defined $path;
    push @INC, $path;
}

my (
    %opts,		# command line options
    $wd,		# tk widgets
    $dfn,		# data file name
    $mds,		# main data structure
);
%opts = (
    a => undef,		# which algorithm to run?
    s => undef,		# start vertex (for some graph algos)
);

getopts('a:s:', \%opts);
die "need exactly one data file. Example:\n\talgotutor -a bst /usr/local/share/algotutor/data/countries.gr\n" 
    unless $#ARGV == 0;
$dfn = $ARGV[0];
die "cannot read data file '$dfn'.\nDoes it exist and do you have read permissions?\n" unless -r $dfn;
die "please specify an algorithm to run using -a. Example:\n\t-a bst\n\t-a heap\n\t-a dfs\n\t-a bfs\n\t-a prim\n\t-a dijk\n\t-a flwa\n"
    unless defined $opts{a};

require "utilalgo";
$mds = eval { do $dfn };
die "'$dfn' does not look like a valid algotutor data file\n"
    unless ($mds and ref $mds eq "HASH");
$wd->{main} = MainWindow->new(-title=>"algotutor");

if (0) {
} elsif ($opts{a} eq "bst") {
    require BST;
    $wd->{can}{main} = gen_can($wd->{main}, undef, -elevation=>1, -maxlevel=>2);
    $wd->{ctrl} = gen_ctrl($wd->{main}, $wd->{can});
    $mds = BST->new(-canvas=>$wd->{can}{main}, %$mds);
} elsif ($opts{a} eq "rbt") {
    require RBTree;
    $wd->{can}{main} = gen_can($wd->{main}, undef, -elevation=>1, -maxlevel=>2);
    $wd->{ctrl} = gen_ctrl($wd->{main}, $wd->{can});
    $mds = RBTree->new(-canvas=>$wd->{can}{main}, %$mds);
} elsif ($opts{a} eq "heap") {
    require Heap;
    $wd->{can}{main} = gen_can($wd->{main}, undef, -elevation=>1, -maxlevel=>3);
    $wd->{ctrl} = gen_ctrl($wd->{main}, $wd->{can});
    $mds = Heap->new(-canvas=>$wd->{can}{main}, %$mds);
} elsif ($opts{a} eq "dfs") {
    require Graph;
    $wd->{can}{main} = gen_can($wd->{main}, undef, -elevation=>1, -maxlevel=>2);
    $wd->{ctrl} = gen_ctrl($wd->{main}, $wd->{can});
    $mds = Graph->new(-canvas=>$wd->{can}{main}, %$mds);
    require "graph/dfs";
    dfs($mds, -start=>$opts{s}, -on_vertex=>\&disp_vert_val);
} elsif (grep { $opts{a} eq $_ } qw(bfs dijk prim)) {
    $mds = prio_first($wd, $mds, $opts{a});
} elsif ($opts{a} eq "flwa") {
    require Graph;
    $wd->{can}{main} = gen_can($wd->{main}, undef, -elevation=>1, -maxlevel=>2);
    $wd->{ctrl} = gen_ctrl($wd->{main}, $wd->{can});
    $mds = Graph->new(-canvas=>$wd->{can}{main}, %$mds);
    require "graph/flwa";
    flwa($mds);
} elsif ($opts{a} eq "dom") {
    require Graph;
    $wd->{can}{main} = gen_can($wd->{main}, undef, -elevation=>1, -maxlevel=>2);
    $wd->{ctrl} = gen_ctrl($wd->{main}, $wd->{can});
    $mds = Graph->new(-canvas=>$wd->{can}{main}, %$mds);
    require "cgeom/dom";
    dom($mds);
} elsif ($opts{a} eq "graham") {
    require Graph;
    $wd->{can}{main} = gen_can($wd->{main}, undef, -elevation=>1, -maxlevel=>2);
    $wd->{ctrl} = gen_ctrl($wd->{main}, $wd->{can});
    $mds = Graph->new(-canvas=>$wd->{can}{main}, %$mds);
    require "cgeom/graham";
    graham($mds);
} else {
    die "unknown algorithm '$opts{a}'\n";
}

$wd->{ctrl}->configure(-recorder=>0);
Tk::MainLoop();

sub disp_vert_val {
    my ($v, $val) = @_;
    $v->configure(-text=>"$v\n$val");
}

sub prio_first {
    my ($wd, $mds, $prio) = @_;
    require Graph;
    $wd->{can}{main} = gen_can($wd->{main}, undef, -elevation=>2, -maxlevel=>3);
    $wd->{can}{fr} = gen_can($wd->{main}, "Fringe", -elevation=>1, -maxlevel=>3);
    $wd->{ctrl} = gen_ctrl($wd->{main}, $wd->{can});
    $mds = Graph->new(-canvas=>$wd->{can}{main}, %$mds);
    require "graph/pfs";
    pfs($mds, $wd->{can}{fr}, -start=>$opts{s}, -priority=>$prio, -on_vertex=>\&disp_vert_val);
    return $mds;
}

__END__

=head1 NAME

algotutor - an interactive program for observing the intermediate steps 
of algorithms.

=head1 SYNOPSIS

B<algotutor> [I<OPTION>] ... I<FILE>

=head1 DESCRIPTION

algotutor is an interactive program for observing the intermediate steps 
of algorithms. The target audience is computer science students and/or anyone 
who studies algorithms and/or data structures. One can create data files in 
plain text format (actually perl anonymous hashes, but one need not care) 
and let algotutor runs through some predefined algorithm. Then one can step 
backward and forward through the execution sequence of the algorithm at 
different levels of details. It requires perl-Tk.

=head1 OPTIONS

=over

=item B<-a> I<ALGO>

Runs the algorithm ALGO. Currently ALGO can be one of:

=over

=item B<bst> operations on binary search trees

=item B<bst> operations on red-black trees (remove() is not implemented yet)

=item B<heap> operations on heaps -- the remove operation on a heap always removes the top element regardless of the argument

=item B<dfs> depth first search on graphs

=item B<bfs> breadth first search on graphs

=item B<prim> Prim's minimal spanning tree on graphs

=item B<dijk> Dijkstra's single-source shortest path on graphs

=item B<flwa> Floyd-Warshall's all-pair shortest path on graphs (very, very slow)

=item B<dom> 2-dimensional point domination

=item B<graham> Graham's scan for convex hull

=back

=item B<-s> I<VERTEX>

Use VERTEX as the starting vertex (for dfs, bfs, prim, and dijk)

=back

=head1 LICENSE

This code is distributed under the GNU General Public License

=head1 AUTHOR

B<Chao-Kuei Hung> ckhung AT cyut DOT edu DOT tw

=head1 SEE ALSO 

Please see /usr/share/doc/algotutor/doc/ for the full set of documentations.

=cut

