#!/bin/sh

. /lib/partman/definitions.sh
. /lib/partman/resize.sh

bestfree=0
bestpart=none
bestpath=none

# Count the number of primary and logical partitions.
count_primary_logical () {
    local primaries=0
    local logicals=0
    while { read num oldid size type fs path name; [ "$oldid" ]; }; do
	case $fs in
	    free)
		;;
	    *)
		case $type in
		    primary)
			primaries="$(($primaries + 1))"
			;;
		    logical)
			logicals="$(($logicals + 1))"
			;;
		esac
		;;
	esac
	echo "$primaries $logicals"
    done | tail -n1
}

# Filter a partition list to include only those entries which are already
# part of an extended partition or which can be resized to provide
# additional space in an extended partition.
can_be_extended () {
    local previous=
    while { read num oldid size type fs path name; [ "$oldid" ]; }; do
	case $type in
	    logical|pri/log)
		if [ "$previous" ]; then
		    # If the previous partition can be resized, that will
		    # create additional space at the end adjacent to this
		    # partition.
		    echo "$previous"
		    previous=
		fi
		echo "$num $oldid $size $type $fs $path $name"
		;;
	    *)
		previous="$num $oldid $size $type $fs $path $name"
		;;
	esac
    done
}

scan_disk () {
    open_dialog PARTITIONS
    partitions="$(read_paragraph)"
    close_dialog

    open_dialog USES_EXTENDED
    read_line uses_extended
    close_dialog

    # TODO: This should all be checked later to take account of recipes
    # other than the defaults for the supported Ubuntu architectures.
    # TODO: We hardcode a maximum primary partition count of 4; a command
    # should be added to parted_server to extract this.
    if [ "$uses_extended" = yes ]; then
	primary_logical="$(echo "$partitions" | count_primary_logical)"
	if [ "$primary_logical" ]; then
	    primaries="${primary_logical% *}"
	    logicals="${primary_logical#* }"
	    log "$primaries primary partitions, $logicals logical partitions"

	    # If we already have four primary partitions (counting extended
	    # partitions), then we won't have room to create the extra one
	    # demanded by the standard recipes.
	    if [ "$primaries" -ge 4 ]; then
		echo '0 0 none none'
		return
	    fi

	    # If there are no logical partitions, then we will need an extra
	    # primary partition slot to create an extended partition.
	    if [ "$logicals" -eq 0 ] && [ "$primaries" -ge 3 ]; then
		echo '0 0 none none'
		return
	    fi

	    # If there is already an extended partition, then only consider
	    # those partitions in which (after resizing) partitions can be
	    # created sufficiently freely.
	    if [ "$logicals" -ne 0 ]; then
		partitions="$(echo "$partitions" | can_be_extended)"
		log "filtered partition list:"
		log "$partitions"
	    fi
	fi
    fi

    totalfree=0
    bestfree=0
    bestpart=none
    bestpath=none
    echo "$partitions" | while { read num oldid size type fs path name; [ "$oldid" ]; }; do
	case $fs in
	    free)
		totalfree="$(expr "$totalfree" + "$size")"
		;;

	    linux-swap|ext2|ext3|fat32)
		get_resize_range
		if [ "$cursize" ] && [ "$minsize" ]; then
		    thisfree="$(expr "$cursize" - "$minsize")"
		    if longint_le $bestfree $thisfree; then
			bestfree=$thisfree
			bestpart=$dev//$oldid
			bestpath=$path
		    fi
		fi
		;;

	    ntfs)
		if ! type ntfsresize >/dev/null 2>&1; then
		    continue
		fi
		check_virtual
		if [ "$virtual" = yes ]; then
		    get_resize_range
		else
		    get_ntfs_resize_range
		fi
		if [ "$cursize" ] && [ "$minsize" ]; then
		    thisfree="$(expr "$cursize" - "$minsize")"
		    if longint_le $bestfree $thisfree; then
			bestfree=$thisfree
			bestpart=$dev//$oldid
			bestpath=$path
		    fi
		fi
		;;
	esac
	echo "$totalfree $bestfree $bestpart $bestpath"
    done | tail -n1
}

get_resize_use_free_on_dev() {
    cd $dev

    scanned="$(scan_disk)"
    log "dev: '$dev', scanned: '$scanned'"
    totalfree="${scanned%% *}"
    cdr="${scanned#* }"
    thisfree="${cdr%% *}"
    if longint_le "$bestfree" "$thisfree"; then
	bestfree="$thisfree"
	cdr="${cdr#* }"
	bestpart="${cdr%% *}"
	bestpath="${cdr#* }"
    fi

    if longint_le "$(expr \( 2 \* 1024 + 200 \) \* 1024 \* 1024)" $totalfree; then
	# enough space, no need to resize
	exit 0
    fi
}

dev="$1"

if [ -z "$dev" ]; then
    for dev in $DEVICES/*; do
	[ -d $dev ] || continue
	get_resize_use_free_on_dev
    done
else
    get_resize_use_free_on_dev
fi

if [ "$bestpart" ] && [ "$bestpart" != none ] && \
    longint_le "$(expr 3 \* 1024 \* 1024 \* 1024)" $bestfree; then
    log "Found resizable partition '$bestpart' ($bestpath) with $bestfree bytes free"
    db_subst partman-auto/text/resize_use_free PARTITION "$(humandev "$bestpath")"
    db_metaget partman-auto/text/resize_use_free description
    printf "%s\t%s" "$bestpart" "$RET"
fi
