from .associable import Associable
class Bus(Associable):
    def __init__(self, bit_type, name, width, associate_with = None):
        Associable.__init__(self, associate_with)
        self.__name = name
        self.__type = bit_type

        if isinstance(width, tuple):
            self.__msb = max(width)
            self.__lsb = min(width)
        elif isinstance(width, int):
            self.__msb = width-1
            self.__lsb = 0
        else:
            raise Exception('type of width unsupported - should be tuple or int')

        self.associate(associate_with)

        self.__bits = [None] * self.width()

        for i in self.indices():
            self.set_bit(i, self.__type(name + '[' + str(i) + ']', self))

    def get_name(self):
        return self.__name

    def msb(self):
        return self.__msb

    def lsb(self):
        return self.__lsb

    def width(self):
        return (self.msb() - self.lsb() + 1)

    def indices(self):
        return range(self.lsb(), self.msb() + 1)

    def set_bit(self, i, obj):
        if obj.is_associated() and obj.associated_with() != self:
            raise Exception('bit should be associated with bus')
        else:
            obj.associate(self)

        if self.__type != type(obj):
            raise Exception('added bit should be of same type as bus')

        self.__bits[i] = obj

    def verilog_type(self):
        return self.get_bit(self.lsb()).verilog_type()

    def verilog_port_list(self, p):
        if p is self.get_bit(self.lsb()):
            return self.__name
        else:
            return None

    def verilog_declare(self, p):
        if p is self.get_bit(self.lsb()):
            return self.verilog_type() + ' [' + str(self.msb()) + ':' + str(self.lsb()) + '] ' + self.__name + ';'
        else:
            return None
        

    def get_bit(self, i):
        return self.__bits[i]

    def all_bits(self):
        return (self.get_bit(i) for i in sorted(self.indices(), reverse=True))
