#
# Copyright (c) 1995 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.
#

#
# Extra routines that access the databases directly - shouldn't be in
# lib-db (since that isn't backup-specific), but its nice to have
# these separated so people stand a chance of implementing them on a
# different database layer...
#

#
# sort_by_use sorts a list of tapeids according to their usage counts 
# in usage_list.
#

sub sort_by_use {
    return($usage_list{$a} - $usage_list{$b});
}

#
# choose_tape picks N free tape from the tape database and returns the
# list of tape IDs.
#
# fixme: ought to deal with write_formats somehow, but what to do?
#

sub choose_tape {
    local($type, $read_formats, $write_format, $location, $number, $run) = @_;
    local($found_tapeid, %found_array, %usage_list);
    local(%TAPES, $tapeid, $value, $tape_value, %tape_array);
    local($free_tapes_available);

    &sigh("error ($0): can't lock $tape_db_file in choose_tape, timed out\n")
      if &lock($tape_db_file) != $LOCK_OK;

    &open_db(*TAPES, $tape_db_file, $db_mode) ||
	&sigh("error (all-backups): can't open the tape dbm file '$tape_db_file' in choose_tape\n");

    $found_tapeid = -1;

find_tape:
    foreach $tapeid (&keys_db(*TAPES)) {
        &read_db(*TAPES, $tapeid, *tape_value, *tape_array);

	# 
	# if the tape is free, of the right type and format, 
	# located here, and has the minimal usage count, consider it
        #
        if ($tape_array{"flags"} eq "free" && 
	    $tape_array{"type"} eq $type &&
	    &valid_format($tape_array{"format"}, 
			  split(/\|/, $read_formats))) {

	    #
	    # If the location of the drive is known and the tape 
	    # has a location, they must be the same.
	    #
	    if ($location ne "" && $tape_array{"location"} ne "") {
		next find_tape if $location ne $tape_array{"location"};
	    }

	    $usage_list{$tapeid} = $tape_array{"uses"}+0;
	}
    }

    #
    # Now we have a list of candidates.  Sort them by usage (least to
    # most)...
    #
    @candidates = sort sort_by_use keys %usage_list;

    #
    # If there aren't enough tapes, complain and quit.
    #
    if (($#candidates + 1) < $number) {
	$free_tapes_available = $#candidates + 1;
	&close_db(*TAPES, $tape_db_file);
	&unlock($tape_db_file);
	&sigh("error ($0): there are only $free_tapes_available free tapes available.\n");
    }

    #
    # ... and pick the N least used tapes, mark them as promised...
    #
    for ($i = 0; $i < $number; $i++) {
	if (! &read_db(*TAPES, $candidates[$i], *value, *tape_array)) {
	    &sigh("error ($0): choose_tape can't read entry for tape $candidates[$i]\n");
	}

	$tape_array{"flags"} = "promised";
	$tape_array{"used_date"} = time;
        $tape_array{"run_id"} = $run;

	if (! &write_db(*TAPES, $candidates[$i], *tape_array, 
			$tape_db_file, "tape_db")) {
	    &sigh("error ($0): choose_tape can't write entry for tape $candidates[$i]\n");
	}
    }

    &close_db(*TAPES, $tape_db_file);

    &unlock($tape_db_file);

    printf("choose_tape: using tape(s) %s\n", 
	   join(' ', @candidates[0..$number-1]))
      if $opt_d & $DEBUG_INFO;

    return(@candidates[0..$number-1]);
}

1;
