--- Demonstrates the basic usage of moonsniff in order to determine device induced latencies
--- This file is the entry point for processing .mscap and .pcap files
--- In order for pcap files to be processed correctly they must feature a 64 bit timestamp at the end
---
--- Valid files can be generated by sniffer.lua with no flags (mscap) or with the flag --capture (pcap)

require "utils"
local log       = require "log"
local dpdk      = require "dpdk"
local pcap      = require "pcap"
local profile   = require "jit.p"

local ffi       = require "ffi"
local C = ffi.C

local MODE_MSCAP, MODE_PCAP = 0, 1
local MODE = MODE_MSCAP

-- skip the initialization of DPDK, as it is not needed for this script
dpdk.skipInit()

function configure(parser)
	parser:description("Demonstrate and test hardware latency induced by a device under test.\nThe ideal test setup is to use 2 taps, one should be connected to the ingress cable, the other one to the egress one.\n\nThe type of the input is automatically detected based on the file extension. Make sure input files are either .pcap or .mscap files.\n\nTo determine which is the pre and which is the post file, files must adhere to the following naming conventions:\n\t<name>-pre.pcap and <name>-post.pcap\n\tor\n\t<name>-pre.mscap and <name>-post.mscap\n\nNote that <name> need not be the same name.")
	parser:option("-i --input", "Path to input file. Supports .mscap or .pcap files."):args(1)
	parser:option("-s --second-input", "Path to second input file. Supports .mscap or .pcap files."):args(1):target("second")
	parser:option("-o --output", "Name of the histogram which is generated."):args(1):default("hist")
	parser:option("-n --nrbuckets", "Size of a bucket for the resulting histogram."):args(1):convert(tonumber):default(1)
	parser:flag("-d --debug", "Create debug information. Instead of processing the input files normally, they are translated into human readable csv files.")
	parser:flag("-p --profile", "Profile the application. May decrease the overall performance.")
	return parser:parse()
end


--- Main entry of the program
function master(args)
	if args.input then INPUT_PATH = args.input end

	-- determine the input type
	if string.match(args.input, ".*%.pcap") then
		MODE = MODE_PCAP
	elseif string.match(args.input, ".*%.mscap") then
		MODE = MODE_MSCAP
	else
		log:err("Input with unknown file extension. Can only process .pcap or .mscap files.")
	end

	print(MODE)
	local PRE
	local POST


	-- determine which is the post and which is the pre file
	if MODE == MODE_MSCAP then
		if not args.second then log:fatal("Detected .mscap file but there was no second file. Single .mscap files cannot be processed.") end

		if string.match(args.input, ".*%-pre%.mscap") and string.match(args.second, ".*%-post%.mscap") then
			PRE = args.input
			POST = args.second

		elseif string.match(args.second, ".*%-pre%.mscap") and string.match(args.input, ".*%-post%.mscap") then
			POST = args.input
			PRE = args.second
		else
			log:fatal("Could not decide which file is pre and which post. Pre should end with -pre.mscap and post with -post.mscap.")
		end
	end

	if MODE == MODE_PCAP then

		if not args.second then log:fatal("Detected .pcap file but there was no second file. Single .pcap files cannot be processed.") end

		if string.match(args.input, ".*%-pre%.pcap") and string.match(args.second, ".*%-post%.pcap") then
			PRE = args.input
			POST = args.second

		elseif string.match(args.second, ".*%-pre%.pcap") and string.match(args.input, ".*%-post%.pcap") then
			POST = args.input
			PRE = args.second
		else
			log:fatal("Could not decide which file is pre and which post. Pre should end with -pre.mscap and post with -post.mscap.")
		end
	end


	print(PRE)
	print(POST)


	-- retrieve file size in order to give an estimation for the processing speed
	local file = assert(io.open(PRE, "r"))
	local size = fsize(file)
	file:close()
	file = assert(io.open(POST, "r"))
	size = size + fsize(file)
	file:close()
	log:info("File size: " .. size / 1e9 .. " [GB]")
	local startTime = getMonotonicTime()
	if args.profile then profile.start("-fl", "profile.log") end

	local packets = 0

	-- run correct matching file
	if MODE == MODE_PCAP then
		local tbb = require "tbbmatch"
		packets = tbb.match(PRE, POST, args)
	elseif MODE == MODE_MSCAP then
		local arr = require "arrmatch"
		packets = arr.match(PRE, POST, args)
	end

	-- finish operations
	if args.profile then profile.stop() end

	local elapsed = getMonotonicTime() - startTime
	log:info("Elapsed time core: " .. elapsed .. " [sec]")
	log:info("Processing speed:\n\t" .. (size / 1e6) / elapsed .. " [MB/s]\n\t" .. (packets / 1e6) / elapsed .. " [mpps]")
end

--- Compute the size of a file
function fsize(file)
	local current = file:seek()
	local size = file:seek("end")
	file:seek("set", current)
	return size
end
