def on_send_gap(match, state, logger):
    """It happens when the writer send a GAP message."""
    writer_oid = get_oid(match[0])
    remote_part = parse_guid(state, match[1], match[2], match[3])
    reader_oid = get_oid(match[4])
    sn_start = parse_sn(match[5])
    sn_end = parse_sn(match[6]) - 1
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send(
        remote_part, writer_oid,
        "Sent GAP to reader %s for samples in [%d, %d]" %
        (reader_oid, sn_start, sn_end), verb)
    add_statistics_packet(writer_oid, 'send', 'GAP', state)

    # Check for large sequence number issues.
    if sn_end - sn_start >= (1 << 31):
        logger.warning("[LP-1] Large Sequence Number difference in GAP")

    # Check for reliable packet lost
    if 'packets_lost' not in state:
        return
    losts = []
    for k in state['packets_lost']:
        info = k.split("-")
        oid = info[0]
        seqnum = int(info[1])
        if oid == writer_oid and seqnum >= sn_start and seqnum < sn_end:
            logger.warning("DATA [%d] may have been lost" % seqnum)
            losts.append(k)
    for k in losts:
        state['packets_lost'].remove(k)
def on_send_gap(match, state, logger):
    """It happens when the writer send a GAP message."""
    writer_oid = get_oid(match[0])
    remote_part = parse_guid(state, match[1], match[2], match[3])
    reader_oid = get_oid(match[4])
    sn_start = parse_sn(match[5])
    sn_end = parse_sn(match[6]) - 1
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send(remote_part, writer_oid,
                "Sent GAP to reader %s for samples in [%d, %d]" %
                (reader_oid, sn_start, sn_end), verb)
    add_statistics_packet(writer_oid, 'send', 'GAP', state)

    # Check for large sequence number issues.
    if sn_end - sn_start >= (1 << 31):
        logger.warning("[LP-1] Large Sequence Number difference in GAP")

    # Check for reliable packet lost
    if 'packets_lost' not in state:
        return
    losts = []
    for k in state['packets_lost']:
        info = k.split("-")
        oid = info[0]
        seqnum = int(info[1])
        if oid == writer_oid and seqnum >= sn_start and seqnum < sn_end:
            logger.warning("DATA [%d] may have been lost" % seqnum)
            losts.append(k)
    for k in losts:
        state['packets_lost'].remove(k)
def on_send_hb_response(match, state, logger):
    """It happens when sending a HB to verify GAP."""
    writer_oid = get_oid(match[0])
    sn_end = parse_sn(match[1])
    sn_start = parse_sn(match[2])
    epoch = int(match[3])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send(
        "", writer_oid, "Sent HB [%d] to verify GAP for samples in [%d, %d]" %
        (epoch, sn_start, sn_end), verb)
def on_send_periodic_hb(match, state, logger):
    """It happens when sending a periodic HB message."""
    writer_oid = get_oid(match[0])
    sn_start = parse_sn(match[1])
    sn_end = parse_sn(match[2])
    epoch = int(match[3])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send(
        "", writer_oid, "Sent periodic HB [%d] for samples in [%d, %d]" %
        (epoch, sn_start, sn_end), verb)
def on_send_preemptive_hb(match, state, logger):
    """It happens when sending a preemptive HB message."""
    writer_oid = get_oid(match[0])
    sn_start = parse_sn(match[1])
    sn_end = parse_sn(match[2])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send(
        "", writer_oid,
        "Sent preemptive HB to let know about samples in [%d, %d]" %
        (sn_start, sn_end), verb)
def on_send_piggyback_hb(match, state, logger):
    """It happens when sending a piggyback HB message."""
    writer_oid = get_oid(match[0])
    sn_first = parse_sn(match[1])
    sn_last = parse_sn(match[2])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send("", writer_oid,
                "Sent piggyback HB to acknowledge samples in [%d, %d]" %
                (sn_first, sn_last), verb)
    add_statistics_packet(writer_oid, "send", "PIGGYBACK HB", state)
