import struct


def read_dns_name_bytes(byte_array, start, label_store):
    """
    reads a byte array from start until the end of a label and returns
    the 'human' representation. Handles DNS decompression of labels.
    :param byte_array: The packet data in a byte array
    :param start: The offset to start reading this label
    :param label_store: A per packet store of previously seen labels with
           their offsets in the packet data
    :return: tuple of:
            (the current position in the packet data after the label has
             been decoded,
             the human readable (dot notation) query or resource name)
    """

    read_on = True
    buff_indx = start
    labels = list()
    return_parts = list()
    while read_on:
        b1 = byte_array[buff_indx]
        if 1 <= b1 <= 63:
            # This is the first time we have seen this label OR this packet
            # is not using compression.
            c_label = byte_array[buff_indx + 1: buff_indx + 1 + b1].tostring()
            labels.append((buff_indx, c_label, ))
            return_parts.append(c_label)
            buff_indx = buff_indx + b1 + 1
        elif b1 == 0:
            # DNS name is done
            read_on = False
            buff_indx += 1
        else:
            location = struct.unpack("!H",
                                     byte_array[buff_indx: buff_indx + 2])[0]
            buff_indx += 2
            # Strip off the top two bits
            location = location & 0x3fff
            if location in label_store:
                return_parts.append(label_store[location])
                labels.append((location, label_store[location], ))
            else:
                raise ValueError("read_dns_name_bytes encountered unexpected "
                                 "compressed data in byte_array. Array bytes "
                                 "are: {0}".format(byte_array[buff_indx - 2:]))
            # Compressed labels come at the end. We break now
            read_on = False
    for index in range(len(labels)):
        cur_label = '.'.join((x[1] for x in labels[index:]))
        if cur_label not in label_store:
            label_store[cur_label] = labels[index][0]
            label_store[labels[index][0]] = cur_label
        else:
            # Suppose this packet is not using compression? But this
            # is not the first time we have seen this label so move on.
            pass
    return buff_indx, '.'.join(return_parts)