#! /bin/sh

## prticulator-- partition calculator to approximate partman-auto results.
## =====================================================================
## This is an implementation in awk of the algorithm described in 'partman-auto-recipe.txt'.
## The expected input is a partman-auto recipe as defined in 'partman-auto-recipe.txt', at:
## https://salsa.debian.org/installer-team/debian-installer/blob/master/doc/devel/partman-auto-recipe.txt
## Note that it is naive and somewhat overoptimistic as it has no clue of disk layout and
## filesystem overheads.
## ---------------------------------------------------------------------------------------------
## USAGE: 'particulator [free_space=Free_Space_in_MB] [RAM=System_RAM_in_MB] recipe_file'
## ======================================================================
## Written by Oded Naveh, Mar. 2009.

awk --re-interval '

function getram(    lram) {
	RS = "\n"; ORS = "\n"
	print ""
	print " *** One or more limits defined relative to RAM! ***" > "/dev/stderr"
	print " please enter amount of RAM in MB then press return," > "/dev/stderr"
	print " or specify RAM=System_RAM_in_MB on the commandline." > "/dev/stderr"
	printf "\nRAM = " > "/dev/stderr"
	getline lram < "/dev/stdin"
	RS = ""; ORS = "\n\n"
	if (lram > 0 && lram !~ /[^0-9]/) return lram
	print "As you wish, bye." > "/dev/stderr"
	ram = "NON"
	exit 1
}

function getfreespace(    freesp) {
	RS = "\n"; ORS = "\n"
	print ""
	print " ******      Free-space to partition is unknown      ******" > "/dev/stderr"
	print " please enter amount of free-space in MB then press return," > "/dev/stderr"
	print " or specify free_space=Free_Space_in_MB on the commandline." > "/dev/stderr"
	printf "\nfree_space = " > "/dev/stderr"
	getline freesp < "/dev/stdin"
	RS = ""; ORS = "\n\n"
	if (freesp > 0 && freesp !~ /[^0-9]/) return freesp
	print "As you wish, bye." > "/dev/stderr"
	exit 2
}

BEGIN {
	RS = ""; ORS = "\n\n"
}

/^(-?[0-9]+%? ){3}/ {					# requires --re_interval command line option for gawk
	for (f = 1; f <= 3; f++) {
		if ($f ~ "%") {
			if (ram == 0) ram = getram()
			sub("%", "", $f)
			$f *= ram/100
		}
		if ($f ~ "-") {
			$f = 1000000000
		}
	}
	if ($0 ~ "method\\\{ swap \\\}") {
		swi++
		mountp = "swap_"swi
	}
	else mountp = $(NF-2)
	desc[++i] = mountp
	min[i] = $1
	prio[i] = $2
	fact[i] =$2 - $1
	max[i] = $3
}

END {
	if (ram == "NON") exit
	if (free_space == 0) free_space = getfreespace()
	RS = "\n"; ORS = "\n"
	print "\n You asked to simulate the partitioning of "free_space"MB by the following recipe:"
	for (j = 1; j <= i; j++) {
		minsum += min[j]
		factsum += fact[j]
		printf("%2d) min=%-7G priority=%-7G max=%-7G for: %s\n", j, min[j], prio[j], max[j], desc[j])
	}
	if (free_space < minsum) {
		print "\n Not enough free-space for the requested recipe."
		print " You need at least "minsum"MB of free-space to install.\n"
		exit 3
	}
	finished = 0
	while (finished != 1) {
		minsum = 0
		for (j = 1; j <= i; j++) {
			minsum += min[j]
		}
		finished = 1
		for(j = 1; j <= i; j++) {
			x = (min[j] + ((free_space - minsum) * fact[j] / factsum))
			if (x > max[j]) x = max[j]
			if (x != min[j]) {
				finished = 0
				min[j] = x
			}
		}
	++count
	}
	print "\n The calculation required "count" iterations and produced these results:"
	for (j = 1; j <= i; j++) {
		printf("%2d) %7.0f MB in %s\n", j, min[j], desc[j])
	}
}
' $*

# for(i=1;i<=N;i++) {
#    factor[i] = priority[i] - min[i];
# }
# finished = FALSE;
# while (! finished) {
#    minsum = min[1] + min[2] + ... + min[N];
#    factsum = factor[1] + factor[2] + ... + factor[N];
#    finished = TRUE;
#    for(i=1;i<=N;i++) {
#       x = min[i] + (free_space - minsum) * factor[i] / factsum;
#       if (x > max[i])
#          x = max[i];
#       if (x != min[i]) {
#          finished = FALSE;
#          min[i] = x;
#       }
#    }
# }