def on_send_piggyback_hb(match, state, logger):
    """It happens when sending a piggyback HB message."""
    writer_oid = get_oid(match[0])
    sn_first = parse_sn(match[1])
    sn_last = parse_sn(match[2])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send(
        "", writer_oid,
        "Sent piggyback HB to acknowledge samples in [%d, %d]" %
        (sn_first, sn_last), verb)
    add_statistics_packet(writer_oid, "send", "PIGGYBACK HB", state)
def on_send_periodic_hb(match, state, logger):
    """It happens when sending a periodic HB message."""
    writer_oid = get_oid(match[0])
    sn_start = parse_sn(match[1])
    sn_end = parse_sn(match[2])
    epoch = int(match[3])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send("", writer_oid,
                "Sent periodic HB [%d] for samples in [%d, %d]" %
                (epoch, sn_start, sn_end),
                verb)
def on_send_preemptive_hb(match, state, logger):
    """It happens when sending a preemptive HB message."""
    writer_oid = get_oid(match[0])
    sn_start = parse_sn(match[1])
    sn_end = parse_sn(match[2])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send("",
                writer_oid,
                "Sent preemptive HB to let know about samples in [%d, %d]" %
                (sn_start, sn_end),
                verb)
def on_send_hb_response(match, state, logger):
    """It happens when sending a HB to verify GAP."""
    writer_oid = get_oid(match[0])
    sn_end = parse_sn(match[1])
    sn_start = parse_sn(match[2])
    epoch = int(match[3])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send("",
                writer_oid,
                "Sent HB [%d] to verify GAP for samples in [%d, %d]" %
                (epoch, sn_start, sn_end),
                verb)
def on_send_piggyback_hb_syncrepair(match, state, logger):
    """It happens when sending a piggyback HB message from repair."""
    writer_oid = get_oid(match[0])
    sn_first = parse_sn(match[1])
    sn_last = parse_sn(match[2])
    epoch = int(match[3])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send(
        "", writer_oid,
        ("Sent piggyback HB [%d] from synchronous reparation" % epoch) +
        " to acknowledge samples in [%d, %d]" % (sn_first, sn_last), verb)
    add_statistics_packet(writer_oid, "send", "PIGGYBACK HB", state)
def on_received_gap(match, state, logger):
    """It happens when the reader receives a GAP."""
    reader_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    lead = parse_sn(match[2])
    bitcount = int(match[3])
    remote = match[4].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.recv(
        writer_addr, reader_oid,
        "Received GAP from writer %s for [%d, %d] (+%d)" %
        (writer_oid, seqnum, lead, bitcount), verb)
def on_send_piggyback_hb_syncrepair(match, state, logger):
    """It happens when sending a piggyback HB message from repair."""
    writer_oid = get_oid(match[0])
    sn_first = parse_sn(match[1])
    sn_last = parse_sn(match[2])
    epoch = int(match[3])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send("",
                writer_oid,
                ("Sent piggyback HB [%d] from synchronous reparation"
                 % epoch) + " to acknowledge samples in [%d, %d]"
                % (sn_first, sn_last),
                verb)
    add_statistics_packet(writer_oid, "send", "PIGGYBACK HB", state)
def on_received_gap(match, state, logger):
    """It happens when the reader receives a GAP."""
    reader_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    lead = parse_sn(match[2])
    bitcount = int(match[3])
    remote = match[4].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.recv(writer_addr,
                reader_oid,
                "Received GAP from writer %s for [%d, %d] (+%d)" %
                (writer_oid, seqnum, lead, bitcount),
                verb)
