#!/bin/bash
## #############################################################
## Spliting up subdirectories for archiving
## 
## Usage:
##   split_for_dvd_burn.bash [switches] arg
##
## Frozen Versions:  
##
## Relies on: (see help description)
##
## #############################################################
## $Id: split_for_dvd_burn.bash,v 1.12 2005/05/06 05:59:53 oli Exp $
## #############################################################
## @TABLE OF CONTENTS:		       [TOCD: 20:55 05 May 2005]
##
##      [0.1] ELEMENTAR SETUP
##  [1] AUX FUNCTIONS
##      [1.1] BIN PACKING
##  [2] MAIN
##      [2.1] READ OPTIONS
##      [2.2] DERIVED VALUES
##      [2.3] SANITY CHECK
##      [2.4] REQUIRED SUB-SCRIPTS and UNIX FUNCTIONS
##      [2.5] SPAM
##  [3] PROCESSING
##      [3.1] INIT
##      [3.2] CHECK FEASIBILITY
##      [3.3] DISTRIBUTE
##      [3.4] CREATE LINKS
##  [4] EMACS VARIABLES
## #############################################################
## @FILE:    split_for_dvd_burn.bash
## @PLACE:   Linux Homestation
## @FORMAT:  Bash Script
## @AUTHOR:  M. Oliver M'o'ller     <omoeller@verify-it.de>
## @BEGUN:   Sat Jan 15 17:13:35 2005
## @VERSION: $Revision: 1.12 $           Thu May  5 22:46:30 2005
## #############################################################
##
SHELL=/bin/bash

## ###############################################
## [0.1] ELEMENTAR SETUP
## ###############################################

## Shell settings
INFILE="";
VERBOSE=false;
QUIET=false;
MAX_MB_PER_DIR=4400 ;
DIR_PREFIX=dvd_ ;
OFFSET=0;
TMPFILE_ALL_FILES=/tmp/tmp.split_for_dvd_burn.bash.all_files.$$
TMPFILE_ALL_DIRS=/tmp/tmp.split_for_dvd_burn.bash.all_dirs.$$
OPTION_ONLYSHOW=false;
OPTION_NEWER_DATE="";
NEWER_DATE_DATE="";
HERE=`dirname $0`;
ME=`basename $0`;
COPY_FILES=true;
BIN_PACK=false;
SOURCE_DIR=$PWD;
TARGET_DIR=/root/Burn ;
## ----------------------------------------------------
VERSION_NUMBER=$(echo "$Revision: 1.12 $" | cut -d':' -f2 | cut -d'$' -f1);
VERSION_DATE="Thu May  5 22:46:30 2005" ;
VERSION="${VERSION_NUMBER} [${VERSION_DATE}]";

declare -a dir_array[1000];
declare -a size_array[1000];

## needed for bin packing
declare -a dist_dir[100000]; 
declare -a size_dir[100000];
declare -a name_dir[100000];
declare -a aux_dist_dir[100000]; # assignment dir -> disc


N_DIR=0;
COUNT=0;


## ###################################################################
## [1] AUX FUNCTIONS
## ###################################################################

