#!/usr/bin/env python3
#
# Copyright (C) 2019-2020 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import argparse
import jinja2
import json

from sys import exit
from tabulate import tabulate

from vyos.util import cmd
from vyos.config import Config

parser = argparse.ArgumentParser()
parser.add_argument("-a", "--all", action="store_true", help="Show LLDP neighbors on all interfaces")
parser.add_argument("-d", "--detail", action="store_true", help="Show detailes LLDP neighbor information on all interfaces")
parser.add_argument("-i", "--interface", action="store", help="Show LLDP neighbors on specific interface")

# Please be careful if you edit the template.
lldp_out = """Capability Codes: R - Router, B - Bridge, W - Wlan r - Repeater, S - Station
                  D - Docsis, T - Telephone, O - Other

Device ID                 Local     Proto  Cap   Platform             Port ID
---------                 -----     -----  ---   --------             -------
{% for neighbor in neighbors %}
{%   for local_if, info in neighbor.items() %}
{{ "%-25s" | format(info.chassis) }} {{ "%-9s" | format(local_if) }} {{ "%-6s" | format(info.proto) }} {{ "%-5s" | format(info.capabilities) }} {{ "%-20s" | format(info.platform[:18]) }} {{ info.remote_if }}
{%   endfor %}
{% endfor %}
"""

def get_neighbors():
    return cmd('/usr/sbin/lldpcli -f json show neighbors')

def parse_data(data, interface):
    output = []
    if not isinstance(data, list):
        data = [data]

    for neighbor in data:
        for local_if, values in neighbor.items():
            if interface is not None and local_if != interface:
                continue
            cap = ''
            for chassis, c_value in values.get('chassis', {}).items():
                # bail out early if no capabilities found
                if 'capability' not in c_value:
                    continue
                capabilities = c_value['capability']
                if isinstance(capabilities, dict):
                    capabilities = [capabilities]

                for capability in capabilities:
                    if capability['enabled']:
                        if capability['type'] == 'Router':
                            cap += 'R'
                        if capability['type'] == 'Bridge':
                            cap += 'B'
                        if capability['type'] == 'Wlan':
                            cap += 'W'
                        if capability['type'] == 'Station':
                            cap += 'S'
                        if capability['type'] == 'Repeater':
                            cap += 'r'
                        if capability['type'] == 'Telephone':
                            cap += 'T'
                        if capability['type'] == 'Docsis':
                            cap += 'D'
                        if capability['type'] == 'Other':
                            cap += 'O'

            remote_if = 'Unknown'
            if 'descr' in values.get('port', {}):
                remote_if = values.get('port', {}).get('descr')
            elif 'id' in values.get('port', {}):
                remote_if = values.get('port', {}).get('id').get('value', 'Unknown')

            output.append({local_if: {'chassis': chassis,
                                       'remote_if': remote_if,
                                       'proto': values.get('via','Unknown'),
                                       'platform': c_value.get('descr', 'Unknown'),
                                       'capabilities': cap}})

    output = {'neighbors': output}
    return output

if __name__ == '__main__':
    args = parser.parse_args()
    tmp = { 'neighbors' : [] }

    c = Config()
    if not c.exists_effective(['service', 'lldp']):
        print('Service LLDP is not configured')
        exit(0)

    if args.detail:
        print(cmd('/usr/sbin/lldpctl -f plain'))
        exit(0)
    elif args.all or args.interface:
        tmp = json.loads(get_neighbors())
        neighbors = dict()

        if 'interface' in tmp.get('lldp'):
            neighbors = tmp['lldp']['interface']

    else:
        parser.print_help()
        exit(1)

    tmpl = jinja2.Template(lldp_out, trim_blocks=True)
    config_text = tmpl.render(parse_data(neighbors, interface=args.interface))
    print(config_text)

    exit(0)