def on_receive_hb(match, state, logger):
    """It happens when the write receives a HB."""
    reader_oid = get_oid(match[0])
    packet = match[1]
    sn_start = parse_sn(match[2])
    sn_end = parse_sn(match[3])
    epoch = int(match[4])
    remote = match[5].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.recv(
        writer_addr, reader_oid,
        "Received %s [%d] from writer %s for samples in [%d, %d]" %
        (packet, epoch, writer_oid, sn_start, sn_end), verb)
def on_receive_data(match, state, logger):
    """It happens when the reader receives data."""
    comm = "best-effort" if match[0] == "Be" else "reliable"
    reader_oid = get_oid(match[1])
    packet = match[2]
    seqnum = parse_sn(match[3], 16 if match[0] == "Be" else 10)
    remote = match[5].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    packet = get_data_packet_name(remote[3]) if packet == "DATA" else packet

    # Sequece number check
    full_id = writer_addr + "." + writer_oid + ' to ' + reader_oid
    if 'last_sn' not in state:
        state['last_sn'] = {}
    if full_id in state['last_sn']:
        prev_seqnum = state['last_sn'][full_id]
        diff = seqnum - prev_seqnum
        # Add a warning message per missing packet to have a good count in
        # the warning summary.
        for _ in range(diff - 1):
            logger.warning("Missing sample from %s" % full_id)
    if full_id not in state['last_sn'] or state['last_sn'][full_id] < seqnum:
        state['last_sn'][full_id] = seqnum

    # Show the message after any possible warning.
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.recv(writer_addr, reader_oid,
                "Received %s [%d] from writer %s (%s)" %
                (packet, seqnum, writer_oid, comm),
                verb)
def on_receive_data(match, state, logger):
    """It happens when the reader receives data."""
    comm = "best-effort" if match[0] == "Be" else "reliable"
    reader_oid = get_oid(match[1])
    packet = match[2]
    seqnum = parse_sn(match[3], 16 if match[0] == "Be" else 10)
    remote = match[5].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    packet = get_data_packet_name(remote[3]) if packet == "DATA" else packet

    # Sequece number check
    full_id = writer_addr + "." + writer_oid + ' to ' + reader_oid
    if 'last_sn' not in state:
        state['last_sn'] = {}
    if full_id in state['last_sn']:
        prev_seqnum = state['last_sn'][full_id]
        diff = seqnum - prev_seqnum
        # Add a warning message per missing packet to have a good count in
        # the warning summary.
        for _ in range(diff - 1):
            logger.warning("Missing sample from %s" % full_id)
    if full_id not in state['last_sn'] or state['last_sn'][full_id] < seqnum:
        state['last_sn'][full_id] = seqnum

    # Show the message after any possible warning.
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.recv(
        writer_addr, reader_oid, "Received %s [%d] from writer %s (%s)" %
        (packet, seqnum, writer_oid, comm), verb)
def on_receive_hb(match, state, logger):
    """It happens when the write receives a HB."""
    reader_oid = get_oid(match[0])
    packet = match[1]
    sn_start = parse_sn(match[2])
    sn_end = parse_sn(match[3])
    epoch = int(match[4])
    remote = match[5].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.recv(writer_addr,
                reader_oid,
                "Received %s [%d] from writer %s for samples in [%d, %d]" %
                (packet, epoch, writer_oid, sn_start, sn_end),
                verb)
def on_send_nack_frag(match, state, logger):
    """It happens when sending a NACK_FRAG."""
    reader_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send("", reader_oid,
                "Sent NACK_FRAG for sample %d" % seqnum,
                verb)
def on_receive_fragment(match, state, logger):
    """It happens when a DATA fragment is received."""
    reader_oid = get_oid(match[0])
    frag_start = int(match[1])
    frag_end = int(match[2])
    seqnum = parse_sn(match[3])
    logger.recv(
        "", reader_oid, "Received DATA fragments %d to %d for sample %d" %
        (frag_start, frag_end, seqnum))
