// numNewHostsForDistro determine how many new hosts should be spun up for an
// individual distro
func (self *DeficitBasedHostAllocator) numNewHostsForDistro(
	hostAllocatorData *HostAllocatorData, distro distro.Distro, settings *evergreen.Settings) int {

	cloudManager, err := providers.GetCloudManager(distro.Provider, settings)

	if err != nil {
		evergreen.Logger.Logf(slogger.ERROR, "Couldn't get cloud manager for distro %v with provider %v: %v",
			distro.Id, distro.Provider, err)
		return 0
	}

	can, err := cloudManager.CanSpawn()
	if err != nil {
		evergreen.Logger.Logf(slogger.ERROR, "Couldn't check if cloud provider %v is spawnable: %v",
			distro.Provider, err)
		return 0
	}
	if !can {
		return 0
	}

	existingDistroHosts := hostAllocatorData.existingDistroHosts[distro.Id]
	runnableDistroTasks := hostAllocatorData.
		taskQueueItems[distro.Id]

	freeHosts := make([]host.Host, 0, len(existingDistroHosts))
	for _, existingDistroHost := range existingDistroHosts {
		if existingDistroHost.RunningTask == "" {
			freeHosts = append(freeHosts, existingDistroHost)
		}
	}

	numNewHosts := util.Min(
		// the deficit of available hosts vs. tasks to be run
		len(runnableDistroTasks)-len(freeHosts),
		// the maximum number of new hosts we're allowed to spin up
		distro.PoolSize-len(existingDistroHosts),
	)

	// cap to zero as lower bound
	if numNewHosts < 0 {
		numNewHosts = 0
	}
	return numNewHosts
}
// numNewDistroHosts computes the number of new hosts needed as allowed by
// poolSize. if the duration based estimate (durNewHosts) is too large, e.g.
// when there's a small number of very long running tasks, utilize the deficit
// of available hosts vs. tasks to be run
func numNewDistroHosts(poolSize, numExistingHosts, numFreeHosts, durNewHosts,
	taskQueueLength int) (numNewHosts int) {

	numNewHosts = util.Min(
		// the maximum number of new hosts we're allowed to spin up
		poolSize-numExistingHosts,

		// the duration based estimate for the number of new hosts needed
		durNewHosts,

		// the deficit of available hosts vs. tasks to be run
		taskQueueLength-numFreeHosts,
	)

	// cap to zero as lower bound
	if numNewHosts < 0 {
		numNewHosts = 0
	}
	return
}