#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "sheep2.h"



static void free2(unsigned char **d, int h)
{
	if (d) {
		int y;
		for (y = 0; y < h; y++) if (d[y]) free(d[y]);
		free(d);
	}
}



static unsigned char **malloc2(int w, int h)
{
	unsigned char **d = malloc(h*sizeof(*d));
	int y;
	if (!d) return NULL;
	for (y = 0; y < h; y++) {
		d[y] = malloc(w);
		if (!d[y]) { free2(d, y); return NULL; }
	}
	return d;
}



static int read_array(FILE *f, unsigned char **d, int w, int h)
{
	int x, y;
	char c;

	for (y = 0; y < h; y++) {
		fscanf(f, " ");
		for (x = 0; x < w; x++) {
			if (fscanf(f, "%c", &c) < 1) return 1;
			if (isdigit(c))
				d[y][x] = c - '0';
			else
				d[y][x] = c - 'A' + 10;
		}
	}

	return 0;
}



LEVELSET *load_levelset(const char *filename)
{
	LEVELSET *set;
	int i;
	FILE *f = fopen(filename, "r");
	if (!f) return NULL;

	set = malloc(sizeof(*set));
	if (!set) goto errornoset;
	set->level = NULL;

	if (fscanf(f, "%40[^\r\n]%*[^\r\n]", set->name) < 1) goto error;
	if (fscanf(f, " Levels%d", &set->n_levels) < 1) goto error;

	set->level = malloc(set->n_levels*sizeof(*set->level));
	if (!set->level) goto error;

	for (i = 0; i < set->n_levels; i++) {
		set->level[i].n_indestructible = NULL;
		set->level[i].n_full = NULL;
		set->level[i].topping = NULL;
		set->level[i].hole = NULL;
		set->level[i].blower = NULL;
	}

	for (i = 0; i < set->n_levels; i++) {
		LEVEL *level = &set->level[i];
		int x, y;

		if (fscanf(f, " Size (%d ,%d )", &x, &y) < 2) goto error;
		level->w = x; level->h = y;

		if (!(level->n_indestructible = malloc2(level->w, level->h))) goto error;
		if (!(level->n_full = malloc2(level->w, level->h))) goto error;
		if (!(level->topping = malloc2(level->w, level->h))) goto error;
		if (!(level->hole = malloc2(level->w, level->h))) goto error;

		if (read_array(f, level->n_indestructible, level->w, level->h)) goto error;
		if (read_array(f, level->n_full, level->w, level->h)) goto error;
		if (read_array(f, level->topping, level->w, level->h)) goto error;
		if (read_array(f, level->hole, level->w, level->h)) goto error;

		for (y = 0; y < level->h; y++)
			for (x = 0; x < level->w; x++)
				if (BLOCK_INVALID(level->topping[y][x]) || level->topping[y][x] == BLOCK_INDESTRUCTIBLE) goto error;

		if (fscanf(f, " Blowers%d", &level->n_blowers) < 1 || level->n_blowers <= 0) goto error;
		level->blower = malloc(level->n_blowers*sizeof(*level->blower));
		if (!level->blower) goto error;
		for (y = 0; y < level->n_blowers; y++) {
			if (fscanf(f, " (%d", &x) < 1 || x < 0 || x >= level->w) goto error;
			level->blower[y].x = x;
			if (fscanf(f, " ,%d", &x) < 1 || x < 0 || x >= level->h) goto error;
			level->blower[y].y = x;
			if (fscanf(f, " ,%d", &x) < 1) goto error;
			level->blower[y].z = x;
			if (fscanf(f, " )%d", &x) < 1 || x < 0 || x >= 4) goto error;
			level->blower[y].d = x;
		}

		if (fscanf(f, " Sheep%d Sheep Needed%d Initial Sheep Delay%d Sheep Interval%d",
			&level->n_sheep, &level->sheep_needed,
			&level->initial_sheep_delay, &level->sheep_interval) < 4 ||
			level->n_sheep <= 0 ||
			level->sheep_needed < 0 ||
			level->sheep_needed > level->n_sheep ||
			level->initial_sheep_delay <= MIN_SHEEP_INTERVAL ||
			level->sheep_interval <= MIN_SHEEP_INTERVAL) goto error;
		if (fscanf(f, " Player (%d ,%d", &x, &y) < 2 || x < 0 || x >= level->w || y < 0 || y >= level->h) goto error;
		level->px = x; level->py = y;
		if (fscanf(f, " )%d", &x) < 1 || x < 0 || x >= 4) goto error;
		level->pd = x;
	}

	fclose(f);
	return set;

	error:
	unload_levelset(set);
	errornoset:
	fclose(f);
	return NULL;
}



void unload_levelset(LEVELSET *set)
{
	if (set) {
		if (set->level) {
			int i;
			for (i = 0; i < set->n_levels; i++) {
				LEVEL *level = &set->level[i];
				free2(level->n_indestructible, level->h);
				free2(level->n_full, level->h);
				free2(level->topping, level->h);
				free2(level->hole, level->h);
				if (level->blower) free(level->blower);
			}
			free(set->level);
		}
		free(set);
	}
}