def on_receive_fragment(match, state, logger):
    """It happens when a DATA fragment is received."""
    reader_oid = get_oid(match[0])
    frag_start = int(match[1])
    frag_end = int(match[2])
    seqnum = parse_sn(match[3])
    logger.recv("", reader_oid,
                "Received DATA fragments %d to %d for sample %d" %
                (frag_start, frag_end, seqnum))
def on_send_data(match, state, logger):
    """It happens when a DATA packet is sent."""
    writer_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    logger.send("", writer_oid, "Sent DATA [%d]" % seqnum)
    add_statistics_packet(writer_oid, "send", "DATA", state)

    key = writer_oid + "-" + str(seqnum)
    if 'packets_lost' in state and key in state['packets_lost']:
        state['packets_lost'].remove(key)
def on_send_data(match, state, logger):
    """It happens when a DATA packet is sent."""
    writer_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    logger.send("", writer_oid, "Sent DATA [%d]" % seqnum)
    add_statistics_packet(writer_oid, "send", "DATA", state)

    key = writer_oid + "-" + str(seqnum)
    if 'packets_lost' in state and key in state['packets_lost']:
        state['packets_lost'].remove(key)
def on_resend_data(match, state, logger):
    """It happens when the writer resend a DATA message."""
    writer_oid = get_oid(match[0])
    packet_name = get_data_packet_name(match[0])
    remote_part = parse_guid(state, match[1], match[2], match[3])
    remote_oid = get_oid(match[4])
    seqnum = parse_sn(match[5])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send(
        remote_part, writer_oid,
        "Resent %s [%d] to reader %s" % (packet_name, seqnum, remote_oid),
        verb)
def on_resend_data(match, state, logger):
    """It happens when the writer resend a DATA message."""
    writer_oid = get_oid(match[0])
    packet_name = get_data_packet_name(match[0])
    remote_part = parse_guid(state, match[1], match[2], match[3])
    remote_oid = get_oid(match[4])
    seqnum = parse_sn(match[5])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send(remote_part, writer_oid,
                "Resent %s [%d] to reader %s"
                % (packet_name, seqnum, remote_oid),
                verb)
def on_receive_out_order_data(match, state, logger):
    """It happens when the received data sequence number isn't contiguous."""
    reader_oid = get_oid(match[0])
    kind = "old" if match[1] == "old" else "future"
    seqnum = parse_sn(match[2])
    remote = match[3].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    packet_name = get_data_packet_name(remote[3])
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.recv(
        writer_addr, reader_oid, "Received %s %s [%d] from writer %s" %
        (kind, packet_name, seqnum, writer_oid), verb)
def on_send_ack(match, state, logger):
    """It happens when a ACK message is sent."""
    reader_oid = get_oid(match[0])
    lead = parse_sn(match[1])
    bitcount = int(match[2])
    epoch = int(match[3])
    remote = match[4].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.send(
        writer_addr, reader_oid, "Sent ACK [%d] to writer %s for %d count %d" %
        (epoch, writer_oid, lead, bitcount), verb)
def on_schedule_data(match, state, logger):
    """It happens when a data is asynchronously scheduled."""
    writer_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    logger.process("", writer_oid, "Scheduled DATA [%d]" % seqnum)

    if 'packets_lost' not in state:
        state['packets_lost'] = []
    key = writer_oid + "-" + str(seqnum)
    if key in state['packets_lost']:
        state['packets_lost'].remove(key)
    else:
        state['packets_lost'].append(key)
def on_schedule_data(match, state, logger):
    """It happens when a data is asynchronously scheduled."""
    writer_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    logger.process("", writer_oid, "Scheduled DATA [%d]" % seqnum)

    if 'packets_lost' not in state:
        state['packets_lost'] = []
    key = writer_oid + "-" + str(seqnum)
    if key in state['packets_lost']:
        state['packets_lost'].remove(key)
    else:
        state['packets_lost'].append(key)
