#include "enemies.h"
#include "core/roguedefs.h"
#include "core/world.h"
#include <functional>

namespace rogue {
Tile CritteLogic::move() {
	Tile location{this->character->location};
	Character *player{this->character->world->get_player()};
	if(this->is_aware_of_player) {
		// cache query_tile call for repeated use
		std::function<TileData(Tile)> query_tile{std::bind(&World::query_tile, this->character->world, std::placeholders::_1)};
		// this could be a few quick vector math operations, but i'm minimizing the C++ features i'm using with SDL structs
		// difference between the player's location and ours
		Tile difference{
			player->location.x - location.x,
			player->location.y - location.y
		};
		// absolute difference, useful for comparing them
		Tile abs{std::abs(difference.x), std::abs(difference.y)};
		// signs of the difference
		Tile signs{
			difference.x == 0 ? 0 : difference.x / std::abs(difference.x),
			difference.y == 0 ? 0 : difference.y / std::abs(difference.y)
		};
		// theoretical motion along x
		Tile x_motion{location.x + signs.x, location.y};
		// theoretical motion along y
		Tile y_motion{location.x, location.y + signs.y};
		// choose either x or y motion depending on which is possible and faster
		if(abs.x >= abs.y) {
			if(!query_tile(x_motion).is_wall)
				return x_motion;
			else if(!query_tile(y_motion).is_wall) {
				return y_motion;
			}
		} else {
			if(!query_tile(y_motion).is_wall) {
				return y_motion;
			} else if(!query_tile(x_motion).is_wall) {
				return x_motion;
			}
		}
	} else {
		// cache get_chunk call for easier reading
		std::function<Chunk(Tile)> get_chunk{std::bind(&World::get_chunk, this->character->world, std::placeholders::_1)};
		this->is_aware_of_player |= get_chunk(player->location) == get_chunk(location);
	}
	// fallback return value, for if there is no desirable tile to move to
	return {
		.x = location.x,
		.y = location.y
	};
}
}
