#!/usr/bin/env bash
#---------------------------------------------------------------------------
#
#	- less than 2 Gb RAM – swap size: 2 x the amount of RAM
#	- more than 2 GB RAM, but less than 32 GB – swap size: 4 GB + (RAM – 2 GB)
#	- 32 GB of RAM or more – swap size: 1 x the amount of RAM
#
#
#---------------------------------------------------------------------------

path_swap_file="/memory/data/from/0/swapfile"
log_file="/var/log/ub.swap.log"
exec 1> ${log_file}

#remove disable swap, remove it and remove entry from fstab
removeSwap() {
    echo "Will remove swap and backup fstab."
    echo ""

    #get the date time to help the scripts
    backupTime=$(date +%y-%m-%d--%H-%M-%S)

    #get the swapfile name
#    swapSpace=$(swapon -s | tail -1 |  awk '{print $1}' | cut -d '/' -f 2)
    swapSpace=$(swapon -s | tail -1 |  awk '{print $1}')
    #debug: echo $swapSpace

    #turn off swapping
    swapoff $swapSpace

    #make backup of fstab
#    cp /etc/fstab /etc/fstab.$backupTime
    
    #remove swap space entry from fstab
    sed -i "/swap/d" /etc/fstab

    #remove swapfile
    rm -f "$swapSpace"

    echo ""
    echo "--> Done"
    echo ""
}

#spinner by: https://www.shellscript.sh/tips/spinner/
setupSwapSpinner() {
  spinner="/|\\-/|\\-"
  while :
  do
    for i in `seq 0 7`
    do
      echo -n "${spinner:$i:1}"
      echo -en "\010"
      sleep 1
    done
  done
}


#identifies available ram, calculate swap file size and configure
createSwap() {
    echo "Will create a swap and setup fstab."
    echo ""

    #get available physical ram
    availMemMb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
    #debug: echo "availMemMb=$availMemMb"

    #convert from kb to mb to gb
    availMemGb=$(awk "BEGIN {print $availMemMb/1024/1024}")
    #debug: echo $availMemGb

    #round the number to nearest gb
    availMemGb=$(echo $availMemGb | awk '{print ($0-int($0)<0.244)?int($0):int($0)+1}') #'
    #debug: echo $availMemGb

    if [[ ${manualSwapSize} ]]; then
	echo "-> Set manual SWAP file: ${manualSwapSize} Gb"
        echo ""
	# set swapSizeGb and change "," to "."
	swapSizeGb=${manualSwapSize//,/.}
    else
	echo "-> Available Physical RAM: $availMemGb Gb"
        echo ""
        if [ $availMemGb -eq 0 ]; then
            echo "Something went wrong! Memory cannot be 0!"
            exit 1
        elif [ $availMemGb -le 2 ]; then
            echo "   Memory is less than or equal to 2 Gb"
            let swapSizeGb=$availMemGb*2
            echo "   -> Set swap size to $swapSizeGb Gb"
        elif [ $availMemGb -gt 2 -a $availMemGb -lt 8 ]; then
            echo "   Memory is more than 2 Gb and less than to 8 Gb."
            let swapSizeGb=4+$availMemGb-2
            echo "   -> Set swap size to $swapSizeGb Gb."
        elif [ $availMemGb -gt 8 -a $availMemGb -lt 16 ]; then
            echo "   Memory is more than 8 Gb and less than to 16 Gb."
            let swapSizeGb=4+$availMemGb-2
            echo "   -> Set swap size to $swapSizeGb Gb."
        elif [ $availMemGb -gt 16 ]; then
            echo "   Memory is more than 16Gb or equal then to 0 Gb."
            echo "   -> Set swap size to 0 Gb."
            exit 1
	fi
    fi
    echo ""

    freeSpaceKb=$(df --output=avail ${path_swap_file%/*} | tail -1)
    freeSpaceMb=$(awk "BEGIN {print ${freeSpaceKb}/1024}")
    #round the number to nearest mb
    freeSpaceMb=$(echo "(${freeSpaceMb})/1" | bc) #"
    #convert from kb to mb to gb
    freeSpaceGb=$(awk "BEGIN {print ${freeSpaceKb}/1024/1024}")
    #round the number to nearest gb
    freeSpaceGb=$(echo "(${freeSpaceGb})/1" | bc) #"
    #debug: echo $availMemGb
    #debug: echo ${freeSpaceGb%.*}
    #debug: echo "freeSpaceMb=${freeSpaceMb}"
    #debug: echo "swapSizeGb=${swapSizeGb}"
    swapSizeMb="$(bc <<< ${swapSizeGb}*1024/1)"
    #debug: echo "swapSizeMb=${swapSizeMb}"

    if [ ${freeSpaceMb} -le ${swapSizeMb} ]; then
            echo "Something went wrong! Free space from ${path_swap_file%/*} cannot be less than or equal to ${freeSpaceMb} Mb !"
            let swapSizeMb=${freeSpaceMb}-64
            echo "   -> Set swap size to $swapSizeMb Mb."
            exit 1
    fi

    echo "Creating the swap file! This may take a few minutes."
    echo ""

    #implement swap file

    #start the spinner:
#    setupSwapSpinner &
    #make a note of its Process ID (PID):
#    SPIN_PID=$!
    #kill the spinner on any signal, including our own exit.
#    trap "kill -9 $SPIN_PID" `seq 0 15`

    #convert swapSizeGb to mb to avoid error: dd-memory-exhausted-by-input-buffer-of-size-bytes

    #create swap file on root system and set file size to mb variable
    echo "-> Create swap file."

    dd if=/dev/zero of=${path_swap_file} bs=1M count=${swapSizeMb}

    #set read and write permissions
    echo "-> Set swap file permissions."
    echo ""
    chmod 600 ${path_swap_file}

    #create swap area
    echo "-> Create swap area."
    echo ""
    mkswap ${path_swap_file}

    #enable swap file for use
    echo "-> Turn on swap."
    echo ""
    swapon ${path_swap_file}

    echo ""

    #update the fstab
    if grep -q "swap" /etc/fstab; then
        echo "-> The fstab contains a swap entry."
        #do nothing
    else
        echo "-> The fstab does not contain a swap entry. Adding an entry."
        echo "/${path_swap_file} swap swap defaults 0 0" >> /etc/fstab
    fi

    echo ""
    echo "--> Done"
    echo ""

    exit 1
}


##the_main_unction_thatis_run by the calling script.
setupSwapMain() {
    #check if swap is on

    isSwapOn=$(swapon -s | tail -1)
    if [[ "$isSwapOn" == "" ]]; then
        echo "No swap has been configured! Will create."
        echo ""
        createSwap
    else
        echo "Swap has been configured. Will remove and then re-create the swap."
	echo ""
        removeSwap
        createSwap
    fi
    echo "Setup swap complete! Check output to confirm everything is good."
}

    [[ $EUID -ne 0 ]] && echo "This script must be run as root! Login as root, sudo or su." && exit 1
    manualSwapSize="$1"
    setupSwapMain
