# Copyright (c) 2021 Satlab A/S <satlab@satlab.com>
# SPDX-License-Identifier: GPL-3.0

import datetime

from gnuradio import gr
import pmt


class PDULogger(gr.basic_block):
    """Log incoming PDUs"""
    def __init__(self, log=None):
        gr.basic_block.__init__(self, name=type(self).__name__, in_sig=[], out_sig=[])
        self.log = log
        self.reset()

        self.message_port_register_in(pmt.intern('rx'))
        self.message_port_register_in(pmt.intern('tx'))
        self.set_msg_handler(pmt.intern('rx'), self.handle_rx_msg)
        self.set_msg_handler(pmt.intern('tx'), self.handle_tx_msg)

    def reset(self):
        self.tx_counter = 0
        self.tx_bytes = 0
        self.rx_counter = 0
        self.rx_bytes = 0
        self.frames = []

    def handle_msg(self, received, msg_pmt):
        meta = pmt.to_python(pmt.car(msg_pmt))
        msg = pmt.cdr(msg_pmt)
        if not pmt.is_u8vector(msg):
            return

        msg_len = len(pmt.u8vector_elements(msg))
        ts = datetime.datetime.utcnow()

        if meta is not None:
            rs_errs = meta.get('rs_errs', 0)
            cc_errs = meta.get('cc_errs', 0)
        else:
            rs_errs = 0
            cc_errs = 0

        if received:
            self.rx_counter += 1
            self.rx_bytes += msg_len
            if self.log is not None:
                self.log.debug(f'RX {self.rx_counter}: {msg_len} bytes ({cc_errs}/{rs_errs})')
        else:
            self.tx_counter += 1
            self.tx_bytes += msg_len
            if self.log is not None:
                self.log.debug(f'TX {self.tx_counter}: {msg_len} bytes')

        self.frames.append((ts, received, msg_len, cc_errs, rs_errs))

    def handle_rx_msg(self, msg_pmt):
        return self.handle_msg(True, msg_pmt)

    def handle_tx_msg(self, msg_pmt):
        return self.handle_msg(False, msg_pmt)

    def get_tx_count(self):
        return self.tx_counter

    def get_tx_bytes(self):
        return self.tx_bytes

    def get_rx_count(self):
        return self.rx_counter

    def get_rx_bytes(self):
        return self.rx_bytes

    def get_frames(self):
        return self.frames
