#include <atari.h>
#include "screen.h"
// #include "pool.h"
// #include "addrs.h"
#include "memclear.h"

screen_t screens[MAX_SCREENS];
pool_t pools[MAX_POOLS];

void init_pools(void) {
	char p;

	pools[0].screen_count = 0;
	pools[0].free_list = (line_t *)END_MARKER;

	for(p = 1; p < MAX_POOLS; p++)
		pools[p].screen_count = POOL_UNUSED;

	add_to_pool(0, SCR_MAIN_MEM, SCR_MAIN_END);

	if((u16)OS.memlo < SCR_LOW_END - sizeof(pool_t))
		add_to_pool(0, (u16)OS.memlo, SCR_LOW_END);

	/* TODO: for pool 0, add whatever RAM exists between the end
	   of the BSS and $3600. also, under-OS XL RAM if enabled. */

	/* TODO: support pools 1 and up for other banks! */
}

void add_to_pool(char p, u16 start, u16 end) {
	line_t *l;

	end -= sizeof(line_t);

	l = (line_t *)start;

	while(l <= (line_t *)end) {
		memclear(l, sizeof(line_t));
		l->next = pools[p].free_list;
		pools[p].free_list = l;
		l++;
	}
}

char get_smallest_pool(void) {
	char p, r;
	u16 min;

	min = 0xffff;
	r = 0;

	for(p = 0; p < MAX_POOLS; p++) {
		if(pools[p].screen_count = POOL_UNUSED)
			continue; /* maybe break here instead */
		if(pools[p].screen_count < min) {
			min = pools[p].screen_count;
			r = p;
		}
	}
	return r;
}

line_t *steal_line(char s) {
	line_t *l, *last_l;
	char candidate, victim;
	u16 maxheight;

	victim = s;
	maxheight = 0;

	for(candidate = 0; candidate < MAX_SCREENS; candidate++) {
		/* only steal from the same pool */
		if(screens[candidate].pool != screens[s].pool)
			continue;
		/* only steal from screens that exist */
		if(screens[candidate].status == SCR_UNUSED)
			continue;
		/* steal from the screen with the most lines */
		if(screens[candidate].line_count > maxheight) {
			maxheight = screens[candidate].line_count;
			victim = candidate;
		}
	}

	/* find 2nd to last line of the victim screen */
	l = screens[victim].line_list;
	while(l->next != (line_t *)END_MARKER) {
		last_l = l;
		l = l->next;
	}
	/* at the end of the loop, l is the last line before the
	   end marker (the line we're stealing), and last_l is the line
	   before that. */

	/* make old_l the last line */
	last_l->next = (line_t *)END_MARKER;

	/* clear out old screen data, then return the stolen line */
	memclear(l->data, LINE_LEN);

	return l;
}

line_t *find_line(char s) {
	line_t *p;

	p = pools[screens[s].pool].free_list;
	if(p != (line_t *)END_MARKER) {
		pools[screens[s].pool].free_list = p->next;
		return p;
	}

	/* free_list was null, pool is full */
	return steal_line(s);
}

void add_line(char s) {
	line_t *p;

	p = find_line(s);
	p->next = screens[s].line_list;
	screens[s].line_list = p;
	screens[s].line_count++;
}