function print_usage {
  echo "${ME}  (${VERSION})" 1>&2;
  echo "" 1>&2;
  echo "usage:   ${ME}  [OPTIONS] " 1>&2;
  echo "options: --help       -h   : print help" 1>&2;
  echo "         --verbose    -v   : verbose on" 1>&2;
  echo "         --size       -m N : set max disc size to N MB (default: ${MAX_MB_PER_DIR})" 1>&2;
  echo "         --source-dir -s D : root directory of data (default: .)" 1>&2;
  echo "         --target-dir -t D : directory to create symlinks in (default: ${TARGET_DIR})" 1>&2;
  echo "         --newer-date -d T : only those newer that date T (e.g. T=\"2005-01-01\")" 1>&2;
  echo "         --only-show  -n   : do not create directories, only show" 1>&2;
  echo "         --prefix     -p X : use string X as directory prefix (default: ${DIR_PREFIX})" 1>&2;
  echo "         --offset     -o N : skip first N DVDs in counting (default: 0)" 1>&2;
  echo "         --no-files   -x   : do not create copies of files found in source-dir" 1>&2; 
  echo "         --bin-pack   -b   : dont use alpabetic order, but pack optimally" 1>&2; 
  echo "         --version         : print version" 1>&2;
}
function print_help {
  print_usage;
  echo "";
  echo "description:";
  echo "  This script generates a segmented copy of a directory tree, starting" ;
  echo "  at source-dir (default: .):";
  echo "     <TARGET_DIR>/${DIR_PREFIX}01/ ";
  echo "     <TARGET_DIR>/${DIR_PREFIX}02/ ";
  echo "     ... ";
  echo "  For all sub-directories of . symbolic links are generated that are distributed" ;
  echo "  alphabetically (unless option -b is selected), such that no segment ${DIR_PREFIX}NN ";
  echo "  exceeds a given size limit (option -m, default: ${MAX_MB_PER_DIR} MB)";
  echo "  All files in . are copied to each segment (unless option -x is selected).";
  echo "  ";
  echo "  Since the copies mainly consist of symbolic links, they will not use up much ";
  echo "  disc space. Make sure that your burn application is set to FOLLOW these symbolic";
  echo "  links. E.g, in k3b, select burn option 'advanced/follow symbolic link'";
  echo "  A file OVERVIEW.txt summarizes the distribution of sub-directories to segments.";
  echo " ";
  echo "  This works well for a large number of sub-directories, each of moderate size.";
  echo "  Warning: The bin packing algorithm is very slow!";
  echo " ";
  echo "relies on:  array sed ";
  echo "";
  echo "author:      M. Oliver M'o'ller     <omoeller@verify-it.de>";
  exit 1;
}

function remove_tempfiles {
    if [ -f ${TMPFILE_ALL_DIRS} ]; then
	rm ${TMPFILE_ALL_DIRS};
    fi;
    if [ -f ${TMPFILE_ALL_FILES} ]; then
	rm ${TMPFILE_ALL_FILES};
    fi;
}
function abort { ## -- clear the temp files --
  echo "$0: ERROR: $1" 1>&2;
  remove_tempfiles;
  echo "** $0 aborted." 1>&2;
  exit 1;
}
function abort_on_error { ## -- clear the temp files --
    if [ $1 -ne 0 ]; then
	abort "$@";
    fi
} 
function confirm()
{
  echo -n "$@ (y/N)? " >&2
  read CONFIRM_QUERY_ANSWER
  case $CONFIRM_QUERY_ANSWER in
    y	  ) echo true;;
    Y	  ) echo true;;
    yes   ) echo true;;
    YES   ) echo true;;
    *	  ) echo false;;
  esac	
}
function get_last {
    local RESULT="";
    for f in "$@"; do
	RESULT=$f;
	echo "----- $f";
    done;
    echo ${RESULT}
}

## total number of KB
function du_total_from_filelist {
    if [ ! -f "$1" ]; then
	abort 1 "du_total_from_filelist: no such file '$1'"
    fi;
    du -c -k  $(cat ${1} ) \
	| grep -e "[0-9]*[ \t]*total$" \
	| sed  's/[^0-9].*$//g';
}
## total number of KB
function du_total_from_dir {
    if [ ! -d "$1" ]; then
	abort 1 "du_total_from_filelist: no such dir '$1'"
    fi;
    du -c -k  ${1} \
	| grep -e "[0-9]*[ \t]*total$" \
	| sed  's/[^0-9].*$//g';
}

function get_dir { ## -- get abs path to directory that is $1-relative to script
    local RESULT;
    pushd $(dirname $0) >/dev/null 2>/dev/null ; 
    if [ -z "$1" ]; then
	export RESULT=$PWD;
    else
	cd $1;
	abort_on_error $? "Failed to change to dir $PWD + $1 ";
	export RESULT=$PWD;
    fi;
    popd >/dev/null 2>/dev/null ; 
    echo ${RESULT}; 
}
function abs_dir { ## -- get abs path to directory that is $1-relative to pwd
    local RESULT;
    if [ -z "$1" ]; then
	export RESULT=$PWD;
    else
	cd $1;
	abort_on_error $? "Failed to change to dir $PWD + $1 ";
	export RESULT=$PWD;
    fi;
    echo ${RESULT}; 
}
function get_version_number_of_script { ## 0.00: nonexistent!
  PROG=$(which $1 2>/dev/null);
  if [ ! -z "${PROG}" ] && [ -x "${PROG}" ]; then
    $PROG --version 2>/dev/null |sed -e "s/@//g" |sed -e "s/\\./@/1" | sed -e "s/[^0123456789@]//g" | sed -e "s/@/./g" ;
  else
    echo "0.00";
  fi
}
function compute_minus { ## minus, scaled (used for comparison of floats)
  echo "10000000.0*(($1)-($2))" | bc -l | cut -d'.' -f 1;
}
function blurt { ## output some text, if ${VERBOSE} is true
    if ${VERBOSE}; then
	echo "$@";
    fi;
}
function set_noswitch_arguments {
  if [ -z ${INFILE} ]; then
    INFILE=$1;
  else
    abort "surplus argument: $1";
  fi
}
function clear_file {
    if [ -z "$1" ]; then
	echo "INTERNAL ERROR: clear_file called without argument";
	exit 99;
    fi;
    rm -f $1;
    touch $1;
    abort_on_error $? "failed to write to file $1";
}

