#!/usr/bin/perl

# electric sheep - a collaborative screensaver
# Copyright (C) 1999-2007  Scott Draves


require "global.pl";
require "../promote.pl";



use CGI;
use File::stat;

$query = CGI::new();

$id = $query->param("id");
$detail = $query->param("detail");

$gen = 247;

$anim_dir = "$id";
$astate_file = "$anim_dir/memory";

if (! (-e $astate_file)) {
    normal_header($query, "error", "sheep $id");
    print "sheep $id does not exist.";
    normal_footer($query, $license_mixed);
    exit(0);
}
dbmopen(%ANIM_STATE, $astate_file, 0644) or die "Couldn't dbmopen $astate_file: $!\n";

#if ("dead" ne $ANIM_STATE{'state'}) {
#    if (defined $detail) {
#	print $query->redirect("node.cgi?id=$id&detail=$detail");
#    } else {
#	print $query->redirect("node.cgi?id=$id");
#    }
#    exit(0);
#}

$time = $ANIM_STATE{'ctime'};
$type = $ANIM_STATE{'type'};
$size = $ANIM_STATE{'size'};
$first = $ANIM_STATE{'first'};
$last = $ANIM_STATE{'last'};
$state = $ANIM_STATE{'state'};
$last_state = $ANIM_STATE{'last_state'};
$brood = $ANIM_STATE{'brood'};
$format = $ANIM_STATE{'format'};
$timeout = $ANIM_STATE{'timeout'};

if ($first eq $last) {
    $title = "<img $icon_tags src=$anim_dir/icon.jpg>";
} else {
    $title = "<img $icon_tags src=$anim_dir/icon0.jpg><img $icon_tags src=$anim_dir/icon1.jpg>";
}

if (defined($query->param('action'))) {
    if (!admin_privs($query)) {
	normal_header($query, $title, "sheep $id");
	print "action denied";
	normal_footer($query, $license_mixed);
	exit(0);    
    }
}

if ($query->param('action') eq "reincarnate") {
    init_state();
    if ($first eq $last) {
	q_loop_edge_edge($total_frames, "reincarnate", $id);
    } else {
	q_edge($total_frames, $first, $last);
    }
    print $query->redirect("status?detail=queue");
    exit(0);
}
if ($query->param('action') eq "promote") {
    eslog("admin: promoting $id");
    print $query->redirect("status.cgi?detail=queue");
    init_state();
    open($filename_uploaded, "<$anim_dir/spex");
    $saved_pid = $id;
    q_hidef($hidef_frames);
    init_anim_state($uploaded_id);
    $ANIM_STATE{'parents'} = $saved_pid;
    exit(0);
}
if ($query->param('action') eq "expunge") {
    expunge_sheep($id);
    print $query->redirect('status.cgi');
    exit(0);
}
if ($query->param('action') eq "finished") {
    if ($brood) {
	$client_ip = $query->remote_addr();
	eslog("admin: finishing $id client_ip=$client_ip");
	clean_dir($id);
	brood_open();
	delete $BROOD_STATE{$id};
	brood_close();
    } else {
	eslog("admin: finishing $id, not brood");
    }
    
}
if ($query->param('action') eq "remove") {
    $client_ip = $query->remote_addr();
    eslog("admin: removing $id client=$client_ip");
    hidef_open();
    delete $HIDEF_STATE{$id};
    hidef_close();
    print $query->redirect('status.cgi');
    exit(0);
}

normal_header($query, $title, "sheep $id");

    $nick = $ANIM_STATE{'upload_nick'};
    $url = $ANIM_STATE{'upload_url'};


$license = $license_cc_by;
if ($nick eq "brood" || $first ne $last) {
    $license =$license_cc_bync;
}


if ($brood && !admin_privs($query)) {
    print "access denied";
    normal_footer($query, $license);
    exit(0);    
}

if (! (defined $detail)) {
    if ($brood) {
	$detail = "icons";
    } elsif ($first eq $last) {
	$detail = "view";
    } else {
	$detail = "motion";
    }
}


