#!/bin/bash

#	 Copyright (C) 2013  <Pavlo Solntsev pavlo.solntsev@gmail.com>
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.


setup_file=~/.firely.conf

echo "+++++++++++++++++++++++++++++++++++"
echo "+       Firefly Configurator      +"
echo -e "+++++++++++++++++++++++++++++++++++\n"

function trundec()
{
	local input=$1
	local res;
	res=`echo $input | bc`
	echo $res
}

function create_conf()
{
# Read variable 
	echo "=== Configuration File Setup ==="
	echo "Here you can define default parameters for your job."
	echo "You can very easy overwrite them on the fly.\n"
	echo "Define a default number of nodes: "
	read default_node
	echo "Define a default number of CPUs per one node: "
	read default_cpu
	echo "Define a default queue name: "
	read default_queue
	echo "Define a default time allowed for your job in format dd:hh:mm:ss or hh:mm:ss"
	read default_time
	echo "Define default amount of overall memory for your job. Use suffix Gb,Mb,Kb,B: 100Mb"
	read default_memory
	echo "It is a time to setup a MPI library..."
	echo "Provide a full path to the MPI home dirrectory."
	echo "This dirrectory should contain bin and lib directories."
	read mpi_path
	echo "Provide a path for temporary files storage (/scratch, /tmp etc.)"
	read default_temp_dir
	echo "What is a path for Firefly home directory?"
	read firefly_home
	echo "Define default parameters for Firefly, i.e -r -f -p "
	read default_parameters
	echo "Provide Firefly's executable filename (firefly8, firefly8.mpich etc.)"
	read ffexec
	echo "Input a full path to a directory with extensions: fastdiag.ex etc."
	read default_exdir
	echo "=== End of Configuration File Setup ==="
# save default data to the file
	echo "default_node $default_node" > $setup_file
	echo "default_cpu $default_cpu" >> $setup_file
	echo "default_queue $default_queue" >> $setup_file
	echo "default_time $default_time" >> $setup_file
	echo "default_memory $default_memory" >> $setup_file
	echo "mpi_path \"$mpi_path\"" >> $setup_file
	echo "default_temp_dir \"$default_temp_dir\"" >> $setup_file
	echo "firefly_home \"$firefly_home\"" >> $setup_file
	echo "default_exdir \"$default_exdir\"" >> $setup_file
	echo "ffexec $ffexec" >> $setup_file
	echo "default_parameters \"$default_parameters\"" >> $setup_file
}

function helpmsg()
{
echo -e "\n qff [-s ] [-N jobname] [-n node] [-p cpu] [-m mem] [-t hh:mm:ss] [-q queue_name] [-b extfile] [-d libdir] [-o ff_parameter] inputfile.inp 
    -h|--help        print usage info
    -s|--setup       Setup $0 configuration file
    jobname          name of the PBS job. Default <inputfile>.
    node             number of nodes. Default $default_node
    cpu              number of cpu's per one node. Default $default_cpu
    mem              amount of total memmory in format of qsub. See \"man qsub\" for details. Default $default_memory
    dd:hh:mm:ss      walltime in the format of qsub. See \"man qsub\" for datails. Default $default_time.
    queue_name       name of the queue of interest. Default $default_queue.
    extfile          File with external basis set
    libdir           Dirrectory with basis set files. Appropriate '@basis' settings should be presented in the input file.
    ff_parameter     any parameters which may be passed to Firefly. Default $default_parameters
    inputfile.inp    input file. 
"
}

