#
# Copyright (c) 1992 The Ohio State University.
# All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that: (1) source distributions retain this entire copyright
# notice and comment, and (2) distributions including binaries display
# the following acknowledgement:  ``This product includes software
# developed by The Ohio State University and its contributors''
# in the documentation or other materials provided with the distribution
# and in all advertising materials mentioning features or use of this
# software. Neither the name of the University nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#

#
# Generic routine to read a location_ci, _co, _list or _move array 
# and print the entries.
# 
sub list_stuff {
    local($location, $what, $show_extra_info) = @_;
    local($id, @tmp);

    $foo = sprintf("@%s_%s", $location, $what);
    print "    eval $foo\n"
      if $opt_d & $DEBUG_INFO;

    @tmp = eval($foo);
    die "error (offsite): ", $@ if $@;

    foreach $id (sort increasing_tapeid @tmp) {
	if ($show_extra_info) {
	    printf "    $id\t[%s]\n", $info{$id};
	} else {
	    print "    $id\n";
	}
    }

    print "\n    ", join(' ', sort increasing_tapeid @tmp), "\n" 
	if $#tmp > -1;
    print "\n";
}

sub add_to_list {
    local($id, $location, $which) = @_;
    local($foo);

    $locations_seen{$location} = 1;

    $foo = sprintf("push(@%s_%s, '%s')", $location, $which, $tapeid);
    print "    eval $foo\n"
      if $opt_d & $DEBUG_INFO;
    eval($foo);
    die "error (offsite): ", $@ if $@;
}

$options = "hd:";
$usage = 
"usage: offsite [-d debuglevel] [-h]
    -d debuglevel	print debugging messages.
    -h			display this message.\n";

require 'global.defs';
require 'local.defs';
require $yagrip_perl;
require $backuplib_perl;

    #
    # Make sure that we clean up after ourselves if someone wants to kill us.
    #
$SIG{'INT'} = 'handle_interrupts';
$SIG{'HUP'} = 'handle_interrupts';
$SIG{'TERM'} = 'handle_interrupts';
$SIG{'QUIT'} = 'handle_interrupts';

die $usage if ! &getopt($options);
die $usage if defined($opt_h);
die $usage if $#ARGV != -1;

    #
    # Read the backup config file...
    #
&read_config();

die "error (offsite): Cannot open the tape database.\n"
  if ! &open_db(*TAPEDB, $tape_db_file, $db_mode);

die "error (offsite): Cannot open the run database.\n"
  if ! &open_db(*RUNDB, $run_db_file, $db_mode);

#
print "processing tapes...\n" if $opt_d & $DEBUG_INFO;

tape_loop:
  foreach $tapeid (&keys_db(*TAPEDB)) {
      &read_db(*TAPEDB, $tapeid, *tape_db_value, *tape_db_array);

      $tape_has_location = defined($tape_db_array{"location"}) && 
	$tape_db_array{"location"} ne "";
      $tape_is_offsite = $tape_has_location && 
	$tape_db_array{"location"} ne $tape_db_array{"home"};

      # skip if the tape isn't used
      if ($tape_db_array{"flags"} ne "used") {
	  # if the tape is offsite, bring it back
	  if ($tape_is_offsite) {
	      $info{$tapeid} = "tape is unused";
	      &add_to_list($tapeid, $tape_db_array{"location"}, "ci");
	  }

	  next tape_loop;
      }

      $run = $tape_db_array{"run_id"};

      # skip if this tape doesn't have a run
      if (! &defined_db(*RUNDB, $run)) {
	  # if the tape is offsite, bring it back
	  if ($tape_is_offsite) {
	      $info{$tapeid} = "tape's run $run doesn't exist";
	      &add_to_list($tapeid, $tape_db_array{"location"}, "ci");
	  }

	  next tape_loop;
      }

      &read_db(*RUNDB, $run, *run_db_value, *run_db_array);

      $chain = $run_db_array{"chain"} + 0;
      $level = $run_db_array{"level"} + 0;
      $start = $run_db_array{"start_date"} + 0;
      chop($date = &ctime($start));
      $location = $tape_db_array{"location"};

      print "  working on $tapeid (run $run $chain,$level $location)\n"
	if $opt_d & $DEBUG_INFO;

      # if this chain isn't part of the offsite games, skip it
      if (! defined($offsite_location{$chain})) {
	  print "    skipped - chain isn't part of the offsite system.\n"
	    if $opt_d & $DEBUG_INFO;

	  # if the tape is offsite, bring it back
	  if ($tape_is_offsite) {
	      $info{$tapeid} = "tape is offsite, but belongs to a chain that shouldn't be";
	      &add_to_list($tapeid, $location, "ci");
	  }

	  next tape_loop;
      }

      $new_location = $offsite_location{$chain};

      # if this tape is younger than X days skip it
      if ((time - $start) < $offsite_wait{$chain}) {
	  print("    skipped - younger than ",
		sprintf("%.2f days\n", $offsite_wait{$chain}/$DAYS))
	    if $opt_d & $DEBUG_INFO;

	  if ($tape_is_offsite) {
	      $info{$tapeid} = sprintf("shouldn't be offsite for %.2f days",
				       ($start + $offsite_wait{$chain} - time) / $DAYS);
	      &add_to_list($tapeid, $location, "ci");
	  }
	      
	  next tape_loop;
      }

      # if the tape is going to be freed within Y days, skip it
      $keep = $level_keep{$chain, $level} + 0;

      if ($start + $keep - $offsite_extra{$chain} < time) {
	  print "    skipped - to be freed in Y days\n"
	    if $opt_d & $DEBUG_INFO;

	  if ($tape_is_offsite) {
	      $info{$tapeid} = sprintf("tape will be free in %.2f days",
				       ($start + $keep - time) / $DAYS);
	      &add_to_list($tapeid, $location, "ci");
	  }

	  next tape_loop;
      }

      # whew, passed all thoses tests, so it should be offsite
      print "    should be offsite\n"
	if $opt_d & $DEBUG_INFO;

      if ($tape_is_offsite) {
	  if ($location ne $new_location) {
	      $info{$tapeid} = "tape is at $location but should be at $new_location";
	      &add_to_list($tapeid, $location, "move");
	  } else {
	      $info{$tapeid} = "run $run chain $chain,$level $date";
	      &add_to_list($tapeid, $location, "list");
	  }
      } else {
	  $info{$tapeid} = "run $run chain $chain,$level $date";
	  &add_to_list($tapeid, $new_location, "co");
      }
  }

#
# For each location that we've dealt with, print the list of what should be 
# off site, what should be taken off site, and what should be brought back.
#
foreach $location (sort keys %locations_seen) {
    print "Location $location\n";

    print "  What Should Be There\n";
    &list_stuff($location, "list", 1);

    print "  What to Take There\n";
    &list_stuff($location, "co", 1);

    print "  What to Bring Back\n";
    &list_stuff($location, "ci", 1);

    print "  Things That Need to Move\n";
    &list_stuff($location, "move", 1);
}

&close_db(*TAPEDB, $tape_db_file);
&close_db(*RUNDB, $run_db_file);

exit(0);