if ($brood) {
    print mk_menu($detail, "detail", "node.cgi?id=$id",
		  ["full", "full"], 
		  ["icons", "icons"], 
		  ["frames", "frames"], 
		  ["stats", "stats"]);
} else {
    print mk_menu($detail, "detail", "dead.cgi?id=$id",
		  ["frames", "frames"], ["motion", "motion"],
		  (($first eq $last) ? ["family", "family"] : ()),
		  (($first eq $last) ? ["lineage", "lineage"] : ()),
		  ["genome", "genome"], ["stats", "stats"],
		  ["view", "view"]);
}

print "</td></tr><tr><td width=520 align=center>";

    if (defined $nick) {
	print "this sheep was designed by ";
	if (defined $url) {
	    print "<a href=\"$url\">$nick</a>";
	} else {
	    print $nick;
	}
	print ".<p>\n";
    }


if (admin_privs($query)) {
    $spacer = "&nbsp;&nbsp;&nbsp;&nbsp;";
      print "<a href=dead?id=$id&action=reincarnate>reincarnate</a>\n";
  if ($first eq $last) {
      print "<a href=dead?id=$id&action=promote>promote</a>\n";
      print "$spacer<a href=set?name=beginid&value=$id>begin</a>/";
      print "<a href=set?name=endid&value=$id>end</a> ";
  }
  $cmd = $brood ? "finished" : (ishidef() ? "remove" : "expunge");
	
  print "$spacer<a href=dead.cgi?id=$id&action=$cmd>$cmd</a><p>\n";
}

$nframes = $ANIM_STATE{'nframes'};
$multiplicity = $ANIM_STATE{'multiplicity'};
$hidef = $ANIM_STATE{'hidef'};

@preds = ();
@succs = ();

if (ishidef()) {
    if (!admin_privs($query)) {
	print "access denied";
	normal_footer($query, $license);
	exit(0);
    }
    hidef_open();
    my @ids = all_hidef_ids();
    foreach $id2 (@ids) {
	($first2, $last2) = split /:/, $HIDEF_STATE{$id2};
	my $ed = ($first eq $last) ^ ($first2 ne $last2);
	if ($last eq $first2 && ! $ed) {
	    push (@succs, $id2);
	}
	if ($first eq $last2 && ! $ed) {
		push (@preds, $id2);
	}
    }
    hidef_close();
}