function wall2sectime()
{
	local timeline=$1
	local timecheck=${timeline//[^:]}
	local timemode=${#timecheck}
	local days=1
	local hours=1
	local minutes=1
	local seconds=1

	case $timemode in 
	2)
		hours=${timeline%*:*:*}
		temp1=${timeline%*:*}
		minutes=${temp1#*:*}
		seconds=${timeline#*:*:*}
		echo $((hours*60*60+minutes*60+seconds))
		;;
	3)	
		temp1=${timeline%*:*:*}
		days=${temp1%*:*}
		hours=${temp1#*:}
		temp1=${timeline#*:*:*}
		minutes=${temp1%*:*}
		seconds=${temp1#*:*}
		echo $((days*24*60*60+hours*60*60+minutes*60+seconds))
		;;
	*)
		echo 0
		;;
	esac
}

function sec2walltime()
{
	local days
	local hours
	local minutes
	local seconds=$1

	days=$(trundec $(($seconds/(24*60*60))))
	seconds=$(($seconds-$days*24*60*60)) # update seconds to remove amount of days
	hours=$(trundec $(($seconds/(60*60))))
	seconds=$(($seconds-$hours*60*60))	# update seconds to remove amount of hours		
	minutes=$(trundec $(($seconds/60)))
	seconds=$(($seconds-$minutes*60))	# update seconds to remove amount of minutes		
	echo "$days:$hours:$minutes:$seconds"
}

if [ ! -f $setup_file ]; then 
	create_conf;
fi

#read variable form the configuration file
default_node=`grep default_node $setup_file | awk '{print $2}'`
default_cpu=`grep default_cpu $setup_file | awk '{print $2}'`
default_queue=`grep default_queue $setup_file | awk '{print $2}'`
default_time=`grep default_time $setup_file | awk '{print $2}'`
default_memory=`grep default_memory $setup_file | awk '{print $2}'`
mpi_path=`grep mpi_path $setup_file | awk '{print $2}' | sed 's/"//g'`
default_temp_dir=`grep default_temp_dir $setup_file | awk '{print $2}' | sed 's/"//g'`
firefly_home=`grep firefly_home $setup_file | awk '{print $2}' | sed 's/"//g'`
default_parameters=`grep default_parameters $setup_file | sed 's/default_parameters//g' | sed 's/"//g'` 
ffexec=`grep ffexec $setup_file | awk '{print $2}'`
default_exdir=`grep default_exdir $setup_file | awk '{print $2}' | sed 's/"//g'`
#define two variable for external basis set and directory for ff8 preprocessor
default_basisfile="NONE"
default_libdir="NONE"
default_mode="no" # control interactive submission of the job

#default name for the job
for j in $@; do 
    echo $j >> /dev/null
done

default_name=${j%.*}


TEMP=$(`which getopt` -o s::N:n:p:m:t:q:b:o:d:r:h:: --long help --long setup -- "$@");

if (( $? )); then
    echo "getopt error. Check TEMP variable in $0";
    exit 1;
fi


#echo "TEMP $TEMP"

eval set -- "$TEMP"

while true; do
	case $1 in 
	-h|--help)
		helpmsg;
		exit 0;
	;;
	-s|--setup)
		create_conf;
		exit 0;
	;;
	-N) 
		shift;
	   	default_name=$1;
		shift;
	;;
	-n) 
		shift;
	    default_node=$1;
		shift;
	;;
	-p)
		shift;
		default_cpu=$1;
		shift;
	;;
	-m)
		shift;
		default_memory=$1;
		shift;
	;;
	-t)
		shift;
		default_time=$1;
		shift;
	;;
	-q)
		shift;
		default_queue=$1;
		shift;
	;;
	-b)
		shift;
		default_basisfile=$1;
		shift;
	;;
	-d)
		shift;
		default_libdir=$1;
		shift;
	;;
	-o)
		shift;
		default_parameters=$1;
		shift;
	;;
	-r)
		shift;
		default_mode=$1;
		shift;
	;;
	--)
		shift;
		break;
	;;
	*)
		shift;
	;;
	esac
done

#define base name and define INPUT file
JOB=${j%*.inp}
INPUT=$j
# Check input file
if [ "$JOB" == "$j" ]; then 
	JOB=${j%*.INP}
    if [ "$JOB" == "$j" ]; then
		echo "Can't find input file or check extinction. Should be <name>.inp"
	else
		INPUT=$JOB.INP
    fi
else
	INPUT=$JOB.inp

fi
OUTPUT=$JOB.out
PUNCH=$JOB.dat
IRCFILE=$JOB.irc

TOTALCPUS=$(($default_node*$default_cpu))

