#!/usr/local/bin/perl

@ARPTYPE = ("REQUEST", "REPLY");
@TCPTYPE = ("tcp", "ack");
@MACTYPE = ("RTS", "CTS", "ACK");
@TORATYPE = ("BEACON", "HELLO", "QUERY", "UPDATE", "CLEAR");

$MACTYPE_RTS = hex("1b");
$MACTYPE_CTS = hex("1c");
$MACTYPE_ACK = hex("1d");
$MACTYPE_DATA = hex("20");

$infile = 0;	# input file
$time = 0;	# length of the simulation

$sent = 0;
$recv = 1;
$sdrp = 2;
$rdrp = 3;
$rxmt = 4;
$bytes = 5;

sub col1_output {
	$A = shift(@_);

	printf("\n%s Packets\n", $A);
	printf("\tTransmitted:    %d\n", $A->[$sent]);
	printf("\tReceived:       %d\n", $A->[$recv]);
	printf("\tRetransmitted:  %d\n", $A->[$rxmt]);
	printf("\tSender Drops:   %d\n", $A->[$sdrp]);
	printf("\tReceiver Drops: %d\n", $A->[$rdrp]);
	printf("\t%% Drops:        %3.2f\n",
		100 * ($A->[$sdrp] + $A->[$rdrp]) / $A->[$sent]);
	printf("\tMissing:        %d\n",
		$A->[$sent] - ($A->[$recv] + $A->[$rdrp]));
	printf("\tThroughput:     %f KB/sec, %f bps\n\n",
		$A->[$bytes] / (1024 * $time), $A->[$bytes] * 8 / $time);
}

sub col2_output {
	$A = shift(@_);
	$B = shift(@_);

	printf("\n%s Packets\t\t\t\t%s Packets\n",
		$A, $B);

	printf("\tTransmitted:      %d\t\t\tTransmitted:      %d\n",
		$A->[$sent], $B->[$sent]);

	printf("\tReceived:         %d\t\t\tReceived:         %d\n",
		$A->[$recv], $B->[$recv]);

	printf("\tRetransmitted:    %d\t\t\tRetransmitted:    %d\n",
		$A->[$rxmt], $B->[$rxmt]);

	printf("\tSender Dropped:   %d\t\t\tSender Dropped:   %d\n",
		$A->[$sdrp], $B->[$sdrp]);

	printf("\tReceiver Dropped: %d\t\t\tReceiver Dropped: %d\n",
		$A->[$rdrp], $B->[$rdrp]);

	printf("\tMissing:          %d\t\t\tMissing:          %d\n",
		$A->[$sent] - ($A->[$recv] + $A->[$rdrp]),
		$B->[$sent] - ($B->[$recv] + $B->[$rdrp]));
	printf("\tThroughput:       %6.2f KB/sec\t\tThroughput:     %6.2f KB/sec\n\n",
		$A->[$bytes] / (1024 * $time), $B->[$bytes] / (1024 * $time));
}

sub show_totals {

	$PKT = shift(@_);

	printf("\n%s Packets\n", $PKT);
	printf("\tTransmitted:      %d\n", $PKT->[$sent]);
	printf("\tReceived:         %d\n", $PKT->[$recv]);
	printf("\tRetransmitted:    %d\n", $PKT->[$rxmt]);
	printf("\tSender Dropped:   %d\n", $PKT->[$sdrp]);
	printf("\tReceiver Dropped: %d\n", $PKT->[$rdrp]);

	printf("\tMissing:          %d\n", $PKT->[$sent] -
		($PKT->[$recv] + $PKT->[$rdrp]));

	if($PKT->[$sent]) {
		printf("\t%% Drops:          %3.2f\n",
			100 * ($PKT->[$sdrp] + $PKT->[$rdrp]) / $PKT->[$sent]);
	}

	printf("\tThroughput:       %f KB/sec, %f bps\n\n",
		$PKT->[$bytes] / (1024 * $time),
		$PKT->[$bytes] * 8 / $time);

	if(! @_) {
		return;
	}

	#
	# Individual Packet Formats
	#
	$tcnt = $PKT->[$sent];
	while(@_) {
		$P = shift(@_);

		$tcnt -= $PKT->{$P}->[$sent];

		printf("\t%s Packets\n", $P);

		printf("\t\tTransmitted:      %d\n", $PKT->{$P}->[$sent]);
		printf("\t\tReceived:         %d\n", $PKT->{$P}->[$recv]);
		printf("\t\tRetransmitted:    %d\n", $PKT->{$P}->[$rxmt]);
		printf("\t\tSender Dropped:   %d\n", $PKT->{$P}->[$sdrp]);
		printf("\t\tReceiver Dropped: %d\n", $PKT->{$P}->[$rdrp]);

		printf("\t\tMissing:          %d\n", $PKT->{$P}->[$sent] -
			($PKT->{$P}->[$recv] + $PKT->{$P}->[$rdrp]));

		printf("\t\tThroughput:       %d KB/sec\n",
			$PKT->{$P}->[$bytes] / (1024 * $time));
	}

	if($tcnt != 0) {
		printf("Error in sent totals.\n");
		exit;
	}
}