## -- other aux functions:


function add_link_to_next_dir { ## $1: directory to add
    if [ ! -d "$1" ]; then
	abort 1 "du_total_from_filelist: no such dir '$1'"
    fi;

    if [ $((${CURRENT_SUM} + $(du_total_from_dir $1))) -ge ${MAX_KB_PER_DIR} ]; then
	export N_DIR=$((${N_DIR}+1));
	export CURRENT_SUM=$((${DU_FILES} + $(du_total_from_dir $1)));
	dir_array[${N_DIR}]="$1";
	size_array[${N_DIR}]="${CURRENT_SUM}";
    else
	export CURRENT_SUM=$((${CURRENT_SUM} + $(du_total_from_dir $1)));
	dir_array[${N_DIR}]="${dir_array[${N_DIR}]} $1";
	size_array[${N_DIR}]="${CURRENT_SUM}";
    fi;
}

function aux_create_overview { ## $1: file name to create
    local COUNT=1;
    echo "" > ${1};
    abort_on_error $? "cannot write to file $1";

    echo "** ********************************************" >> $1 ;
    echo "** TOTAL NUMBER OF DISCS: ${N_DIR} : $((${OFFSET}+1)) - $((${OFFSET}+${N_DIR})) " >> $1 ;
    echo "** ********************************************" >> $1 ;
    echo "" >> $1 ;
    while [ ${COUNT} -le ${N_DIR} ]; do
	echo "++ DISC $((${COUNT}+${OFFSET})) [$((${size_array[${COUNT}]} / 1024)) MB] +++++++++++++++++++++++++++++++" >> $1 ;
	for f in ${dir_array[${COUNT}]}; do
	    echo "   $f" >> $1 ;
	done;
	echo "" >> $1 ;

	COUNT=$((${COUNT}+1));
    done;
}

function show_all {
    local TMP_OVERVIEW=/tmp/tmp.split_for_dvd_burn.bash.overview.$$ ;
    aux_create_overview ${TMP_OVERVIEW};
    cat ${TMP_OVERVIEW};
    rm ${TMP_OVERVIEW};
}
function create_overview {
    aux_create_overview ${FILENAME_OVERVIEW};
}

## ###################################################################
## [1.1] BIN PACKING
## ###################################################################

# NOTE:
# The bin packing problem (assignment of N objects of differen size to a
# minimal number K of containers of fixed size S) is NP-Complete. For large or
# mean instances of this problem, every known algorithm will run in
# superpolynomial time.
# A bash script is certainly not your choice of language to solve these
# instances.
#
# The algorithm used here is rather simple (spell: stupid), but complete.
# The idea is that we start with a theoretically possible K, and
# systematically try all combinations for feasibility (i.e. no container
# overflows). 
# If no such solution exists, K is incremented.
# As soon as a feasible solution for the current K is found, the algorithms
# stops. 


# Determine whether a combination is feasible
# $1: N_DIRS
function is_feasible {
    local RESULT=true;
    local DIR=1;
    local DISC;
    local VALUE;

#    echo "? is_feasible ${aux_dist_dir[1]} ${aux_dist_dir[2]} ${aux_dist_dir[3]} ..." >&2 ;

    DISC=1;
    while [ ${DISC} -le ${BEST_NUMBER_OF_DISCS} ]; do
	size_array[${DISC}]=${DU_FILES};
	DISC=$((${DISC}+1));
    done;

    while ${RESULT} && [ ${DIR} -le ${1} ] ; do
	DISC=aux_dist_dir[${DIR}];
	VALUE=$((${size_array[${DISC}]} + ${size_dir[${DIR}]}));
	if [ ${VALUE} -le ${MAX_KB_PER_DIR} ]; then
	    size_array[${DISC}]=${VALUE};
	else
	    RESULT=false;
	fi;
	DIR=$((${DIR}+1));
    done

    echo ${RESULT};
}