echo "Job name: $default_name"
echo "Memmory: $default_memory"
echo "Walltim: $default_time"
echo "Total time in seconds" $(wall2sectime $default_time)
echo "Nodes: $default_node"
echo "CPU's: $default_cpu"
echo "Input file is $j"
echo "Job is $JOB"
echo "Queue is $default_queue"
echo "Basis dirrectory is $default_libdir"
echo "Basis set file is $default_basisfile"
echo "Total # of processors is $TOTALCPUS"
echo "Default parameters are $default_parameters"
echo "INPUT: $INPUT"
echo "OUTPUT: $OUTPUT"
echo "IRCFILE: $IRCFILE"
echo "PUNCH: $PUNCH"

#Print info about appropriate timlim
walltimesec=$(wall2sectime $default_time)
timlim=$(trundec $((walltimesec*96/(100*60))))
echo "To cerrectly finish the job execution this line will be added to your input file"
echo " \$SYSTEM TIMLIM=$timlim \$END"
res=$(sec2walltime $walltimesec)
#echo "sec2walltime is $res" 

if [ "$default_libdir" != "NONE" ]; then
	cat $INPUT | sed '/#libdir/d' >  $INPUT.qff
	echo "#libdir ../basis" > $INPUT
	cat $INPUT.qff >> $INPUT
	rm -rf $INPUT.qff
fi
#update timlim reccord
echo -e "\n \$SYSTEM TIMLIM=$timlim \$END" >> $INPUT

#create pbs file
PBSSCR=$JOB.pbs

echo "#!/bin/bash -x" > $PBSSCR
echo "#PBS -N $default_name" >> $PBSSCR
echo "#PBS -l nodes=$default_node:ppn=$default_cpu" >> $PBSSCR
echo "#PBS -l mem=$default_memory" >> $PBSSCR
echo "#PBS -l walltime=$default_time" >> $PBSSCR
echo "#PBS -e $JOB.e" >> $PBSSCR
echo "#PBS -o $JOB.o" >> $PBSSCR
echo "#PBS -q $default_queue" >> $PBSSCR

echo "
export MPI_HOME=$mpi_path
export PATH=\$MPI_HOME/bin:\$PATH
export LD_LIBRARY_PATH=\$MPI_HOME/lib:\$LD_LIBRARY_PATH
export TMP_DIR=$default_temp_dir/\$PBS_JOBID
export FFHOME=$firefly_home
export WORK_DIR=\$PBS_O_WORKDIR
" >> $PBSSCR

if [ "$default_libdir" != "NONE" ]; then 
echo "
mkdir -p \$TMP_DIR/basis
cd \$WORK_DIR
cp $default_libdir/* \$TMP_DIR/ " >> $PBSSCR
fi

FFCOMMAND="/usr/bin/time mpirun -r ssh -np $TOTALCPUS \$FFHOME/$ffexec $default_parameters -ex $default_exdir -i \$WORK_DIR/$INPUT -o \$WORK_DIR/$OUTPUT"

if [ "$default_basisfile" != "NONE" ]; then
	FFCOMMAND="$FFCOMMAND -b \$WORK_DIR/$default_basisfile -t \$TMP_DIR/";
else
	FFCOMMAND="$FFCOMMAND -t \$TMP_DIR/";
fi

echo "
$FFCOMMAND

cd \$WORK_DIR
#Build list for archive
LIST=\"$INPUT $OUTPUT $PUNCH \"
if [ -f $IRCFILE ]; then 
	LIST=\"\$LIST $IRCFILE\"
fi

tar zcvf $JOB.tar.gz \$LIST

cd \$WORK_DIR && rm -rf \$TMP_DIR
rm -rf \$TMP_DIR.*

" >> $PBSSCR

#echo "Do you want to submit the job? [y/n]"
#read answer

if [ "$default_mode" == "yes" ]; then
	qsub $JOB.pbs
elif [ "$default_mode" == "no" ]; then
	echo "Type manually: 'qsub $JOB.pbs' or equivalent command"
else
	echo "Can't recognize you -r $default_mode key. "
	echo "Type manually: 'qsub $JOB.pbs' or equivalent command"
fi
















