#include "network.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <random>

int main(int, char** argv) {
	{
		std::random_device hrng{};

		auto seed = hrng();

		std::minstd_rand srng{seed};

		std::minstd_rand cpyrng{seed};

		auto soc = socket(AF_INET, SOCK_DGRAM, 0);
		struct sockaddr_in server;
		server.sin_family = AF_INET;
		server.sin_addr.s_addr = *(in_addr_t*)std::array<unsigned char, 4>{127,0,0,1}.data();
		server.sin_port = htons(20450);

		uint32_t tot = 2048;

		if(argv[1])
		{
			tot = std::stoi(argv[1]);
		}

		connect(soc, (struct sockaddr*)&server, sizeof(server));

		sending_data reply;
		received_data request;

		db_page& v = request.page;
		v.fill(1);

		record_identifier& tar = request.identifier;

		auto begin = std::chrono::high_resolution_clock::now();

		for(size_t idx=0;idx<tot;idx++)
		{
			tar.x.internal = srng();
			tar.y.internal = srng();
			request.op = db_op::write;
			sendto(
				soc,
				(void*)&request,
				sizeof(request),
				0,
				(struct sockaddr*)&server,
				(socklen_t)sizeof(server)
			);
			recv(soc, &reply, sizeof(reply), 0);
		}

		auto durr = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - begin)/tot;

		std::cerr << "w:durr/elem = " << durr.count() << "ns/op" << std::endl;
		std::cerr << "w:elem/s = " << 1000000000.0f/durr.count() << std::endl;

		begin = std::chrono::high_resolution_clock::now();

		for(size_t idx=0;idx<tot;idx++)
		{
			tar.x.internal = cpyrng();
			tar.y.internal = cpyrng();
			request.op = db_op::read;
			sendto(
				soc,
				(void*)&request,
				sizeof(request),
				0,
				(struct sockaddr*)&server,
				(socklen_t)sizeof(server)
			);
			recv(soc, &reply, sizeof(reply), 0);
			if(reply.page[0] != 1)
			{
				std::cerr << "read failed" << std::endl;
			}
		}

		durr = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - begin)/tot;

		std::cerr << "r:durr/elem = " << durr.count() << "ns/op" << std::endl;
		std::cerr << "r:elem/s = " << 1000000000.0f/durr.count() << std::endl;

		request.op = db_op::read;
		sendto(
			soc,
			(void*)&request,
			sizeof(request),
			0,
			(struct sockaddr*)&server,
			(socklen_t)sizeof(server)
		);
		recv(soc, &reply, sizeof(reply), 0);

		if(reply.page[0] != 1) {
			std::cerr << "read failed" << std::endl;
		}

		request.op = db_op::remove;
		sendto(
			soc,
			(void*)&request,
			sizeof(request),
			0,
			(struct sockaddr*)&server,
			(socklen_t)sizeof(server)
		);
		recv(soc, &reply, sizeof(reply), 0);

		request.op = db_op::read;
		sendto(
			soc,
			(void*)&request,
			sizeof(request),
			0,
			(struct sockaddr*)&server,
			(socklen_t)sizeof(server)
		);

		reply.page.fill(0);
		recv(soc, &reply, sizeof(reply), 0);

		if(reply.page[0] == 1) {
			std::cerr << "remove failed" << std::endl;
		}
	}
}
