#include "IFace.h"
#include "util/netsender.h"
#include "util/netwatcher.h"
#include "util/packetmaker.h"
#include "util/output.h"

#include <stdio.h>

#include <iostream>

extern "C" {
#include <libnet.h>
}

using namespace std;
using namespace wibble::sys;
using namespace util;

class PacketPrinter : public PacketListener
{
public:
	virtual void handleARP(struct libnet_arp_hdr* arp_header) throw ()
	{
		cout << "Seen ARP";

		// Parse and check the arp header
		if (ntohs (arp_header->ar_op) == ARPOP_REPLY)
		{
			string rep;
			//in_addr* ipv4_him = arp_get_tip(arp_header);
			in_addr* ipv4_him = arp_get_sip(arp_header);
			ether_addr* mac_him = arp_get_sha(arp_header);

			rep += fmt(IPAddress(*ipv4_him)) + " " + fmt(*mac_him);

			cout << " reply from " << rep;

			//IPv4_FROM_LIBNET(ipv4_me, arp_header->ar_tpa);
			//IPv4_FROM_ARP(ipv4_him, arp_header->ar_spa);
		}
		cout << endl;
	}
	virtual void handleEthernet(struct libnet_ethernet_hdr* arp_header) throw ()
	{
		cout << "Seen Ethernet" << endl;
	}
// others to come as needed, like:
// //         // virtual handleDHCP(struct libnet_hdcp_something* hdcp_header) throw () {}
};

static void printConfig(const char* tag, IFace& iface)
{
	if_params ifp = iface.getConfiguration();
	printf("%-10.10s %s: ", tag, iface.name().c_str());
	ifp.print();
}

int main(int argc, char* argv[])
{
	if (argc < 2)
		fatal_error("Usage: %s <iface>\n", argv[0]);
	try {
		wibble::exception::InstallUnexpected installUnexpected;

		{
			fprintf(stderr, "\t\tTrying libnet setup...\n");
			libnet_t* ln_context;
			char ln_errbuf[LIBNET_ERRBUF_SIZE];
			if (!(ln_context = libnet_init(LIBNET_LINK_ADV, argv[1], ln_errbuf)))
				throw wibble::exception::Libnet(ln_errbuf, "opening link interface");
			fprintf(stderr, "\t\tLibnet deleting %p...\n", ln_context);
			libnet_destroy(ln_context);
			fprintf(stderr, "\t\tLibnet tried...\n");
		}

		NetSender::configure(argv[1]);
		NetWatcher::configure(argv[1]);

		IFace iface(argv[1]);
		if_params ifp = iface.getConfiguration();
		printConfig("Initial", iface);

		/*
		fprintf(stderr, "\t\tDeconfiguring interface...\n");
		system("ifconfig eth0 down");
		printConfig("Down", iface);

		{
			fprintf(stderr, "\t\tInitializing net sender...\n");
			NetSender sender(argv[1]);
			printConfig("Post-NS", iface);
		}

		fprintf(stderr, "\t\tConfiguring for broadcast...\n");
		iface.initBroadcast(4);
		printConfig("Broadcast", iface);

		{
			fprintf(stderr, "\t\tInitializing net sender...\n");
			NetSender sender(argv[1]);
			printConfig("Post-NS", iface);
		}
		*/
		PacketPrinter pp;
		NetWatcher::get().addARPListener(&pp);

		// Build and send arp probes
		Buffer pkt = PacketMaker::makeARPRequest(IPAddress("192.168.1.1"), IPAddress("0.0.0.0"));

		// Enqueue the packet for sending
		NetSender::get().post(pkt, 1000, 10000);

		Starter::get().start();

		sleep(20);

		fprintf(stderr, "\t\tRestoring interface...\n");
		iface.setConfiguration(ifp);
		printConfig("Restored", iface);
		fprintf(stderr, "\t\tDone.\n");
	}
	catch (std::exception& e)
	{
		error("%s\n", e.what());
		return 1;
	}
	return 0;
}

// vim:set ts=4 sw=4:
