import sys
import re
import os
import threading
from collections import defaultdict
from time import time, sleep

candump_re = re.compile(r'(can[^\s]*)\s+([0-9A-Fa-f]+)')

counters = defaultdict(int)
total_msg_counter = 0

last_time = {}
sum_intervals = defaultdict(float)
avg_interval = {}

start_time = time()
lock = threading.Lock()
PRINT_INTERVAL = 0.25

def print_table(repeat = False):
    print("\033[s", end='')
    while (True):
        print("\033[u", end='') 
        sleep(PRINT_INTERVAL)
        os.system('clear')
        with lock:
            elapsed = time() - start_time
            print(f"CAN counter by CAN ID. \nTotal: {total_msg_counter}, Program time: {elapsed:.2f} s\n")
            print(f"{'ID':>9} | {'%':>7} | {'Count':>6} | {'Avg Δt (s)':>10}")
            print("-" * 36)
            for can_id, count in sorted(counters.items()):
                percent = count * 100 / total_msg_counter if total_msg_counter else 0
                avg_dt = avg_interval.get(can_id, 0.0)
                print(f"{can_id:>3}: {percent:7.2f}% {count:6} {avg_dt:10.6f}" + "\033[K")
        if (not repeat):
            break

def read_input():
    global total_msg_counter
    for line in sys.stdin:
        match = candump_re.search(line)
        if not match:
            continue
        can_device = match.group(1)
        can_id = match.group(2).upper()
        can_id = f"{can_device} {can_id}"
        now = time()
        with lock:
            total_msg_counter += 1
            counters[can_id] += 1
            if can_id in last_time:
                interval = now - last_time[can_id]
                sum_intervals[can_id] += interval
                avg_interval[can_id] = sum_intervals[can_id] / counters[can_id]
            else:
                avg_interval[can_id] = 0.0
            last_time[can_id] = now

printer_thread = threading.Thread(target=print_table, daemon=True, kwargs={"repeat": True})
printer_thread.start()

try:
    read_input()
except KeyboardInterrupt:
    print_table()
