#include "client.hpp"
#include "linker.hpp"

int __cdecl main(int argc, char** argv)
{
	if (argc <= 4)
	{
		std::printf("[!] invalid usage...\n");
		std::printf("\t> server.exe --ip 0.0.0.0 --port 1234\n");
		std::printf("\t> server.exe --ip 0.0.0.0 --port 1234 --debug\n");
		return -1;
	}

	for (auto idx = 0; idx < argc; ++idx)
		if (!strcmp(argv[idx], "--debug"))
			dbg_print = true;

	int result{};
	SOCKET server_socket, client_socket;

	WSADATA startup_data;
	ADDRINFOA addr_info, *addr_result = nullptr;
	memset(&addr_info, NULL, sizeof addr_info);

	if ((result = WSAStartup(MAKEWORD(2, 2), &startup_data)))
	{
		std::printf("[!] failed to startup wsa... reason = %d\n", result);
		return -1;
	}

	if ((result = getaddrinfo(argv[2], argv[4], &addr_info, &addr_result)))
	{
		std::printf("[!] failed to get address info = %s:%s, reason = %d\n",
			argv[2], argv[4], result);
		return -1;
	}

	if ((server_socket = socket(addr_result->ai_family, 
		addr_result->ai_socktype, addr_result->ai_protocol)) == INVALID_SOCKET)
	{
		std::printf("[!] failed to create socket... reason = %d\n", 
			WSAGetLastError());
		return -1;
	}

	if ((result = bind(server_socket, addr_result->ai_addr, addr_result->ai_addrlen)))
	{
		std::printf("[!] failed to bind server socket... reason = %d\n", result);
		return -1;
	}

	if ((result = listen(server_socket, SOMAXCONN)))
	{
		std::printf("[!] failed to listen on socket... reason = %d\n", result);
		return -1;
	}

	// read libs off disk and into map...
	std::vector<lnk::obj_buffer_t> demo_dll, demo_imgui, demo_drv;

	lnk::get_objs("DemoDll.lib", demo_dll);
	if (demo_dll.empty())
	{
		std::printf("[!] failed to load DemoDll.lib objs...\n");
		return -1;
	}
	std::printf("[+] loaded objs from DemoDll.lib... count = %d\n", demo_dll.size());

	lnk::get_objs("DemoDrv.lib", demo_drv);
	if (demo_drv.empty())
	{
		std::printf("[!] failed to load DemoDrv.lib objs...\n");
		return -1;
	}
	std::printf("[+] loaded objs from DemoDrv.lib... count = %d\n", demo_drv.size());

	lnk::get_objs("DemoImGui.lib", demo_imgui);
	if (demo_imgui.empty())
	{
		std::printf("[!] failed to load DemoImGui.lib objs...\n");
		return -1;
	}
	std::printf("[+] loaded objs from DemoImGui.lib... count = %d\n", demo_imgui.size());

	theo::lib_files[theo::theo_file_type::demo_dll] = demo_dll;
	theo::lib_files[theo::theo_file_type::demo_drv] = demo_drv;
	theo::lib_files[theo::theo_file_type::demo_imgui] = demo_imgui;

	std::printf("[+] listening on %s:%s...\n", argv[2], argv[4]);
	while ((client_socket = accept(server_socket, NULL, NULL)) != INVALID_SOCKET)
	{
		theo::connections[client_socket] =
			std::shared_ptr<theo::client>(
				new theo::client(client_socket));

		sockaddr socket_info;
		int socket_info_len = sizeof socket_info;

		const auto psocket_info = 
			reinterpret_cast<sockaddr_in*>(&socket_info);

		getpeername(client_socket, &socket_info, &socket_info_len);
		std::printf("[+] new client... ip = %s\n", inet_ntoa(psocket_info->sin_addr));
	}
}