#include "animia.h"
#include "animia/fd.h"
#include "animia/strategies.h"
#include "animia/types.h"
#include "animia/util.h"
#include "animia/win.h"

#include <set>
#include <string>
#include <vector>

namespace animia {

namespace internal {

static bool IsExecutableInList(const Player& player, const std::string& name) {
	std::string stem;
#ifdef WIN32
	if (!util::Stem(name, stem))
#endif
		stem = name;

	for (const auto& pattern : player.executables)
		if (util::CheckPattern(pattern, stem))
			return true;

	return false;
}

static bool IsWindowInList(const Player& player, const std::string& name) {
	for (const auto& pattern : player.windows)
		if (util::CheckPattern(pattern, name))
			return true;

	return false;
}

static bool PlayerHasStrategy(const Player& player, const Strategy& strategy) {
	for (const auto& pstrategy : player.strategies)
		if (pstrategy == strategy)
			return true;

	return false;
}

} // namespace internal

bool GetResults(const std::vector<Player>& players, std::vector<Result>& results) {
	/* Start out with file descriptors. */
	auto process_proc = [&](const Process& process) -> bool {
		for (const auto& player : players) {
			if (!internal::PlayerHasStrategy(player, Strategy::OpenFiles))
				continue;

			if (!internal::IsExecutableInList(player, process.name))
				continue;

			results.push_back({ResultType::Process, player, process, {}, {}});
			break;
		}
		return true;
	};

	if (!internal::EnumerateOpenProcesses(process_proc))
		return false;

	/* Then add our cool windows.
	   Note: X11 is stupid and there's no reliable way to get a PID from a given window.
	         This is because some windows might not even have a process attached to them.
	         We should set the PID of the process if we can get it, but that'll be for when
	         I can actually be arsed to implement the X11 backend. */
	auto window_proc = [&](const Process& process, const Window& window) -> bool {
		for (const auto& player : players) {
			if (!internal::PlayerHasStrategy(player, Strategy::WindowTitle))
				continue;

			if (!internal::IsWindowInList(player, window.class_name))
				continue;

			results.push_back({ResultType::Window, player, process, window, {}});
			break;
		}
		return true;
	};

	if (!internal::EnumerateWindows(window_proc))
		return false;

	return internal::ApplyStrategies(results);
}

} // namespace animia
