#!/usr/bin/env python3
# encoding: utf-8
"""
response/text.py

Created by Thomas Mangin on 2012-12-30.
Copyright (c) 2009-2017 Exa Networks. All rights reserved.
License: 3-clause BSD. (See the COPYRIGHT file)
"""

import os

from exabgp.util import hexstring
from exabgp.bgp.message import Action


class Text(object):
    def __init__(self, version):
        self.version = version

    def _header_body(self, header, body):
        header = ' header %s' % hexstring(header) if header else ''
        body = ' body %s' % hexstring(body) if body else ''

        total_string = header + body if body else header

        return total_string

    def _counter(self, neighbor):
        return None

    def up(self, neighbor):
        return 'neighbor %s up\n' % (neighbor['peer-address'])

    def connected(self, neighbor):
        return 'neighbor %s connected\n' % (neighbor['peer-address'])

    def down(self, neighbor, reason=''):
        return 'neighbor %s down - %s\n' % (neighbor['peer-address'], reason)

    def shutdown(self):
        return 'shutdown %d %d\n' % (os.getpid(), os.getppid())

    def negotiated(self, neighbor, negotiated):
        return None

    def fsm(self, neighbor, fsm):
        return None

    def signal(self, neighbor, signal):
        return None

    def notification(self, neighbor, direction, message, negotiated, header, body):
        return 'neighbor %s %s notification code %d subcode %d data %s%s\n' % (
            neighbor['peer-address'],
            direction,
            message.code,
            message.subcode,
            hexstring(message.data),
            self._header_body(header, body),
        )

    def packets(self, neighbor, direction, category, negotiated, header, body):
        return 'neighbor %s %s %d%s\n' % (
            neighbor['peer-address'],
            direction,
            category,
            self._header_body(header, body),
        )

    def keepalive(self, neighbor, direction, negotiated, header, body):
        return 'neighbor %s %s keepalive%s\n' % (neighbor['peer-address'], direction, self._header_body(header, body))

    def open(self, neighbor, direction, sent_open, negotiated, header, body):
        return 'neighbor %s %s open version %d asn %d hold_time %s router_id %s capabilities [%s]%s\n' % (
            neighbor['peer-address'],
            direction,
            sent_open.version,
            sent_open.asn,
            sent_open.hold_time,
            sent_open.router_id,
            str(sent_open.capabilities).lower(),
            self._header_body(header, body),
        )

    def update(self, neighbor, direction, update, negotiated, header, body):
        prefix = 'neighbor %s %s update' % (
            neighbor['peer-address'],
            direction,
        )

        r = '%s start\n' % prefix

        attributes = str(update.attributes)
        for nlri in update.nlris:
            if nlri.EOR:
                r += '%s route %s\n' % (prefix, nlri.extensive())
            elif nlri.action == Action.ANNOUNCE:  # pylint: disable=E1101
                if nlri.nexthop:
                    r += '%s announced %s%s\n' % (prefix, nlri.extensive(), attributes)
                else:
                    # This is an EOR or Flow or ... something newer
                    r += '%s %s %s\n' % (prefix, nlri.extensive(), attributes)
            else:
                r += '%s withdrawn %s\n' % (prefix, nlri.extensive())
        if header or body:
            r += '%s\n' % self._header_body(header, body)

        r += '%s end\n' % prefix

        return r

    def refresh(self, neighbor, direction, refresh, negotiated, header, body):
        return 'neighbor %s %s route-refresh afi %s safi %s %s%s\n' % (
            neighbor['peer-address'],
            direction,
            refresh.afi,
            refresh.safi,
            refresh.reserved,
            self._header_body(header, body),
        )

    def _operational_advisory(self, neighbor, direction, operational, header, body):
        return 'neighbor %s %s operational %s afi %s safi %s advisory "%s"%s' % (
            neighbor['peer-address'],
            direction,
            operational.name,
            operational.afi,
            operational.safi,
            operational.data,
            self._header_body(header, body),
        )

    def _operational_query(self, neighbor, direction, operational, header, body):
        return 'neighbor %s %s operational %s afi %s safi %s%s' % (
            neighbor['peer-address'],
            direction,
            operational.name,
            operational.afi,
            operational.safi,
            self._header_body(header, body),
        )

    def _operational_counter(self, neighbor, direction, operational, header, body):
        return 'neighbor %s %s operational %s afi %s safi %s router-id %s sequence %d counter %d%s' % (
            neighbor['peer-address'],
            direction,
            operational.name,
            operational.afi,
            operational.safi,
            operational.routerid,
            operational.sequence,
            operational.counter,
            self._header_body(header, body),
        )

    def operational(self, neighbor, direction, what, operational, negotiated, header, body):
        if what == 'advisory':
            return self._operational_advisory(neighbor, direction, operational, header, body)
        elif what == 'query':
            return self._operational_query(neighbor, direction, operational, header, body)
        elif what == 'counter':
            return self._operational_counter(neighbor, direction, operational, header, body)
        # elif what == 'interface':
        # 	return self._operational_interface(peer,operational)
        else:
            raise RuntimeError('the code is broken, we are trying to print a unknown type of operational message')