function bin_pack {
    local N_DIRS=0;
    local DIR;
    local DISC;
    local POS;
    local FINISH;
    
    echo "## USING BIN-PACKING: stopping when an minimal assignment is found";
    echo "## !! WARNING !!      This may run a LONG time...";
    echo "";

## -- initial best assigment is the alpabetic one --------------------------
    size_array[1]=${DU_FILES};

    DISC=1;
    for f in $(cat ${TMPFILE_ALL_DIRS}); do

	N_DIRS=$((1+${N_DIRS}));
	size_dir[${N_DIRS}]=$(du_total_from_dir $f);
	name_dir[${N_DIRS}]=$f;
	aux_dist_dir[${N_DIRS}]=1;

	if [ $((${size_array[${DISC}]} + ${size_dir[${N_DIRS}]})) -gt ${MAX_KB_PER_DIR} ]; then
	    DISC=$((${DISC}+1));
	    size_array[${DISC}]=${DU_FILES};
	fi
	dist_dir[${N_DIRS}]=${DISC};
	size_array[${DISC}]=$((${size_array[${DISC}]}+${size_dir[${N_DIRS}]}));

    done;

    BEST_NUMBER_OF_DISCS=${DISC};
    if ! ${QUIET}; then
	echo "## current best number of discs: ${BEST_NUMBER_OF_DISCS}";
	echo "## theoretically possible min number of discs: ${MIN_NUMBER_OF_DISCS}";
    fi;
## -- Compute a minimal assignment -----------------------------------------

    while [ ${BEST_NUMBER_OF_DISCS} -gt ${MIN_NUMBER_OF_DISCS} ]; do

	if $(is_feasible ${N_DIRS}); then
	    if [ ${MIN_NUMBER_OF_DISCS} -lt ${BEST_NUMBER_OF_DISCS} ]; then
		BEST_NUMBER_OF_DISCS=${MIN_NUMBER_OF_DISCS};
		DIR=1;
		while [ ${DIR} -le ${N_DIRS} ]; do
		    dist_dir[${DIR}]=${aux_dist_dir[${DIR}]};
		    DIR=$((${DIR}+1));
		done;
	    fi
	fi;
	
## -- count up ----------------------------------------
	POS=1;
	FINISHED=false;

	while ! ${FINISHED} && [ ${POS} -le ${N_DIRS} ] ; do
	    VALUE=$((1+${aux_dist_dir[${POS}]}));
	    if [ ${VALUE} -le ${MIN_NUMBER_OF_DISCS} ]; then
		aux_dist_dir[${POS}]=${VALUE};
		#echo "increment pos ${POS} to ${VALUE}" >&2 ;
		#echo "${aux_dist_dir[${POS}]}             " >&2 ;
		FINISHED=true;
	    else
		aux_dist_dir[${POS}]=1;
		POS=$((${POS}+1));
	    fi
	done
	if [ ${POS} -gt ${N_DIRS} ]; then ## OVERFLOW
	    export MIN_NUMBER_OF_DISCS=$((${MIN_NUMBER_OF_DISCS}+1));
	    if ! ${QUIET}; then
		echo "## theoretically possible min number of discs: ${MIN_NUMBER_OF_DISCS}";
	    fi;
	    DIR=1;
	    while [ ${DIR} -le ${N_DIRS} ]; do
		aux_dist_dir[${N_DIRS}]=1;
		DIR=$((${DIR}+1));
	    done;
	else
	    if ${VERBOSE}; then
		:
		#echo "Counted up to ${aux_dist_dir[1]} ${aux_dist_dir[2]} ${aux_dist_dir[3]} ..." >&2 ;
	    fi;
	fi;

    done;

## -- Create this assignment -----------------------------------------------

    DISC=1;
    while [ ${DISC} -le ${BEST_NUMBER_OF_DISCS} ]; do
	dir_array[${DISC}]="";
	size_array[${DISC}]=${DU_FILES};
	DISC=$((${DISC}+1));
    done;


    DIR=1;
    while [ ${DIR} -le ${N_DIRS} ]; do
	DISC=${dist_dir[${DIR}]};
	dir_array[${DISC}]="${dir_array[${DISC}]} ${name_dir[${DIR}]}";
	size_array[${DISC}]=$((${size_array[${DISC}]} + ${size_dir[${DIR}]}));

	DIR=$((${DIR}+1));
    done;
	
## -- show assignment ------------------------------------------------------

    if ${VERBOSE}; then
	echo "## Minimal assignment found: ";
	DIR=1;
	while [ ${DIR} -le ${N_DIRS} ]; do
	    echo "${DIR} : ${name_dir[${DIR}]} (${size_dir[${DIR}]} KB) -> disc ${dist_dir[${DIR}]}";
	    DIR=$((${DIR}+1));
	done
    fi;

## -- set number of discs --------------------------------------------------

    export N_DIR=${BEST_NUMBER_OF_DISCS};
}

