// Copyright (c) 2023 Alex Diener. All rights reserved.

#include "PROJECT_NAME/GameSavedState.h"
#include "utilities/IOUtilities.h"
#include <limits.h>
#include <stdlib.h>

GameSavedState * GameSavedState_create(unsigned int roomCount, unsigned int currentRoomIndex, EntityPlayer * player, EntityPlayer * roomResetPlayer) {
	GameSavedState * save = malloc(sizeof(*save));
	save->roomCount = roomCount;
	save->roomSaves = calloc(roomCount, sizeof(*save->roomSaves));
	save->roomResetSave = NULL;
	save->currentRoomIndex = currentRoomIndex;
	struct memwriteContext context = memwriteContextInit(NULL, 0, 0, true);
	call_virtual(encodeState, player, &context, false);
	save->playerDataSize = context.length;
	save->playerData = context.data;
	context = memwriteContextInit(NULL, 0, 0, true);
	call_virtual(encodeState, roomResetPlayer, &context, false);
	save->roomResetPlayerDataSize = context.length;
	save->roomResetPlayerData = context.data;
	return save;
}

void GameSavedState_dispose(GameSavedState * save) {
	for (unsigned int roomIndex = 0; roomIndex < save->roomCount; roomIndex++) {
		if (save->roomSaves[roomIndex] != NULL) {
			RoomSavedState_dispose(save->roomSaves[roomIndex]);
		}
	}
	free(save->roomSaves);
	if (save->roomResetSave != NULL) {
		RoomSavedState_dispose(save->roomResetSave);
	}
	free(save->playerData);
	free(save->roomResetPlayerData);
	for (unsigned int nodeIndex = 0; nodeIndex < save->undoNodeCount; nodeIndex++) {
		call_virtual(dispose, save->undoNodes[nodeIndex]);
	}
	free(save->undoNodes);
	free(save);
}

void GameSavedState_encodeUndoStack(GameSavedState * save, UndoStack * undoStack) {
	save->undoNodeCount = undoStack->nodeCount;
	save->currentUndoDepth = undoStack->currentDepth;
	if (undoStack->nodeCount == 0) {
		save->undoNodes = NULL;
	} else {
		save->undoNodes = malloc(save->undoNodeCount * sizeof(*save->undoNodes));
		for (unsigned int nodeIndex = 0; nodeIndex < undoStack->nodeCount; nodeIndex++) {
			save->undoNodes[nodeIndex] = call_virtual(copy, undoStack->nodes[nodeIndex].stateDelta);
		}
	}
}

void GameSavedState_decodeUndoStack(GameSavedState * save, UndoStack * undoStack) {
	undoStack->nodeCount = save->undoNodeCount;
	undoStack->nodeAllocatedCount = save->undoNodeCount;
	if (undoStack->nodeCount > 0) {
		undoStack->nodes = malloc(undoStack->nodeCount * sizeof(*undoStack->nodes));
		for (unsigned int nodeIndex = 0; nodeIndex < save->undoNodeCount; nodeIndex++) {
			undoStack->nodes[nodeIndex].uniqueID = nodeIndex + 1;
			undoStack->nodes[nodeIndex].stateDelta = call_virtual(copy, save->undoNodes[nodeIndex]);
		}
	}
	undoStack->nextNodeID = save->undoNodeCount + 1;
	undoStack->currentDepth = save->currentUndoDepth;
}
