#include "client.hpp"

namespace theo
{
	client::client
	(
		SOCKET client_socket, 
		const theo::theo_data& init_packet, 
		const mapper_routines_t& routines
	)
		: 
		client_socket(client_socket),
		alloc(std::get<0>(routines)),
		mcopy(std::get<1>(routines)),
		resolver(std::get<2>(routines))
	{
		// send first packet to the server... this is an init packet...
		if (send(client_socket, reinterpret_cast<const char*>(
			&init_packet), sizeof init_packet, NULL) == SOCKET_ERROR)
			std::printf("[!] failed to send init packet... reason = %d\n",
				WSAGetLastError());
	}

	std::uintptr_t client::handle() const
	{
		theo::theo_data packet;
		memset(&packet, NULL, sizeof packet);

		while (recv(client_socket, reinterpret_cast<char*>(
			&packet), sizeof packet, MSG_WAITALL) != SOCKET_ERROR)
		{
			switch (packet.type)
			{
				case theo::theo_packet_type::alloc_memory:
				{
					packet.alloc.addr = alloc(packet.alloc.alloc_size, packet.alloc.prot);
					break;
				}
				case theo::theo_packet_type::copy_memory:
				{
					mcopy(packet.copy_memory.dest_addr, 
						packet.copy_memory.data, packet.copy_memory.size);
					break;
				}
				case theo::theo_packet_type::resolve_symbol:
				{
					packet.resolve.symbol_addr = 
						resolver(packet.resolve.symbol);
					break;
				}
				case theo::theo_packet_type::disconnect:
				{
					const auto result = packet.entry_point;
					closesocket(client_socket);
					return result;
				}
			}

			send(client_socket, reinterpret_cast<char*>(
				&packet), sizeof packet, NULL);

			memset(&packet, NULL, sizeof packet);
		}

		std::printf("[+] socket closed with reason = %d\n", 
			WSAGetLastError());

		return {};
	}
}