## ###################################################################
## [2] MAIN
## ###################################################################


## ###############################################
## [2.1] READ OPTIONS
## ###############################################


AWAIT="";
for switch in $@; do
  case $AWAIT in
	    -m ) AWAIT=""; export MAX_MB_PER_DIR=$switch;;
	    -p ) AWAIT=""; export DIR_PREFIX=$switch;;
	    -d ) AWAIT=""; export NEWER_DATE_DATE=$(echo $switch | sed 's/#/ /g');;
	    -o ) AWAIT=""; export OFFSET=$switch;;
	    -s ) AWAIT=""; export SOURCE_DIR=$(abs_dir $switch);;
	    -t ) AWAIT=""; export TARGET_DIR=$(abs_dir $switch);;
	    *  ) case $switch in
	     --help ) print_help;;
	      -help ) print_help;;
	         -h ) print_help;;
          --verbose ) VERBOSE=true;;
	         -v ) VERBOSE=true;;
	         -q ) QUIET=true;;
        --only-show ) OPTION_ONLYSHOW=true;;
                 -n ) OPTION_ONLYSHOW=true;;
             --size ) AWAIT="-m";;
                 -m ) AWAIT="-m";;
           --prefix ) AWAIT="-p";;
                 -p ) AWAIT="-p";;
       --newer-date ) AWAIT="-d";;
                 -d ) AWAIT="-d";;
	         -o ) AWAIT="-o";;
           --offset ) AWAIT="-o";;
       --source-dir ) AWAIT="-s";;
                 -s ) AWAIT="-s";;
       --target-dir ) AWAIT="-t";;
                 -t ) AWAIT="-t";;
         --no-files ) COPY_FILES=false;;
                 -x ) COPY_FILES=false;;
         --bin-pack ) BIN_PACK=true;;
                 -b ) BIN_PACK=true;;
          --version ) echo "Version:   $VERSION";exit 0;;
		 -* ) echo "Unknown switch: $switch";print_usage;exit 1;;
                 *  ) set_noswitch_arguments $switch;; 
	         esac
  esac
done;


## ###############################################
## [2.2] DERIVED VALUES
## ###############################################

export MAX_KB_PER_DIR=$((1024 * ${MAX_MB_PER_DIR}));

## ###############################################
## [2.3] SANITY CHECK
## ###############################################


if [ ! -d ${SOURCE_DIR} ]; then
  echo "$0: source directory ${SOURCE_DIR} does not exist." 1>&2;
  print_usage;
  exit 1;
fi

if [ ! -d ${TARGET_DIR} ]; then
  echo "$0: target directory ${TARGET_DIR} does not exist." 1>&2;
  print_usage;
  exit 1;
fi
FILENAME_OVERVIEW=${TARGET_DIR}/OVERVIEW.txt;

if [ ! -z "${NEWER_DATE_DATE}" ]; then
    COMPUTED_MINUTES=$(echo \($(date +%s) - \
	$(date --date "${NEWER_DATE_DATE}" +%s) \) / 60 | bc);
    OPTION_NEWER_DATE="-mmin -${COMPUTED_MINUTES}";

    if [ ${COMPUTED_MINUTES} -lt 0 ]; then
	echo "ERROR: selected date \"${NEWER_DATE_DATE}\" is in the future.";
	exit 1;
    fi
