#! perl -w
use lib "/afs/sipb.mit.edu/user/kenta/chess-rep-0.4/share/perl/5.8.8";
use Chess::Rep;
use Expect;
use strict;
$::command = "./glaurung";
$::killswitch = "killswitch";
$::matemult=100000;
#die unless $ARGV[0] =~ /^\d+$/;
$::timethink=$ARGV[0];

shift @ARGV;
&start_engine;
&main;

$::exp->send("quit\n");
$::exp->soft_close();

sub main {
    
#@moves_so_far=qw/c2c4 g8f6 c4c5 f6g8 c5c6 g8f6 c6b7 f6g8/;
    print << 'EOF';
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
  <head> 
    <title>Glaurung analysis</title> 
    <meta http-equiv="refresh" content="5">
  </head> 
 
  <body> 
EOF


    #my @moves_so_far=qw/f3 e5 h3/;
    my @moves_so_far;
    open FI,$ARGV[0] or die "cannot open file $ARGV[0]";
    while(<FI>){
	next if /^#/;
	my @G=split;
	for(@G){
	    next if /^\d+\.$/;
	    s/^\d+\.//;
	    push @moves_so_far,$_;
	}
    }

    print "<p>$ARGV[1], Pondering move ",(2+scalar@moves_so_far)/2,
    ", Glaurung $::timethink</p>\n<pre>\n";
    my $rep=Chess::Rep->new;
    my $canon="";
    my $parity=1;
    for(@moves_so_far){
	$canon.=" ".canonicalmove($rep,$_);
        $parity=not$parity;
    }
    $canon.=" ";
    my $current_fen=$rep->get_fen();
    my @themoves=basic_algebraic_moves(@{$rep->status->{moves}});
    
    print STDERR "$canon\n";
    my $total=@themoves;
    my %continuation_score;
    my $count=1;
    for(@themoves){
	if (-e $::killswitch) {
	    unlink $::killswitch;
	    die "killswitch";
	}
	my($computer,$score,$pv,$depth,$nps)=
	    &engine($canon.$_,$::timethink);
	print STDERR " $count/$total is $_ -> $computer $score/$depth $nps $pv \n";
	$count++;
	my@sans=san_sequence($current_fen,$_,split /\s+/,$pv);
	my$line=&concat_san(@sans)." depth $depth nps $nps";
	$continuation_score{$line}=$score;
    }
    my@sorted_keys=(sort {score_compare($continuation_score{$a},$continuation_score{$b})} (keys %continuation_score));
    
    $count=1;
    for (@sorted_keys){
        my $i;
        if ($parity){
            $i=invert_score($continuation_score{$_});
        }else{
            $i=$continuation_score{$_};
        }
	print "$count. $i: $_\n";
	$count++;
    }
    print "</pre>\n<p>Moves:\n",&concat_san(@moves_so_far);
    print"</p>\n\n<p>FEN $current_fen</p>\n";
    print << 'EOF';
<p>See the <a href="RCS/index.html,v">RCS file</a> for previous moves.  
<a href="script.pl">Here is the script</a> used to generate this analysis.</p>
<p>"cp" = centi-pawn</p>
</body>
</html>
EOF
}

sub engine {
    my $movelist1=shift;
    my $timethink=shift;
    #print "movelist1 $movelist1\n";
    $::exp->send( << "EOF"
ucinewgame
position startpos moves $movelist1
go $timethink
EOF
		#go wtime $two btime $two winc $hour binc $hour
	);
    
    my($depth,$score,$pv,$nps);
    for(;;){
	if (-e $::killswitch) {
	    unlink $::killswitch;
	    die "killswitch internal";
	}
	#($matched_pattern_position, $error, $successfully_matching_string, $before_match,       $after_match);
	my@expect_result=$::exp->expect(undef,("-re",'bestmove.*\r',"-re",'info depth.*score.*\r')) or die;
	my$successfully_matching_string=$expect_result[2];
	#print STDERR "gotsms $successfully_matching_string\n";
	if ($successfully_matching_string =~ /info depth .* score.*/){
	    die unless ($depth,$score,$nps,$pv)=($successfully_matching_string =~
					    /info depth (\d+) score (.*) time .* nodes .* nps (.*) pv (.*)/);
	}
	last if $successfully_matching_string =~ /bestmove/;
    }
    my$gotmatch=$::exp->match;
    die $_ unless $gotmatch=~/bestmove (\S+)/;
    my $computermove=$1;
    #print "$computermove: score $score, pv $pv\n";
    ($computermove,$score,$pv,$depth,$nps)
	
}


sub basic_algebraic_moves {
    my @yesmoves;
    for(@_){
	#printf("%02x ",$$_{piece});
	my$go=lc(Chess::Rep::get_field_id($$_{from})
		 .Chess::Rep::get_field_id($$_{to}));
	if (($$_{piece}==0x81 and 
	     (Chess::Rep::get_row_col($$_{to}))[0] == 7)
	    or
	    ($$_{piece}==0x01 and 
	     (Chess::Rep::get_row_col($$_{to}))[0] == 0)) {
	    for my $p (qw/n b r q/){
		push @yesmoves,"$go$p"
	    }
	} else {
	    push @yesmoves,$go;
	}
    }
    @yesmoves;
}

sub canonicalmove {
  my($rep,$usermove)=@_;
  die if $rep->status->{mate};
  die if $rep->status->{stalemate};


  my %rh=%{${$rep->status}{hash_moves}};
  my $r;
  eval {$r=$rep->go_move($usermove);};
  if ($@){
    print "Died $@\n";
    die;
  }
  unless ($rh{"$$r{from_index}-$$r{to_index}"}) {
    print "bad\n";
    die;
  }
  if ($$r{piece} eq 'P' and $$r{to_row}==7 and not $$r{promote}) {
    die "need promotion";
  }
  my $gomove="$$r{from}$$r{to}";
  $gomove .= $$r{promote} if ($$r{promote});
  $gomove=lc$gomove;
}

sub san_sequence {
    my $current_fen=shift;
    my $rep=Chess::Rep->new($current_fen);
    my @sans;
    for(@_){
	#print "doing $_\n";
	my $result=$rep->go_move($_);
	push @sans,$$result{san}
    }
    @sans;
}

sub mate_convert {
    my $rawmoves=shift;
    if ($rawmoves<0){
	-($::matemult+$rawmoves);
    }
    elsif ($rawmoves>0){
	$::matemult-$rawmoves;
    } else { die "cannot convert $rawmoves" ; }
}

sub string_convert {
    if ($_[0] =~ /cp\s+(\S+)/) {
	$1;
    } elsif ($_[0] =~ /mate\s+(\S*)/){
	&mate_convert($1);
    } else {
	die "cant convert $_[0]";
    }
}

sub score_compare {
    (&string_convert($_[0])<=>(&string_convert($_[1])));
}
	    
sub concat_san {
    my $o="";
    for(@_){
	$o.=" $_";
    }
    $o;
}
    
sub invert_score {
    my $answer;
    for($_[0]){
	die "$_" unless /(.*)\s+(-?\d+)/;
	$answer=$1." ".(0-$2);
    }
    $answer;
}

sub start_engine {
    $::exp = Expect->spawn($::command)
	or die;
    $::exp->log_stdout(0);
    $::exp->log_file("/tmp/glauxz12.log");
    $::exp->expect(15, ("Tord Romstad.\r")) or die;
    $::exp->send("uci\n");
    $::exp->expect(5,("uciok\r")) or die;
    $::exp->send("isready\n");
    $::exp->expect(5,"readyok\r") or die;
}
