#!/usr/bin/env python3

import requests
import curses
import time
import sys
import traceback
from collections import defaultdict

# API endpoint
URL = "http://localhost:8080/status"
if len(sys.argv) > 1:
    URL = sys.argv[1]

def print_error(stdscr, msg):
    stdscr.erase()
    stdscr.addstr(0, 0, msg)
    stdscr.refresh()

def draw_status(stdscr):
    # Get SvxReflector status
    try:
        r = requests.get(url = URL)
    except requests.exceptions.ConnectionError as e:
        print_error(stdscr, '*** ERROR: ' + str(e))
        return

    if r.status_code != 200:
        print_error(stdscr, '*** ERROR: Could not get ' + URL)
        return

    # Extract data in JSON format
    data = r.json()

    # Get terminal size
    rows, columns = stdscr.getmaxyx()

    # Row format for all table rows
    row_fmt = "%-9s | %8s | %15s | %3s | %s"

    # Sort nodes on talkgroup
    tg2nodes = defaultdict(list)
    for callsign in sorted(data['nodes'].keys()):
        node = data['nodes'][callsign]
        tg = int(node['tg'])
        node['callsign'] = callsign
        tg2nodes[tg].append(node) 

    # Print header line
    header = row_fmt % ("Callsign", "TG#", "RX", "Lev", "Monitored TGs")
    right_txt = "| %d | %s" % (len(data['nodes']), time.ctime())
    nspaces = int(columns) - len(right_txt) - len(header)
    if nspaces > 0:
        header = header + (' ' * nspaces) + right_txt
    stdscr.addstr(0, 0, header, curses.color_pair(3) | curses.A_REVERSE | curses.A_BOLD)

    # Print all node lines
    def print_node_lines():
        line = 1
        for tg in sorted(tg2nodes.keys(), reverse=True):
            node_list = tg2nodes[tg]
            for node in node_list:
                callsign = node['callsign']
                tg = str(node['tg'])
                if 'restrictedTG' in node and bool(node['restrictedTG']):
                    tg = "*" + tg
                monitored_tgs = " ".join(str(tg) for tg in node['monitoredTGs'])
                rx_name = ''
                siglev = ''
                if 'qth' in node and isinstance(node['qth'], list):
                    for qth in node['qth']:
                        qth_name = ''
                        if 'name' in qth:
                            qth_name = ' ' + qth['name']
                        if 'rx' in qth:
                            for rx_id in qth['rx']:
                                rx = qth['rx'][rx_id]
                                if 'active' in rx and rx['active']:
                                    rx_name = rx['name'] + qth_name
                                    siglev = rx['siglev']
                rx_name = rx_name[0:15]
                attrs = curses.color_pair(2)
                if node['isTalker']:
                    attrs = curses.color_pair(1)
                stdscr.addnstr(line, 0, row_fmt % (callsign, tg, rx_name, siglev, monitored_tgs), int(columns)-1, attrs)
                stdscr.clrtoeol()
                if line >= rows-1:
                    return
                line = line + 1
    print_node_lines()
    stdscr.clrtobot()
    stdscr.refresh()


def main(stdscr):
    curses.curs_set(False)
    curses.use_default_colors()
    curses.init_pair(1, curses.COLOR_RED, -1)
    curses.init_pair(2, curses.COLOR_GREEN, -1)
    curses.init_pair(3, curses.COLOR_YELLOW, -1)
    stdscr.timeout(500)

    while True:
        try:
            draw_status(stdscr)
        except:
            stdscr.erase()
            stdscr.addstr(0, 0, traceback.format_exc())
            stdscr.refresh()

        # Read command. Will timeout after the time specified above.
        cmd = stdscr.getch()
        if cmd == ord('q'):
            break;


try:
    curses.wrapper(main)
except KeyboardInterrupt:
    pass
