#!/bin/sh

AUTOMODE=
PLYMOUTH=
REBOOT_ON_FAILURE=

while getopts ":a" opt; do
  case $opt in
    a)
    AUTOMODE=1
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      ;;
  esac
done

if [ -z "$AUTOMODE" ]; then
    PLYMOUTH=0
    REBOOT_ON_FAILURE=0
else
    PLYMOUTH=1
    REBOOT_ON_FAILURE=1
fi

function message {
    if [ -n "$PLYMOUTH" -a "$PLYMOUTH" -eq 1 ]; then
        plymouth display-message  --text "$1"
    else
        echo $1
    fi
}

function check_echo_reboot {
       read key
       if [[ $key != 'r' && $key != 'R' ]]; then
               check_echo_reboot
       fi
}

function read_config {
    local CONF_FILE=""
    CONF_FILE="/etc/installer.conf"

    if [ ! -e $CONF_FILE ]; then
        message "Installation failure, missing /etc/installer.conf"
        test $REBOOT_ON_FAILURE -eq 1 &&  (
            sleep 5
            /usr/sbin/reboot
        )
        exit 1
    else
        . $CONF_FILE
    fi
}

function set_mounts {
    SRCMNT=$(mktemp -d /media/srctmp.XXXXXX)
    TGTMNT=$(mktemp -d /media/tgttmp.XXXXXX)
    SRCOSMNT=$(mktemp -d /media/srcostmp.XXXXXX)
}