sub process_arp {
	$OP = shift(@_);		# send, receive, drop
	$RXMT = shift(@_);		# retransmission (YES/NO)
	$SIZE = shift(@_);		# packet size
	$LINE = shift(@_);		# line from log file

	ARP->[$OP] += 1;
	ARP->[$rxmt] += $RXMT;
	ARP->[$bytes] += $SIZE;

	if($LINE =~ / ------- (\d+)\/(\d+) (\w+) (\d+)\/(\d+) .*/) {
		$op = $3;

		if( $op != "REQUEST" && $op != "REPLY" ) {
			print "Invalid ARP packet.\n";
			exit;
		}
		ARP->{$op}->[$OP] += 1;
		ARP->{$op}->[$rxmt] += $RXMT;
		ARP->{$op}->[$bytes] += $SIZE;
	}
	else {
		print "ARP Logging error\n$LINE\n";
		exit;
	}
}

sub process_tcp {
    $OP = shift(@_);		# send, receive, drop
    $RXMT = shift(@_);		# retransmission (YES/NO)
    $SIZE = shift(@_);		# packet size
    $LINE = shift(@_);		# line from log file
    
    TCP->[$OP] += 1;
    TCP->[$rxmt] += $RXMT;
    
    if($LINE =~ 
/^(.) .*(\d+) (\w+) (\d+) ------- (\d+) \[(\d+):(\d+) (\d+):(\d+)\]/) {
	$kind = $1;
	$node = $2;
	$op = $3;
	$src = $6;
	$dst = $8;

	if ($kind == 'r' && $node == $dst) {
	    # a succesful receipt
	    TCP->[$bytes] += $SIZE;
	}

	if( $op != "tcp" && $op != "ack" ) {
	    print "Invalid TCP packet.\n";
	    exit;
	}
	TCP->{$op}->[$OP] += 1;
	TCP->{$op}->[$rxmt] += $RXMT;
	TCP->{$op}->[$bytes] += $SIZE;
    }
    else {
	print "TCP Logging error\n$LINE\n";
	exit;
    }
    
}

sub process_tora {
	$OP = shift(@_);		# send, receive, drop
	$RXMT = shift(@_);		# retransmission (YES/NO)
	$SIZE = shift(@_);		# packet size
	$LINE = shift(@_);		# line from log file

	TORA->[$OP] += 1;
	TORA->[$rxmt] += $RXMT;
	TORA->[$bytes] += $SIZE;

	if($LINE =~ / ------- \[(\w+):(\w+) (\w+):(\w+)\] (\w+) .*/) {
		$t = hex($5);

		if($t == 1) {
			$op = "QUERY";
		}
		elsif($t == 2) {
			$op = "UPDATE";
		}
		elsif($t == 4) {
			$op = "CLEAR";
		}
		elsif($t == 16) {
			$op = "BEACON";
		}
		elsif($t == 32) {
			$op = "HELLO";
		}
		else {
			print "Invalid TORA packet.\n";
			exit;
		}

		TORA->{$op}->[$OP] += 1;
		TORA->{$op}->[$rxmt] += $RXMT;
		TORA->{$op}->[$bytes] += $SIZE;
	}
	else {
		print "TCP Logging error\n$LINE\n";
		exit;
	}
}

