#!/usr/bin/perl
use warnings;
use strict;
use autodie;
use Data::Dump qw(dump);

if ( $ARGV[0] eq 'update' ) {
	print <<__SH__
./sw-name-mac.sh
./sw-names | xargs -i ./dell-switch.pl {} 'show lldp neighbors'
/home/dpavlin/mikrotik-switch/m-neighbour
__SH__
	;
	exit 0;
};


my $debug = $ENV{DEBUG} || 0;

use lib 'lib';
use name2mac;
my $mac2name = $name2mac::mac2name;
warn "# mac2name = ",dump($mac2name); # if $debug;

sub mac2name {
	my ( $mac, $name ) = @_;
	return unless defined $mac;


	$mac = lc($mac);

	if ( exists $mac2name->{$mac} ) {
		my $mac_name = $mac2name->{$mac};
		warn "ERROR: name different $name != $mac_name" if $name && $name ne $mac_name;
		return ( $mac, $mac_name );
	}
	return ( $mac, $name );
}

open(my $n_fh, '>', '/dev/shm/neighbors.tab');
open(my $html_fh, '>', '/var/www/neighbors.html');
print $html_fh qq{<table>\n};

# parse Dell switch lldp neighbors output

foreach my $file ( glob('log/*lldp*') ) {
	my ( undef, $name, undef ) = split(/_/, $file);
	print "# $name $file\n" if $debug;

	my $line_regex;
	my @ports;

	open(my $f, '<', $file);
	while(<$f>) {
		chomp;
		#print "## $_<--\n";
		next if ( /^$/ || /^\s+Port/ );
		if ( /^--+/ ) {
			$line_regex = $_;
			$line_regex =~ s/\s+$//;
			$line_regex =~ s/-/./g;
			$line_regex =~ s/^/(/g;
			$line_regex =~ s/ /) (/g;
			$line_regex =~ s/$/)/g;

			if ( $file =~ m/remote-device/ ) {
				$line_regex =~ s{\) \(}{.)(}g;
				$line_regex =~ s{\(\.+\)$}{(.+)}g;
			}

			print "## line_regex = $line_regex\n" if $debug;
			next;
		}

		s{^\s+}{} if $file =~ m/remote-device/; # remote left-over from pager

		my @v;

		if ( defined($line_regex) &&  /$line_regex/ ) {
 			# port, mac, remote_port, system_name, capabilities
			@v = ( $1, $2, $3, $4, $5 );

			if ( $file =~ m/neighbors/ ) {

				# show lldp neighbours
				# Port       Device ID          Port ID          System Name     Capabilities 

			} elsif ( $file =~ m/remote-device/ ) {

				# show lldp remote-device all
				# Interface RemID   Chassis ID          Port ID           System Name

				@v = ( $v[0], $v[2], $v[3], $v[4], '' );

				# move overflow numbers from system name to port id
				if ( $v[3] =~ s{^(\d+)}{} ) {
					$v[2] .= $1;
				}

			} else {
				die "don't know how to parse $file";
			}
		} elsif ( defined($line_regex) && $file =~ m/remote-device/ ) {
			# if we don't have system name, line_regex is too long
			my @s = split(/\s+/,$_);
			@v = ( $s[0], $s[2], $s[3], '', '' ) if $#s == 3;
		} elsif ( $debug ) {
			my $l = $line_regex;
			$l =~ s{[\(\)]}{}g;
			print "# [$_]<-- LINE IGNORED\n# [$l]\n",dump($_);
		}

		if (@v) {
			print "# [$_] ",join('|',@v),$/ if $debug;

			@v = map { s/^\s+//; s/\s+$//; $_ } @v;

			if ( length($v[1]) == 6 ) { # decode text mac
				$v[1] = unpack('H*', $v[1]);
				$v[1] =~ s/(..)/$1:/g;
				$v[1] =~ s/:$//;
			}

			( $v[1], $v[3] ) = mac2name( $v[1], $v[3] );


			#my ( $port, $device_id, $port_id, $system_name, $cap ) = @v;
			if ( @ports && $v[0] =~ m/^$/ ) {
				my @old = @{ pop @ports };
				foreach my $i ( 0 .. $#old ) {
					$old[$i] .= $v[$i];
				}
				push @ports, [ @old ];
			} else {
				push @ports, [ @v ];
			}
		} else {
			if ( $debug ) {
				my $l = $line_regex;
				$l =~ s{[\(\)]}{}g;
				print "# [$_]<-- IGNORED no v\n# [$l]\n";
			}
		}
	}

	foreach my $p ( @ports ) {
		next if ( $p->[1] eq lc($p->[2]) && $p->[3] eq '' ); # FIXME hosts?
		print "$name ", join(' | ', @$p ), "\n";
		print $n_fh "$name\t", join("\t", @$p ), "\n";
		print $html_fh "<tr><td>$name</td><td>", join("</td><td>", @$p ), "</td></tr>\n";
	}
}

# prase MikroTik /ip neighbor print detail terse

my $patt = 'ip neighbor print detail terse';
$patt =~ s{\s}{\\ }g; # escape spaces
my @files = ( map { $_ . '/*' . $patt } qw( ../mikrotik-switch/out/ ../tilera/out/ ));
@files = map { glob $_ } @files;
warn "XXX $patt files=",dump(\@files) if $debug;

foreach my $file ( @files ) {
	my $name = $1 if $file =~ m{out/+([\w\-]+)\.ip neighbor};
	print "## [$name] file $file\n" if $debug;
	open(my $f, '<', $file);
	while(<$f>) {
		chomp;
		next if m/^\s*$/;
		s{^\s*\d+\s+}{}; # remote ordinal number
		print "# $_\n" if $debug;
		my $l;
		foreach my $kv ( split(/ /, $_) ) {
			my ($k,$v) = split(/=/, $kv);
			$l->{$k} = $v if ( defined($v) && $v ne '""' );
		}

		no warnings 'uninitialized';

		#warn "## l=",dump($l),$/;
		# Port       Device ID          Port ID          System Name     Capabilities 
		my @v = (
			$l->{interface},
			$l->{'mac-address'},
			$l->{'interface-name'},
			$l->{'identity'},
			#$l->{caps},
			join(' ', $l->{address}, $l->{platform}, $l->{board}, $l->{version} ),
		);

		( $v[1], $v[3] ) = mac2name( $v[1], $v[3] );

		if ( $v[2] eq 'NIC' ) { # XXX fix NIC Broadcom
			my ( $host, $if ) = split(/-/, $v[3], 2);
			$v[3] = $host;
			$v[2] = $if
		}

		print "$name ", join(' | ', @v), $/;
		print $n_fh "$name\t", join("\t", @v ), "\n";
		print $html_fh "<tr><td>$name</td><td>", join("</td><td>", @v ), "</td></tr>\n";
	}
}

print $html_fh qq{</table>\n};

close($n_fh);
#system "git -C /dev/shm/ commit -m neighbors.tab neighbors.tab";