fi;

## ###############################################
## [2.4] REQUIRED SUB-SCRIPTS and UNIX FUNCTIONS
## ###############################################


#SCRIPT_VERSION=$(get_version_number_of_script fig2eps);
#if [ $(compute_minus $SCRIPT_VERSION 1.0) -lt 0 ]; then
#  echo "$0: Need SCRIPT 1.0 or higher. " 1>&2;
#  echo "Sorry. " 1>&2;
#  exit 1;
#fi;


## ###############################################
## [2.5] SPAM
## ###############################################

if $VERBOSE; then
    echo "----------------------------------------------------------------------";
    echo "SOURCE_DIR:                ${SOURCE_DIR}" ;
    echo "TARGET_DIR:                ${TARGET_DIR}" ;
    echo "MAX_MB_PER_DIR:            ${MAX_MB_PER_DIR}" ;
    echo "MAX_KB_PER_DIR:            ${MAX_KB_PER_DIR}" ;
    echo "DIR_PREFIX:                ${DIR_PREFIX}" ;
    echo "OPTION_ONLYSHOW:           ${OPTION_ONLYSHOW}" ;
    echo "NEWER_DATE_DATE:           ${NEWER_DATE_DATE}" ;
    echo "OPTION_NEWER_DATE:         ${OPTION_NEWER_DATE}" ;
    echo "OFFSET:                    ${OFFSET}" ;
    echo "QUIET:                     ${QUIET}" ;
    echo "COPY_FILES:                ${COPY_FILES}" ;
    echo "BIN_PACK:                  ${BIN_PACK}" ;
    echo "VERBOSE:                   ${VERBOSE}" ;
    echo "VERSION:                   ${VERSION}" ;
    echo "----------------------------------------------------------------------";
fi;

## ###################################################################
## [3] PROCESSING
## ###################################################################


## ###############################################
## [3.1] INIT
## ###############################################