if ($detail eq "motion") {

  if ($first eq $last) {

    print "<table><tr><td><table>\n";

    foreach $p (@preds) {
      if ($p ne $id) {
	$fl = "$p/icon0.jpg";
	if (! -e $fl) {
	    $fl = $anon_icon;
	}
	$icon = "<a href=dead.cgi?id=$p&" .
	    "detail=motion><img src=$fl border=0></a>";
	print "<tr><td>$icon</td></tr>\n";
      }
    }

    print "</table></td><td>";
    if ($last_state eq 'done' || $last_state eq 'upload') {
      $src = "$anim_dir/face.jpg";
    } else {
      $src = $anon_face;
    }
    print "<img border=0 width=$face_size height=$face_size src=$src></td><td><table>\n";

    foreach $p (@succs) {
      if ($p ne $id) {
	$fl = "$p/icon1.jpg";
	if (! -e $fl) {
	    $fl = $anon_icon;
	}
	$icon = "<a href=dead.cgi?id=$p&" .
	    "detail=motion><img src=$fl border=0></a>";
	print "<tr><td>$icon</td></tr>\n";
      }
    }

    print "</table></td></tr></table>\n";
  } else {
    print "<table><tr>\n";

    foreach $p (@preds) {
      if ($p ne $id) {
	$icon = "<a href=dead.cgi?id=$p&" .
	    "detail=motion><img src=$p/icon.jpg border=0></a>";
	print "<td>$icon</td>\n";
      }
    }

    print "<td><a href=$anim_dir/sheep.$suffix>";
    if ($last_state eq 'done' || $last_state eq 'upload') {
      $src = "$anim_dir/face.jpg";
    } else {
      $src = $anon_edge;
    }
    $face_size2 = int($face_size / 2);
    print "<img border=0 width=$face_size height=$face_size2 src=$src></a></td>\n";


    foreach $p (@succs) {
      if ($p ne $id) {
	$icon = "<a href=dead.cgi?id=$p&" .
	    "detail=motion><img src=$p/icon.jpg border=0></a>";
	print "<td>$icon</td>\n";
      }
    }

    print "</tr></table>\n";
  }
} elsif ($detail eq "family") {

    $parents = $ANIM_STATE{'parents'};
    if (defined $parents) {
	print "parents<br>";
	family_list3($parents);
    } else {
	genebank_parents($gen, $id);
    }

    print "myself<br>";
    family_list3($id);

    $children = $ANIM_STATE{'children'};
    if (defined $children) {
	print "children<br>";
	family_list3($children);
    }

    $id = $query->param('id');
    $page = int($id / $family_tree_sheep_per_page);
    $p2 = int($id / $by_time_sheep_per_page);
    print "<p>graph of <a href=best.cgi?menu=tree&p=$page>family tree</a> or ";
    print "<a href=best?menu=time&p=$p2>cohort</a><br>\n";

    
} elsif ($detail eq "lineage") {

    if (! -e "$id/family_tree.jpg") {
	write_local_family_tree($gen, $id);
    }
    print read_whole_file("$id/family_tree.map");
    print "<img src=$id/family_tree.jpg border=0 usemap=\"#treemap\">";

} elsif ($detail eq "view") {
  $jpg_name = sprintf("electricsheep.%d.%05d.jpg", $gen, $id);
  $src = "$anim_dir/$jpg_name";
  print "<table class=tab><tr><td colspan=2><img src=$src></td></tr>\n";
  print "</table>\n";
} elsif ($detail eq "icons") {

    
sub clampe {
    my ($e) = @_;
    if ($e < 0.01) {
	$e = 0;
    } elsif ($e < 0.4) {
	$e = 0.5;
    } else {
	$e = 1.0;
    }
    return $e;
}

sub donealready {
    my ($try) = @_;
    my @pixx = split /:/, $ANIM_STATE{'brood_picks'};
    my $id = $pixx[$try];
    my $bp = $ANIM_STATE{'brood_parent'};
    if (2 == $ANIM_STATE{'brood_type'}) {
	$tfirst = $id;
	$tlast = $bp;
    } else {
	$tfirst = $bp;
	$tlast = $id;
    }
    eslog("try=$try searching for $tfirst:$tlast");
    @ids = all_hidef_ids();
    foreach $i (@ids) {
	my ($first, $last) = split /:/, $HIDEF_STATE{$i};
	if (($first eq $tfirst) && ($last eq $tlast)) {
	    return 1;
	}
    }

    return 0;
}

if ($brood) {
    print "<p>";
    $bt = $ANIM_STATE{'brood_type'};
    if  ($bt == 1 || $bt == 2) {
	my $num_tries = $nframes / $brood_frames_per_try;
	undef %SIZES;
	for ($try = 0; $try < $num_tries; $try++) {
	    my $min_i = -1;
	    my $max_i = -1;
	    my $min = 0;
	    my $max = 0;
	    for ($i = 0; $i < $brood_frames_per_try; $i++) {
		$frame = $try * $brood_frames_per_try + $i;
		if (! -e "$anim_dir/$frame.$format") {
		    next;
		}
		$size = stat("$anim_dir/$frame.$format")->size;
		$errors = 0;
		if ($format eq "jpg") {
		    $jcomm = `rdjpgcom $anim_dir/$frame.jpg`;
		    if ($jcomm =~ /flam3_error_rate:(.+)/) {
			$errors = $1;
		    } else {
			eslog("could not find flam3_errors");
			$errors = 0;
		    }
		}
		    
		if (-1 == $min_i || $size < $min) {
		    $min_i = $i;
		    $min = $size;
		}
		if (-1 == $max_i || $errors > $max) {
		    $max_i = $i;
		    $max = $errors;
		}
	    }

	    $SIZES{$try} = $min;
	    $ERRORS{$try} = $max;
	}
	print "<p>";
	@pixx = split /:/, $ANIM_STATE{'brood_picks'};
	hidef_open();
	my @sorted = sort {donealready($a) <=> donealready($b) ||
			   clampe($ERRORS{$a}) <=> clampe($ERRORS{$b}) ||
			   $SIZES{$b} <=> $SIZES{$a}} keys %SIZES;
	hidef_close();

	calc_hd_io();

	$bp = $ANIM_STATE{'brood_parent'};
	$bpf = $ANIM_STATE{'brood_parent_frame'};
	print "brood parent = <a href=dead.cgi?id=$bp>$bp</a>";
	if (defined $bpf) {
	    print " frame = <a href=frame.cgi?id=$bp&frame=$bpf>$bpf</a>";
	}
	print "<table>";
	foreach $try (@sorted) {
	    $pix = $pixx[$try];
	    $n0 = (2 == $ANIM_STATE{'brood_type'}) ? 0 : 1;
	    $n1 = $n0 ? 0 : 1;
	    $io = $n0 ? $HDEL{$pix} : $HDEF{$pix};
	    $jsz = $SIZES{$try};
	    $ern = $ERRORS{$try};
	    print "<tr><td><a href=dead.cgi?id=$pix>$pix</a></td><td>$io</td><td align=right>$jsz</td><td align=right>$ern</td>";
	    my $enqueue = "<td><a href=submit.cgi?type=edge&n$n0=$pix&n$n1=$bp&fini=$id>enqueue</a></td>";
	    print $enqueue;
	    for ($i = 0; $i < $brood_frames_per_try; $i++) {
		$frame = $try * $brood_frames_per_try + $i;
		print "<td><a href=frame.cgi?id=$id&frame=$frame>";
		print "<img border=0 $icon_tags src=$anim_dir/i$frame.jpg>";
		print "</a></td>\n";
	    }
	    print $enqueue;
	    print "<td><a href=dead.cgi?id=$pix>$pix</a></td><td>$io</td></tr>";
	}
	print "</table>";
    } else {
	undef %SIZES;
	for ($i = 0; $i < $nframes; $i++) {
	    $fname = "$anim_dir/$i.$format";
	    if (! -e $fname) {
		next;
	    }
	    $SIZES{$i} = stat($fname)->size;
	}
	my @sorted = sort {$SIZES{$b} <=> $SIZES{$a}} keys %SIZES;
	foreach $i (@sorted) {
	    print "<a href=frame.cgi?id=$id&frame=$i&action=seed><img border=0 src=$anim_dir/$i.$format></a><p>";
	}
    }
}
else {
  $nframes = $ANIM_STATE{'nframes'};
  $multiplicity = $ANIM_STATE{'multiplicity'};
  $njobs = $nframes * $multiplicity;
  $ndone = $ANIM_STATE{'ndone'};
  $ntimed_out = $ANIM_STATE{'ntimed_out'};
  $done = 0;
  $col = 0;

  print "<table>";
  for ($i = 0; $i < $njobs; $i++) {
      if ($col == 0) {
	print "<tr>";
      }
      ($fstate, $client, $time, $nick) = split /:/, $ANIM_STATE{$i};

      print "<td><a href=frame.cgi?id=$id&frame=$i>";

      if (-e "$anim_dir/$i.$format") {
	$done += 1;
	$fname = "$anim_dir/i$i.jpg";
    } else {
	$busy += 1;
	$fname = $busy_icon;
      }

      print "<img border=0 $icon_tags src=$fname></a></td>";
      if ($col++ == 15) {
	$col = 0;
	print "</tr>\n";
      }
  }
    print "</table>\n";
    print "njobs=$njobs done=$done<br>\n";
}
} elsif ($detail eq "full") {
  $src = "$anim_dir/0.$format";
  print "<table class=tab><tr><td colspan=2><img src=$src></td></tr>\n";
  print "</table>\n";
} elsif ($detail eq "frames") {
  $nframes = $ANIM_STATE{'nframes'};
  $ndone = $ANIM_STATE{'ndone'};
  $ntimed_out = $ANIM_STATE{'ntimed_out'};

  $ready = 0;
  $busy = 0;
  $done = 0;

  $col = 0;

  if (admin_privs($query)) {
      $ip_heading = "<th>IP#</th>";
  } else {
      $ip_heading = "";
  }
  print "<table class=tab border=0 cellpadding=3><tr><th>frame</th><th>nick</th>$ip_heading<th>finished</th></tr>\n";
  for ($i = 0; $i < $nframes; $i++) {
      ($fstate, $client, $time, $nick) = split /:/, $ANIM_STATE{$i};
      $nick = nick_as_html($nick);
      if ($time > 0) {
	  $date_name = localtime $time;
      } else {
	  $date_name = "&nbsp;";
      }
      if (admin_privs($query)) {
	  $ip_field = "<td>$client</td>";
      } else {
	  $ip_field = "";
      }
      
      print "<tr><td align=right>$i</td><td>$nick</td>$ip_field<td>$date_name</td></tr>\n";
  }
  print "</table>\n";

} elsif ($detail eq "genome") {

    $spex = $ANIM_STATE{'spex'};
    $spex =~ s/</&lt;/g;
    $spex =~ s/>/&gt;/g;
    $spex =~ s/\n/<br>/g;

    $ff = sprintf("%05d", $id);

  print "<table>\n";
  print "<tr><td align=center><a href=$anim_dir/electricsheep.$gen.$ff.flam3>file</a></td></tr>\n";
  print "<tr><td><font size=\"-2\">$spex</font>\n";
  print "</td></tr></table>\n";

} elsif ($detail eq "stats") {

    $ctime = $ANIM_STATE{'ctime'};
    $btime = $ANIM_STATE{'btime'};
    $dtime = $ANIM_STATE{'dtime'};
    $ctime_name = localtime $ctime;

    if (defined $btime) {
	$btime_name = localtime $btime;
	$gestation = $ANIM_STATE{'btime'} - $ANIM_STATE{'ctime'};
	if ($gestation > 600) {
	    $gestation_name = int($gestation / 60) . " minutes";
	} else {
	    $gestation_name = $gestation . " seconds";
	}
    } else {
	$btime_name = "<em>not born yet</em>";
	$gestation_name = "<em>NA</em>";
    }

    if (defined $dtime) {
	$dtime_name = localtime $dtime;
	if (defined $btime) {
	    $lifetime = $dtime - $btime;
	    if ($lifetime > 172800) {
		$lifetime_name = int($lifetime / 86400) . " days";
	    } elsif ($lifetime > 7200) {
		$lifetime_name = int($lifetime / 3600) . " hours";
	    } else {
		$lifetime_name = int($lifetime / 60) . " minutes";
	    }
	}
    }    

    if ($size > 10 * 1024 * 1024) {
	$size_name = int($size/(1024 * 1024)) . " Mbytes";
    } elsif ($size > 10 * 1024) {
	$size_name = int($size/(1024)) . " Kbytes";
    } else {
	$size_name = $size . " bytes";
    }

    $prog = $ANIM_STATE{'program'};

    print "<table class=tab>";
    print "<tr><td align=right>state</td><td>$state</td></tr>\n";
    print "<tr><td align=right>last state</td><td>$last_state</td></tr>\n";
    print "<tr><td align=right>conception</td><td>$ctime_name</td></tr>\n";
    $fftime = $ANIM_STATE{'first_frame_time'};
    if (defined $fftime) {
	$fftime_name = localtime $fftime;
	print "<tr><td align=right>first frame</td><td>$fftime_name</td></tr>\n";
    }
    if (defined $btime) {
	print "<tr><td align=right>birth</td><td>$btime_name</td></tr>\n";
	print "<tr><td align=right>gestation</td><td>$gestation_name</td></tr>\n";
    }
    if (defined $dtime) {
	print "<tr><td align=right>death</td><td>$dtime_name</td></tr>\n";
	if (defined $btime) {
	    print "<tr><td align=right>lifetime</td><td>$lifetime_name</td></tr>\n";
	}
    }
    if ($last_state eq "done") {
	$size_field = "$size_name";
	print "<tr><td align=right>size</td><td>$size_field</td></tr>\n";
	$max = $ANIM_STATE{'max_rating'};
	if (defined $max) {
	    print "<tr><td align=right>peak rating</td><td>$max</td></tr>\n";
	}
    }

    $inter = $ANIM_STATE{'interpolation'};
    if (defined $inter) {
	print "<tr><td align=right>interpolation</td><td>$inter</td></tr>\n";
    }



  print "<tr><td align=right>first</td><td><a href=dead?id=$first>$first</a></td></tr>\n";
  print "<tr><td align=right>last</td><td><a href=dead?id=$last>$last</a></td></tr>\n";

    if (defined $hidef) {
	print "<tr><td align=right>hidef</td><td>$hidef</td></tr>\n";
	    
    }
    if (defined $brood) {
	$brood_type = $ANIM_STATE{'brood_type'};
	$brood_picks = $ANIM_STATE{'brood_picks'};
	$brood_parent = $ANIM_STATE{'brood_parent'};
	$brood_parent_frame = $ANIM_STATE{'brood_parent_frame'};
	print "<tr><td align=right>brood</td><td>$brood</td></tr>\n";
	print "<tr><td align=right>brood_type</td><td>$brood_type</td></tr>\n";
	print "<tr><td align=right>brood_picks</td><td>$brood_picks</td></tr>\n";
	print "<tr><td align=right>brood_parent</td><td><a href=node?id=$brood_parent>$brood_parent</a></td></tr>\n";
	print "<tr><td align=right>brood_parent_frame</td><td>$brood_parent_frame</td></tr>\n";
    }
    $mega = $ANIM_STATE{'mega'};
    if (defined $mega) {
	$mega_count = $ANIM_STATE{'mega_count'};
	$mega_parent = $ANIM_STATE{'mega_parent'};
	$mega_first = $ANIM_STATE{'mega_first'};
	$mega_succ = $ANIM_STATE{'mega_succ'};
	print "<tr><td align=right>mega</td><td>$mega</td></tr>\n";
	print "<tr><td align=right>mega_count</td><td>$mega_count</td></tr>\n";
	print "<tr><td align=right>mega_first</td><td>$mega_first</td></tr>\n";
	print "<tr><td align=right>mega_succ</td><td>$mega_succ</td></tr>\n";
	print "<tr><td align=right>mega_parent</td><td>$mega_parent</td></tr>\n";
    }
    $n_bad = $ANIM_STATE{'n_bad_frames'};
    $bads = $ANIM_STATE{'bad_frames_history'};
    if (defined $n_bad) {
	print "<tr><td align=right>bad frames</td><td>$n_bad: $bads</td></tr>\n";
    }
  print "<tr><td align=right>multiplicity</td><td>$multiplicity</td></tr>\n";
  print "<tr><td align=right>nframes</td><td>$nframes</td></tr>\n";
  print "<tr><td align=right>timeout</td><td>$timeout</td></tr>\n";
  print "<tr><td align=right>format</td><td>$format</td></tr>\n";


  if ("expunge" eq $state) {
      $extime_name = localtime $ANIM_STATE{'extime'};
      print "<tr><td align=right>extime</td><td>$extime_name</td></tr>\n";
  }

    if (0) {
	$parents = $ANIM_STATE{'parents'};
	if (defined $parents) {
	    print "<tr><td align=right>parents</td><td>$parents</td></tr>\n";
	}
	$children = $ANIM_STATE{'children'};
	if (defined $children) {
	    print "<tr><td align=right>children</td><td>$children</td></tr>\n";
	}
    }
    if (admin_privs($query)) {
	$promoted = $ANIM_STATE{'promoted'};
	if (defined $promoted) {
	    print "<tr><td align=right>promoted</td><td>$promoted</td></tr>\n";
	}
    }
    $src_url = $ANIM_STATE{'src_url'};
    if (defined $src_url) {
	print "<tr><td align=right>src</td><td><a href=$src_url>url</a></td></tr>\n";
    }

    
  print "</table>\n";
}

print_promote_command();

normal_footer($query, $license);