sub process_mac {
	$OP = shift(@_);		# send, receive, drop
	$RXMT = shift(@_);		# retransmission (YES/NO)
	$SIZE = shift(@_);		# packet size
	$LINE = shift(@_);		# line from log file

	MAC->[$OP] += 1;
	MAC->[$rxmt] += $RXMT;
	MAC->[$bytes] += $SIZE;

	if($LINE =~ /\[(\w+) (\w+) (\w+) (\w+) (\w+)\] .*/) {
		$t = hex($1) & 255;

		if($t == $MACTYPE_RTS) {
			$op = "RTS";
		}
		elsif($t == $MACTYPE_CTS) {
			$op = "CTS";
		}
		elsif($t == $MACTYPE_ACK) {
			$op = "ACK";
		}
		else {
			print "Invalid MAC packet.\n";
			exit;
		}

		MAC->{$op}->[$OP] += 1;
		MAC->{$op}->[$rxmt] += $RXMT;
		MAC->{$op}->[$bytes] += $SIZE;
	}
	else {
		print "TCP Logging error\n$LINE\n";
		exit;
	}

}


#
# Main Procedure begins here.
#
if(! @ARGV) {
	print "\nERROR: Must specify file to process.\n\n";
	exit 1;
}

if(! open $infile, $ARGV[0]) {
	print "Could not open $ARGV[0]\n";
	exit 1;
}

while(<$infile>) {
	if(/ (\d+).(\S+) \[(\w+) (\w+) (\w+) (\w+) (\w+)\] (\d+) (\D+) (\d+).*/) {
		$time = $1;
		# fractional part of time = $2;
		$mac_type = hex($3);
		$mac_duration = hex($4);
		$mac_dst = hex($5);
		$mac_src = hex($6);
		$ether_type = hex($7);
		$node = $8;
		$pkttype = $9;
		$pktsize = $10;

		if($mac_type > 255) {
			$retransmit = 1;
			$mac_type &= 255;
		}

		if(/^s /) {
			$opcode = $sent;
			$pktsize = 0;
		}
		elsif(/^r /) {
			$opcode = $recv;
			$retransmit = 0;
		}
		elsif(/^d / || /^D /) {
			if($mac_src == $node) {
				$opcode = $sdrp;
			}
			else {
				$opcode = $rdrp;
			}
			$pktsize = 0;
			$retransmit = 0;
		}
		else {
			print "Invalid OPERATION\n$_\n";
			exit;
		}

		if($mac_type == $MACTYPE_RTS ||
		   $mac_type == $MACTYPE_CTS ||
		   $mac_type == $MACTYPE_ACK) {
			process_mac($opcode, $retransmit, $pktsize, $_);
		}
		elsif($mac_type == $MACTYPE_DATA) {
			if($pkttype eq "ARP") {
				process_arp($opcode, $retransmit, $pktsize, $_);
			}
			elsif($pkttype eq "tcp" ||
			      $pkttype eq "ack") {
				process_tcp($opcode, $retransmit, $pktsize, $_);
			}
			elsif($pkttype eq "TORA") {
				process_tora($opcode, $retransmit, $pktsize, $_);
			}
			elsif($pkttype eq "DSR") {
			    #### Nothing
			}
			else {
				print "Invalid packet type $pkttype\n";
				exit;
			}
		}
		else {
			print "Invalid packet type $pkttype\n";
			exit;
		}
	}
	elsif (/^RR (\d+).(\S+) (\d+) (\w+) (.*)/) {
	    $time = $1;
	    # fractional part of time = $2;
	    $who = $3;
	    $rest = $4
	    }
	elsif (/^$miss/) {
	}
	elsif (/^$hit/) {
	}
	elsif (/^SendFailure/) {
	}
	elsif (/^debug/) {
	}
	elsif(/^M /) {
	}
	else {
		print "Error: $_\n";
		exit;
	}
}

$time += 1;		# accounts for fractional part

foreach $PKT (MAC, ARP, TCP, TORA) {
	$TOTAL[$sent] += $PKT->[$sent];
	$TOTAL[$recv] += $PKT->[$recv];
	$TOTAL[$sdrp] += $PKT->[$sdrp];
	$TOTAL[$rdrp] += $PKT->[$rdrp];
	$TOTAL[$rxmt] += $PKT->[$rxmt];
	$TOTAL[$bytes] += $PKT->[$bytes];
}

show_totals("MAC", @MACTYPE);
show_totals("ARP", @ARPTYPE);
#show_totals("TORA", @TORATYPE);
show_totals("TCP", @TCPTYPE);
print "Simulation Time: $time\n";
col1_output("TOTAL");

exit;
