#!/usr/bin/env bash

export DISK_SDA_SCHEME="msdos"
declare -a DISK_SDA_PARTITIONS=()
DISK_SDA_PARTITIONS+=("1GB:fat32:/boot:defaults:0:0:False")
DISK_SDA_PARTITIONS+=("12.5GB:ext4:/:defaults:0:0:True")
export DISK_SDA_PARTITIONS
export DISK_SDB_SCHEME="mbr"
declare -a DISK_SDB_PARTITIONS=()
DISK_SDB_PARTITIONS+=("12G:swap::defaults:0:0:true")
export DISK_SDB_PARTITIONS

declare -a DISK_DEVICES=("sda")
export DISK_DEVICES

# convertSizeToByte - converts a given size to byte
# parameter:
#  $1 - size in "kB", "MB", "MiB", "GB", "GiB", "TB" or "TiB"
# return:
#  size in byte
convertSizeToByte() {
  local unit=$(echo $1 | sed "s/[1-9\.]*//g")
  local value=$(echo $1 | sed "s/[a-zA-Z%]*//g")
  local factor=1
 
  case ${unit} in
   "B") factor=1;;
   "kB") factor=1000 ;;
   "MB") factor=1000000 ;;
   "GB") factor=1000000000 ;;
   "TB") factor=1000000000000 ;;
   "kiB") factor=1024 ;;
   "MiB") factor=1048576 ;;
   "GiB") factor=1073741824 ;;
   "TiB") factor=1099511627776 ;;
   *) factor=1 ;;
  esac

  res=$(dc -e "0k ${value} ${factor} * p")
  
  echo "${res%.*}"
}

# convertByteToSize - converts a byte size to a given unit 
# parameter:
#  $1 - size in byte
#  $2 - unit like "kB", "MB", "MiB", "GB", "GiB", "TB" or "TiB"
# return:
#  rounded size with unit
convertByteToSize() {
  local factor=1

  case $2 in
   "B") factor=1;;
   "kB") factor=1000 ;;
   "MB") factor=1000000 ;;
   "GB") factor=1000000000 ;;
   "TB") factor=1000000000000 ;;
   "kiB") factor=1024 ;;
   "MiB") factor=1048576 ;;
   "GiB") factor=1073741824 ;;
   "TiB") factor=1099511627776 ;;
   *) factor=1 ;;
  esac

  res=$(dc -e "2k $1 ${factor} / p")
  echo "${res%.*}$2"
}

# validateDiskScheme - checks the scheme of a disk device
# parameter:
#  $1 - disk device name
# retur:
#  0 - no changes
#  1 - label has changed
validateScheme() {
 local lbl=$(echo $diskdata[0] | cut -f 6 -d ":")
 local retval=1
 local scheme=$(eval echo \$DISK_$(echo $1 | tr [a-z] [A-Z])_SCHEME)
 
 if [ "x${scheme}" = "x${lbl}" ];
 then
   retval=0
 fi

 return ${retval}
}

# initialDiskScheme - initials the scheme of a disk device
# parameter:
#  $1 - disk device name
# return:
#  none
initialDiskScheme() {
  local scheme=$(eval echo \$DISK_$(echo $1 | tr [a-z] [A-Z])_SCHEME)

  if [ ${scheme} = "mbr" ];
  then
    parted -s -m /dev/$1 mklabel msdos
  else
    parted -s -m /dev/$1 mklabel ${scheme}
  fi

  return
}

# validateDiskPartitions - checks the partitions of a disk device
# parameter:
#  $1 - disk device name
# return:
#  0 - no changes
#  1 - partions has changed
validateDiskPartitions() {
 declare -a parts=()
 local retval=0

 for part in $(eval "for p in \${DISK_$(echo $1 | tr [a-z] [A-Z])_PARTITIONS[@]}; do echo \$p; done ")
 do
   parts+=(${part})
 done

 if [ ${#parts[@]} -eq $((${#diskdata[@]} - 1)) ];
 then
   for idx in $(seq 1 1 ${#parts[@]})
   do
     gsize=$(convertSizeToByte $(echo ${parts[$((${idx} - 1))]} | cut -f 1 -d ":"))
     dsize=$(convertSizeToByte $(echo ${diskdata[${idx}]} | cut -f 4 -d ":"))
     diffperc=$(dc -e "2k $dsize $gsize - 100 * $gsize / p" | sed -e "s/^-//g")

     if [ -n "x${diffperc%.*}" ];
     then
       diffperc=0
     fi

     #if difference between current disk size and given disk size more than 1% then partitions has changed
     if [ ${diffperc%.*} -gt 1 ];
     then
       retval=1
     fi
   done
 else
   retval=1
 fi

 return ${retval}
}

# initialDiskPartitions - initial the partitions of a disk device
# parameter:
#  $1 - disk device name
# return:
#  none 
initialDiskPartitions() {
 declare -a parts=()
 local start=$(convertSizeToByte "1MiB")
 local fs=""
 local size=""
 local end=""

 for part in $(eval "for p in \${DISK_$(echo $1 | tr [a-z] [A-Z])_PARTITIONS[@]}; do echo \$p; done ")
 do
   fs=$(echo ${part} | cut -f 2 -d ":")
   fsize=$(echo ${part} | cut -f 1 -d ":")
   size=$(convertSizeToByte $(echo ${part} | cut -f 1 -d ":"))
   end=$((${start} + ${size}))
   parted -a optimal -s -m /dev/$1 mkpart primary ${fs} $(convertByteToSize ${start} "MiB") $(convertByteToSize ${end} "MiB")
   start=${end}
 done
}

for disk in ${DISK_DEVICES[@]}
do
  declare -a diskdata=()

  for ddt in $(parted -s -m /dev/${disk} print 2>/dev/null | sed '1d;s/[ ]*//g')
  do
    diskdata+=(${ddt})
  done

  validateScheme ${disk}
  
  if [ $? -eq 0 ];
  then
    validateDiskPartitions ${disk}

    if [ $? -ne 0 ];
    then
      initialDiskPartitions ${disk}
    fi
  else
    initialDiskScheme ${disk}
    initialDiskPartitions ${disk}
  fi  
done