# encoding: utf-8
"""
sradjlan.py

Created by Evelio Vila
Copyright (c) 2014-2017 Exa Networks. All rights reserved.
"""

import json
from struct import unpack
from exabgp.vendoring import six
from exabgp.util import hexstring

from exabgp.vendoring.bitstring import BitArray
from exabgp.protocol.iso import ISO
from exabgp.bgp.message.update.attribute.bgpls.linkstate import LINKSTATE, LsGenericFlags
from exabgp.bgp.message.notification import Notify

#   0                   1                   2                   3
#   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
#  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#  |              Type             |            Length             |
#  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#  |     Flags     |     Weight    |            Reserved           |
#  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#   |             OSPF Neighbor ID / IS-IS System-ID                |
#   +                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#   |                               |
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
#   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#   |                    SID/Label/Index (variable)                 |
#   +---------------------------------------------------------------+
# 		draft-gredler-idr-bgp-ls-segment-routing-ext-03


@LINKSTATE.register()
class SrAdjacencyLan(object):
    TLV = 1100

    def __init__(self, flags, sids, weight, undecoded=[]):
        self.flags = flags
        self.sids = sids
        self.weight = weight
        self.undecoded = undecoded

    def __repr__(self):
        return "sr_adj_lan_flags: %s, sids: %s, undecoded_sid: %s" % (self.flags, self.sids, self.undecoded)

    @classmethod
    def unpack(cls, data, length):
        # We only support IS-IS flags for now.
        flags = LsGenericFlags.unpack(data[0:1], LsGenericFlags.ISIS_SR_ADJ_FLAGS)
        # Parse adj weight
        weight = six.indexbytes(data, 1)
        # Move pointer 4 bytes: Flags(1) + Weight(1) + Reserved(2)
        system_id = ISO.unpack_sysid(data[4:10])
        data = data[10:]
        # SID/Index/Label: according to the V and L flags, it contains
        # either:
        # *  A 3 octet local label where the 20 rightmost bits are used for
        # 	 encoding the label value.  In this case the V and L flags MUST
        # 	 be set.
        #
        # *  A 4 octet index defining the offset in the SID/Label space
        # 	 advertised by this router using the encodings defined in
        #  	 Section 3.1.  In this case V and L flags MUST be unset.
        sids = []
        raw = []
        while data:
            # Range Size: 3 octet value indicating the number of labels in
            # the range.
            if int(flags.flags['V']) and int(flags.flags['L']):
                b = BitArray(bytes=data[:3])
                sid = b.unpack('uintbe:24')[0]
                data = data[3:]
                sids.append(sid)
            elif (not flags.flags['V']) and (not flags.flags['L']):
                sid = unpack('!I', data[:4])[0]
                data = data[4:]
                sids.append(sid)
            else:
                raw.append(hexstring(data))
                break

        return cls(flags=flags, sids=sids, weight=weight, undecoded=raw)

    def json(self, compact=None):
        return ', '.join(
            [
                '"sr-adj-lan-flags": {}'.format(self.flags.json()),
                '"sids": {}'.format(json.dumps(self.sids)),
                '"undecoded-sids": {}'.format(json.dumps(self.undecoded)),
                '"sr-adj-lan-weight": {}'.format(json.dumps(self.weight)),
            ]
        )