def on_receive_out_order_data(match, state, logger):
    """It happens when the received data sequence number isn't contiguous."""
    reader_oid = get_oid(match[0])
    kind = "old" if match[1] == "old" else "future"
    seqnum = parse_sn(match[2])
    remote = match[3].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    packet_name = get_data_packet_name(remote[3])
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.recv(writer_addr, reader_oid, "Received %s %s [%d] from writer %s" %
                (kind, packet_name, seqnum, writer_oid),
                verb)
def on_receive_ack(match, state, logger):
    """It happens when receiving an ACK message."""
    writer_oid = get_oid(match[0])
    remote = match[1].split('.')
    reader_addr = parse_guid(state, remote[0], remote[1], remote[2])
    reader_oid = get_oid(remote[3])
    seqnum = parse_sn(match[2])
    bitcount = int(match[3])
    epoch = int(match[4])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.recv(
        reader_addr, writer_oid,
        "Received ACKNACK [%d] from reader %s for %d +%d" %
        (epoch, reader_oid, seqnum, bitcount), verb)
def on_send_nack(match, state, logger):
    """It happens when a NACK message is sent."""
    reader_oid = get_oid(match[0])
    lead = parse_sn(match[1])
    bitcount = int(match[2])
    epoch = int(match[3])
    remote = match[4].split('.')
    writer_addr = parse_guid(state, remote[0], remote[1], remote[2])
    writer_oid = get_oid(remote[3])
    verb = 1 if is_builtin_entity(remote[3]) else 0
    logger.send(writer_addr,
                reader_oid,
                "Sent NACK [%d] to writer %s for %d count %d" %
                (epoch, writer_oid, lead, bitcount),
                verb)
def on_receive_ack(match, state, logger):
    """It happens when receiving an ACK message."""
    writer_oid = get_oid(match[0])
    remote = match[1].split('.')
    reader_addr = parse_guid(state, remote[0], remote[1], remote[2])
    reader_oid = get_oid(remote[3])
    seqnum = parse_sn(match[2])
    bitcount = int(match[3])
    epoch = int(match[4])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.recv(reader_addr,
                writer_oid,
                "Received ACKNACK [%d] from reader %s for %d +%d" %
                (epoch, reader_oid, seqnum, bitcount),
                verb)
def on_complete_fragment(match, state, logger):
    """It happens when the fragment is complete."""
    reader_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    logger.process("", reader_oid, "Fragmented sample %d is complete" % seqnum)
def on_rejected_data(match, state, logger):
    """It happens when the reader rejects data."""
    seqnum = parse_sn(match[0])
    logger.process("", "", "Reader rejected DATA (%d)" % seqnum)
    logger.warning("A DataReader rejected sample %d" % seqnum)
def on_accept_data(match, state, logger):
    """It happens when the reader accepts data."""
    seqnum = parse_sn(match[0])
    logger.process("", "", "Reader accepted DATA (%d)" % seqnum, 1)
def on_complete_fragment(match, state, logger):
    """It happens when the fragment is complete."""
    reader_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    logger.process("", reader_oid,
                   "Fragmented sample %d is complete" % seqnum)
def on_accept_data(match, state, logger):
    """It happens when the reader accepts data."""
    seqnum = parse_sn(match[0])
    logger.process("", "", "Reader accepted DATA (%d)" % seqnum, 1)
def on_rejected_data(match, state, logger):
    """It happens when the reader rejects data."""
    seqnum = parse_sn(match[0])
    logger.process("", "", "Reader rejected DATA (%d)" % seqnum)
    logger.warning("A DataReader rejected sample %d" % seqnum)
def on_send_nack_frag(match, state, logger):
    """It happens when sending a NACK_FRAG."""
    reader_oid = get_oid(match[0])
    seqnum = parse_sn(match[1])
    verb = 1 if is_builtin_entity(match[0]) else 0
    logger.send("", reader_oid, "Sent NACK_FRAG for sample %d" % seqnum, verb)