#pragma once

#include "debuglog.h"
#include "perf_window.h"

struct admissions_info {
	struct perf_window perf_window;
	int                percentile;        /* 50 - 99 */
	int                control_index;     /* Precomputed Lookup index when perf_window is full */
	uint64_t           estimate;          /* cycles */
	uint64_t           relative_deadline; /* Relative deadline in cycles. This is duplicated state */
};

/**
 * Initializes perf window
 * @param self
 */
static inline void
admissions_info_initialize(struct admissions_info *self, int percentile, uint64_t expected_execution,
                           uint64_t relative_deadline)
{
#ifdef ADMISSIONS_CONTROL

	self->relative_deadline = relative_deadline;
	self->estimate          = admissions_control_calculate_estimate(expected_execution, relative_deadline);
	debuglog("Initial Estimate: %lu\n", self->estimate);
	assert(self != NULL);

	perf_window_initialize(&self->perf_window);

	if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid admissions percentile");
	self->percentile = percentile;

	self->control_index = PERF_WINDOW_BUFFER_SIZE * percentile / 100;
#endif
}

/*
 * Adds an execution value to the perf window and calculates and caches and updated estimate
 * @param self
 * @param execution_duration
 */
static inline void
admissions_info_update(struct admissions_info *self, uint64_t execution_duration)
{
#ifdef ADMISSIONS_CONTROL
	assert(!software_interrupt_is_enabled());
	struct perf_window *perf_window = &self->perf_window;

	LOCK_LOCK(&self->perf_window.lock);
	perf_window_add(perf_window, execution_duration);
	uint64_t estimated_execution = perf_window_get_percentile(perf_window, self->percentile, self->control_index);
	self->estimate = admissions_control_calculate_estimate(estimated_execution, self->relative_deadline);
	LOCK_UNLOCK(&self->perf_window.lock);
#endif
}