echo "## ls -l ${TARGET_DIR} --------------------------------  ";
ls -l ${TARGET_DIR} ;
echo "## END OF ls -l ${TARGET_DIR} --------------------------------  ";
if $(confirm "clean up target dir: ${TARGET_DIR} "); then
    rm -rf ${TARGET_DIR}/*;
fi;

clear_file ${TMPFILE_ALL_FILES} ;
clear_file ${TMPFILE_ALL_DIRS} ;

if ${COPY_FILES}; then 
    find ${SOURCE_DIR}/ -name "*" -type f -maxdepth 1  > ${TMPFILE_ALL_FILES};
fi;
find ${SOURCE_DIR}/* -name "*" -type d -maxdepth 0  ${OPTION_NEWER_DATE} > ${TMPFILE_ALL_DIRS};

if [ -S ${TMPFILE_ALL_DIRS} ]; then
    echo "ERROR: no directories found.";
    exit 1;
fi;

export DU_FILES=0;
if [ -S ${TMPFILE_ALL_FILES} ]; then
    export DU_FILES=$(du -c -k $(cat ${TMPFILE_ALL_FILES} ) \
	| grep -e "[0-9]*[ \t]*total$" \
	| sed  's/[^0-9].*$//g');
fi;
DU_DIRS=$(du_total_from_filelist ${TMPFILE_ALL_DIRS});

if ! ${QUIET}; then
    echo "## ALL FILES (${DU_FILES} KB -> $((${DU_FILES} /1024)) MB):";
    cat ${TMPFILE_ALL_FILES}
    echo "";
    echo "## ALL DIRS (${DU_DIRS} KB -> $((${DU_DIRS}/1024)) MB):";
    cat ${TMPFILE_ALL_DIRS}
    echo "";
fi;


## ###############################################
## [3.2] CHECK FEASIBILITY
## ###############################################

export TOTAL_KB_TO_BURN=0;

for f in $(cat ${TMPFILE_ALL_DIRS}); do
    THIS_DIR_KB=$(du_total_from_dir $f);
    export TOTAL_KB_TO_BURN=$((${TOTAL_KB_TO_BURN}+${THIS_DIR_KB}));

    if [ $((${DU_FILES}+${THIS_DIR_KB})) -ge ${MAX_KB_PER_DIR} ]; then
	echo "ERROR: cannot keep size limit of ${MAX_KB_PER_DIR} KB."
	echo "       Follwing directory is too big:";
	echo "         $f   ($(du_total_from_dir $f) KB)";
	echo "       (together with ${DU_FILES} KB of commonly copied files)";
	exit 1;
    fi;
done;

## ###############################################
## [3.3] DISTRIBUTE
## ###############################################


export DISC_SPACE=$((${MAX_KB_PER_DIR}-${DU_FILES}));
export MIN_NUMBER_OF_DISCS=$((${TOTAL_KB_TO_BURN} / ${DISC_SPACE}));

if [ 0 -ne $((${TOTAL_KB_TO_BURN} % ${DISC_SPACE})) ]; then
    export MIN_NUMBER_OF_DISCS=$((${MIN_NUMBER_OF_DISCS}+1));
fi  
if ! ${QUIET}; then
    echo "## ${TOTAL_KB_TO_BURN} KB vs DISC SPACE ${DISC_SPACE} KB ";
    echo "## The minimal number of required discs is at least ${MIN_NUMBER_OF_DISCS}";
fi;

if ${BIN_PACK}; then

    bin_pack ;

else
    if ! ${QUIET}; then
	echo "## DISTRIBUTING ${TOTAL_KB_TO_BURN} KB ALPHABETICALLY ";
    fi

    CURRENT_SUM=${MAX_KB_PER_DIR};
    for f in $(cat ${TMPFILE_ALL_DIRS}); do
	add_link_to_next_dir $f;
    done;
fi;


if ${VERBOSE} || ${OPTION_ONLYSHOW}; then
    show_all;
fi;

## ###############################################
## [3.4] CREATE LINKS
## ###############################################

if ! ${OPTION_ONLYSHOW}; then
    create_overview;
    COUNT=1;
    while [ ${COUNT} -le ${N_DIR} ]; do
	blurt "## CREATING DISC $((${COUNT}+${OFFSET}))";
	CURRENT_DIR=${TARGET_DIR}/${DIR_PREFIX}$(printf "%02d" $((${COUNT}+${OFFSET})));
	mkdir ${CURRENT_DIR};
	abort_on_error $? "Creation of  ${CURRENT_DIR} FAILED";
	if [ -S ${TMPFILE_ALL_FILES} ]; then
	    cp $(cat ${TMPFILE_ALL_FILES}) ${CURRENT_DIR}/ ;
	fi;
	cp ${FILENAME_OVERVIEW} ${CURRENT_DIR}/ ;
	for d in ${dir_array[${COUNT}]}; do
	    ln -s $d ${CURRENT_DIR} ;
	    abort_on_error $? "FAILED to create symbolic link to $d" ;
	done;
	COUNT=$((${COUNT}+1));
    done;
fi;

## ----------------------------------------------------
remove_tempfiles;
if ! ${QUIET} && ! ${OPTION_ONLYSHOW}; then
    echo "";
    echo "** -----------------------------------------------------------------------";
    echo "** READY TO BURN ${N_DIR} SUB-DIRECTORIES OF  ${TARGET_DIR}";
    echo "** NOTE: Make sure that your burn program follow the symbolic links."
    echo "** e.g, in k3b, select burn option 'advanced/follow symbolic link'";
    echo "** -----------------------------------------------------------------------";
    echo "";

fi;
exit 0; ## --- OK -------------------------------------


## ###################################################################
## [4] EMACS VARIABLES
## ###################################################################


### Local Variables: ***
### mode: lisp ***
### eval: (defun update-global-date () (let ((pos (point-marker))) (goto-char (point-min)) (if (search-forward-regexp "^VERSION_DATE=" (point-max) t) (progn (kill-line) (insert (format "\"%s\" ;" (current-time-string))) (basic-save-buffer) (message "** Version Date Updated."))) (goto-char pos))) ***
### eval: (defun new-global-hh-insert-disclaimer () (interactive) (insert-disclaimer) (update-global-date) (shell-script-mode)(font-lock-mode) (local-set-key [f4] #'new-global-hh-insert-disclaimer)) ***
### eval: (progn (shell-script-mode)(font-lock-mode) (local-set-key [f4] #'new-global-hh-insert-disclaimer)) ***
### comment-column:0 ***
### comment-start: "### "  ***
### comment-end:"***" ***
### End: ***