function find_devices {
    for i in $(ls /sys/block/*/device/model); do
        dev=$(echo $i | cut -d'/' -f-4) ;
        device=$(echo $i | cut -d'/' -f4)
        grep -q 1 $dev/removable
        if [ "$?" = "1" ]; then
            TARGET_DEV="/dev/$device";
            break
        fi
    done

    if [ -z "$TARGET_DEV" ]; then
        message "Installation failure, unable to find suitable install target media"
        test $REBOOT_ON_FAILURE -eq 1 &&  (
            sleep 5
            /usr/sbin/reboot
        )
        exit 1
    fi
}

# Global variable for storing the partition option parameters;
params=

function msdos_partition_options {
    # the partition number
    local i=$1
    # used for storing the per-part variables,
    # accessed via indirect referencing
    local tmp=""

    tmp="INSTALLERFW_PART${i}_SIZE"
    local size=${!tmp}
    [ -z "$size" ] && size="1024"
    if [[ "$INSTALLERFW_PART_COUNT" = "$((i+1))" ]]; then
        # an 'empty' value means that sfdisk will use
        # the defaults, in this case expanding to the
        # end of the disk
        size=""
    fi
    params=$(printf "${params}\n%s" ",${size}")

    tmp="INSTALLERFW_PART${i}_FSTYPE"
    local fstype=${!tmp}
    local typeid='83'
    [ "$fstype" = "swap" ] && typeid='82'
    params=$(printf "${params}%s" ",${typeid}")

    # handle bootflag last
    tmp="INSTALLERFW_PART${i}_BOOTFLAG"
    local bootflag=${!tmp}
    if [ "$bootflag" = "True" ]; then
        params=$(printf "${params}%s" ',*')
    else
        params=$(printf "${params}\n")
    fi
}

function gpt_partition_options {
    # the partition number
    local i=$1
    # used for storing the per-part variables,
    # accessed via indirect referencing
    local tmp=""

    tmp="INSTALLERFW_PART${i}_ALIGN"
    local align=${!tmp}
    [ -n "$align" ] && params=$(printf "${params}%s" " --set-alignment=${align}")

    # sgdisk uses '0' to mean 'default value'
    params=$(printf "$params%s" " --new=0:0")

    tmp="INSTALLERFW_PART${i}_SIZE"
    local size=${!tmp}
    if [[ "$INSTALLERFW_PART_COUNT" = "$((i+1))" ]]; then
        size="0"
    fi
    [ -z "$size" ] && size="1024"
    [ -n "$size" ] && params=$(printf "${params}%s" ":${size}M")

    # TODO: need to handle swap partition types if encountered

    # the following GUID option does not accept default partition values,
    # so partition numbering must start at index 1, not 0
    local partnum="$((i+1))"

    tmp="INSTALLERFW_PART${i}_TYPE_ID"
    local typeid=${!tmp}
    [ -n "$typeid" ] && params=$(printf "${params}%s" " --typecode=${partnum}:${typeid}")
}

function partition_msdos {
    # make sure there is a newline in the heredoc,
    # or else sfdisk fails to parse the input
    /usr/sbin/sfdisk --in-order -uM ${TARGET_DEV} << EOF
${1}

EOF
    sync
}

function partition_gpt {
    /usr/sbin/sgdisk -Z ${TARGET_DEV}
    /usr/sbin/sgdisk ${1} ${TARGET_DEV}
    sync
}

function format_device {
    local fstype=$1
    local instfw_pnum=$2
    # the actual partition numbers begin at index 1, not 0
    local partnum="$((instfw_pnum+1))"

    # TODO: need to handle swap partitions

    /usr/sbin/mkfs.${fstype} ${TARGET_DEV}${partnum}

    if [[ ${fstype} = "btrfs" ]]; then
        mount ${TARGET_DEV}${partnum} $TGTMNT
        /usr/sbin/btrfs subvolume create ${TGTMNT}/tizen
        /usr/sbin/btrfs subvolume create ${TGTMNT}/tizen/.snapshots
        SUBVOLID=$(/usr/sbin/btrfs subvolume list $TGTMNT | grep 'tizen$' | awk '{ print $2 }')
        echo "Setting subvolume ${SUBVOLID} as default"
        /usr/sbin/btrfs subvolume set-default $SUBVOLID $TGTMNT
        sync
        umount $TGTMNT
    fi
}

function mount_device {
    local mountpoint=$1
    local instfw_pnum=$2
    # the actual partition numbers begin at index 1, not 0
    local partnum="$((instfw_pnum+1))"

    SRCOSMNT="/"

    # we make this substitution in extlinux.conf on the target device
    [ "$mountpoint" = "/" ] && ROOTFS="${TARGET_DEV}${partnum}"

    mkdir -p ${TGTMNT}/${mountpoint}

    # for this to work, the rootfs partition entry in installer.conf
    # must be first entry, or else some mount points will be hidden
    # during the rsync
    mount ${TARGET_DEV}${partnum} ${TGTMNT}/${mountpoint}
}

function install_extlinux {
    mkdir -p ${TGTMNT}/boot/extlinux
    cat > ${TGTMNT}/boot/extlinux/extlinux.conf << EOF
default vesamenu.c32
timeout 10

menu background splash.png
menu title Welcome to Tizen PC!
menu color border 0 #ffffffff #00000000
menu color sel 7 #ff000000 #ffffffff
menu color title 0 #ffffffff #00000000
menu color tabmsg 0 #ffffffff #00000000
menu color unsel 0 #ffffffff #00000000
menu color hotsel 0 #ff000000 #ffffffff
menu color hotkey 7 #ffffffff #ff000000
menu color timeout_msg 0 #ffffffff #00000000
menu color timeout 0 #ffffffff #00000000
menu color cmdline 0 #ffffffff #00000000
menu hidden
menu clear
label tizen
  menu label Boot Tizen
  kernel ../vmlinuz
  append root=${ROOTFS} ${INSTALLERFW_KERNEL_OPTS} ${ROOTFLAGS}
menu default
EOF

    cp /usr/share/branding/default/syslinux/syslinux-vesa-splash.jpg ${TGTMNT}/boot/extlinux/splash.png

    cat /usr/share/syslinux/mbr.bin > ${TARGET_DEV}
    /sbin/extlinux -i  ${TGTMNT}/boot/extlinux
}

function fixup_fstab {
    local pnum=0
    local devpnum="$((pnum+1))"
    local tmp=""
    local srcuuid=""
    local tgtuuid=""

    while [ "$pnum" -lt "$INSTALLERFW_PART_COUNT" ]; do
        tmp="INSTALLERFW_PART${pnum}_UUID"
        srcuuid=${!tmp}

        tgtuuid=$(blkid ${TARGET_DEV}${devpnum} | sed 's/.* UUID="\([^"]*\)".*/\1/')
        sed -i "s/.*\(UUID=\).*${srcuuid}\(.*\)/\1${tgtuuid}\2/" ${TGTMNT}/etc/fstab

        pnum="$((pnum+1))"
        devpnum="$((devpnum+1))"
    done
}

function fixup_gummiboot {
    # expect the rootfs to be the last entry in installer.conf
    local pnum="$((INSTALLERFW_PART_COUNT-1))"
    local devpnum="$((pnum+1))"
    local tmp=""
    local mntpoint=""
    local srcpuuid=""
    local tgtpuuid=""
    local confs="$(ls -1 "${TGTMNT}/boot/loader/entries/")"

    tmp="INSTALLERFW_PART${pnum}_PARTUUID"
    srcpuuid=${!tmp}

    tgtpuuid=$(blkid ${TARGET_DEV}${devpnum} | sed 's/.* PARTUUID="\([^"]*\)".*/\1/')

    printf "%s\n" "$confs" | while IFS= read -r conf; do
        sed -i "s/\(.*PARTUUID=\).*${srcpuuid}\(.*\)/\1${tgtpuuid}\2/" "${TGTMNT}/boot/loader/entries/${conf}"
    done
}

function install_os {
    rsync  -WaHXSh --exclude='/dev/' --exclude='/lost+found/' --exclude='/media/*' --exclude='/sys/' --exclude='/proc/' --exclude="/tmp/" --exclude="/run/"  $SRCOSMNT/ $TGTMNT

    mkdir ${TGTMNT}/dev/
    chmod 0755 ${TGTMNT}/dev

    # TODO: switch to using systemd mount units instead of the fstab
    #rm ${TGTMNT}/etc/fstab

    fixup_fstab

    if [ "$INSTALLERFW_PTABLE_FORMAT" = "gpt" ]; then
	fixup_gummiboot
    fi

    if [[ $FILESYSTEM = "btrfs" ]]; then
        ROOTFLAGS="rootflags=subvol=tizen"
    else
        ROOTFLAGS=""
    fi

    if [ "$INSTALLERFW_PTABLE_FORMAT" = "msdos" ]; then
        install_extlinux
    fi

    if [[ $FILESYSTEM = "btrfs" ]]; then
        sed -i 's|SUBVOLUME="/"|SUBVOLUME="'${TGTMNT}'"|' /etc/snapper/configs/root
        snapper create -d "Factory Default"
    fi
}

function unmount_devices {
    sync
    sleep 2
    [ -d "$TGTMNT" ] && umount -R $TGTMNT
}

message "This installation will wipe all data from the hard drive, hit Y key to continue or ctrl-alt-del to abort."
if [ -n "$PLYMOUTH" -a "$PLYMOUTH" -eq 1 ]; then
    plymouth watch-keystroke --command="/usr/bin/test" --keys "yY"
else
    read key
    if [[ $key != 'y' && $key != 'Y' ]]; then
        test $REBOOT_ON_FAILURE -eq 1 && /usr/sbin/reboot
    fi
fi
if [ -n "$PLYMOUTH" -a "$PLYMOUTH" -eq 1 ]; then
    plymouth hide-message  --text "This installation will wipe all data from the hard drive, hit Y key to continue or ctrl-alt-del to abort."
fi

read_config
set_mounts
find_devices
message "Installing on to the hard disk now, this will take a few minutes..."

pnum=0
# first, generate the option list to pass to either 'sfdisk' or 'sgdisk'
while [ "$pnum" -lt "$INSTALLERFW_PART_COUNT" ]; do
    if [ "$INSTALLERFW_PTABLE_FORMAT" = "msdos" ]; then
        msdos_partition_options $pnum
    elif [ "$INSTALLERFW_PTABLE_FORMAT" = "gpt" ]; then
        gpt_partition_options $pnum
    fi
    pnum="$((pnum+1))"
done

# now, do the partitioning
if [ "$INSTALLERFW_PTABLE_FORMAT" = "msdos" ]; then
    partition_msdos "$params"
elif [ "$INSTALLERFW_PTABLE_FORMAT" = "gpt" ]; then
    partition_gpt "$params"
fi

pnum="$((INSTALLERFW_PART_COUNT-1))"
# NOTE: for now, partitions are processed in reverse order, and we
# expect the rootfs to be the last entry in installer.conf
while [ "$pnum" -ge "0" ]; do
    tmp="INSTALLERFW_PART${pnum}_FSTYPE"
    fstype=${!tmp}

    format_device $fstype $pnum

    tmp="INSTALLERFW_PART${pnum}_MOUNTPOINT"
    mountpoint=${!tmp}

    mount_device $mountpoint $pnum

    pnum="$((pnum-1))"
done

unset fstype
unset mountpoint

install_os
unmount_devices

if [ -n "$PLYMOUTH"  -a "$PLYMOUTH" -eq 1 ]; then
    plymouth hide-message  --text "Installing on to the hard disk now, this will take a few minutes..."
fi
message "Hit R key to reboot and then remove the usb stick. Enjoy!"

if [ -n "$PLYMOUTH" -a "$PLYMOUTH" -eq 1 ]; then
    plymouth watch-keystroke --command="/usr/bin/test" --keys "rR"
else
    check_echo_reboot
fi
/usr/sbin/reboot
