#!/usr/bin/perl -w
# matrixchain - @sꪺx}ۭ, sӦضǭp̦Ĳv?
# @: x¶Q http://www.cyut.edu.tw/~ckhung
# v: public domain (pGznNڪ{gΪj{,
# jPĳNzIH GPL)
#
# oӵ{JO algotutor @, ]iHbrҦU,
# ϥ Tk, W߰C
# W߰覡:
# Ux}WٻPjp̧Ǽgb @chain oӳCC
# Ҧp A,B,C, ... H Kӯx}ns, jpU:
# 32x35, 35x24, 24x30, 30x36, 36x25, 25x40, 40x34, 34x35
# hiO @chain = qw(32 A 35 B 24 C 30 D 36 E 25 F 40 G 34 H 35);
# M ./matrixchain -e ansi
# -e w "j" ܤ覡, ᭱i ansi  html

use Getopt::Std;
use strict;

my (%opts) = (
    e => "ansi",# type of emphasis, either "ansi" or "html"
);

my ($ES) = {
    ansi => { pre=>"\x1b[7m", post=>"\x1b[m", nl=>"\n" },
    html => { pre=>"<em>", post=>"</em>", nl=>"<br /><br />\n" },
};


sub matrixchain {
    my ($chain, $can) = @_;
    my (@dim, @name, $show, $left, $size, $best, $i, $expr);
    my ($cell) = sub { return $show->cell(
	($_[0]+1) % ($#name+2), ($_[1]+$#name+2) % ($#name+2)
    ); };

    while ($#$chain > 0) {
	push @dim, (shift @$chain);
	push @name, (shift @$chain);
    }
    push @dim, @$chain;

    if (ref $can) {
	$show = Board->new(-canvas=>$can, -width=>$#name+2, -height=>$#name+2,
	    -node_opts=>{ -size=>Vector->new(50,40), -shape=>"rectangle" } );
	map { $cell->(-1,$_)->configure(-text=>$name[$_], -status=>"done"); } 0..$#name;
	map { $cell->($_,-1)->configure(-text=>$name[$_], -status=>"done"); } 0..$#name;
	$expr = $can->createText(@{ $show->rc2xy($#name+2, int(($#name+1)/2) ) },
	    -justify=>"center", -text=>"expr");
    }
    for ($left=0; $left<=$#name; ++$left) {
	$best->[$left][$left] = { val => 0 };
	if (ref $can) {
	    $cell->($left,$left)->configure(-text=>0, -status=>"done");
	    for ($i=$left+1; $i<=$#name; ++$i) {
		$cell->($i,$left)->configure(-status=>"hidden");
	    }
	}
    }
    $can->set_mark(2) if ref $can;
    for ($size=1; $size<=$#name; ++$size) {
	for ($left=0; $left<=$#name-$size; ++$left) {
	    $cell->($left,$left+$size)->configure(-text=>"?", -status=>"focus")
		if ref $can;
	    my ($s, $t);
	    $best->[$left][$left+$size] = { val => 1e99 };
	    for ($i=0; $i<$size; ++$i) {
		$s = $best->[$left][$left+$i]{val} . " + " .
		    $best->[$left+$i+1][$left+$size]{val} . " + " .
		    $dim[$left] . " * " .
		    $dim[$left+$i+1] . " * " .
		    $dim[$left+$size+1];
		$t = eval $s;
		if (ref $can) {
		    $can->itemconfigure($expr, -text=>"$t = $s");
		    $cell->($left, $left+$i)->configure(-status=>"focus");
		    $cell->($left+$i+1, $left+$size)->configure(-status=>"focus");
		    if ($i >= 1) {
			$cell->($left, $left+$i-1)->configure(-status=>"done");
			$cell->($left+$i, $left+$size)->configure(-status=>"done");
		    }
		    $can->set_mark(1);
		}
		if ($t < $best->[$left][$left+$size]{val}) {
		    $best->[$left][$left+$size] = { val=>$t, cut=>$left+$i };
		}
	    }
	    if (ref $can) {
		$t = $best->[$left][$left+$size];
		$t = $t->{val} . "\n" . $name[$t->{cut}] . "|" .  $name[$t->{cut}+1];
		$cell->($left,$left+$size)->configure(-text=>$t, -status=>"done");
		$can->itemconfigure($expr, -text=>"");
		$cell->($left, $left+$size-1)->configure(-status=>"done");
		$cell->($left+$size, $left+$size)->configure(-status=>"done");
		$can->set_mark(2);
	    }
	}
    }

    for ($i=1; $i<=$#name; ++$i) {
	printf "     %2s    ", $name[$i];
    }
    print "\n";
    for ($left=0; $left<$#name; ++$left) {
	print "           " x $left;
	for ($i=$left+1; $i<=$#name; ++$i) {
	    my ($t) = sprintf "%d:%s|%s",
		$best->[$left][$i]{val},
		$name[$best->[$left][$i]{cut}],
		$name[$best->[$left][$i]{cut}+1];
	    printf "%11s", $t;
	}
	print "  $name[$left]\n";
    }
}

if ($0 =~ /matrixchain$/) {

getopts('e:', \%opts);
my (@chain) = qw(32 A 35 B 24 C 30 D 36 E 25 F 40 G 34 H 35);
print "@chain\n";
matrixchain(\@chain);

}

1;

