#!/usr/bin/env python

from __future__ import print_function, division
import os
import sys
import time
import argparse
import curses
from threading import Lock
import pyModeS as pms
from pyModeS.extra.tcpclient import BaseClient
from pyModeS.extra.rtlreader import RtlReader
from pyModeS.streamer.stream import Stream
from pyModeS.streamer.screen import Screen

LOCK = Lock()
ADSB_MSG = []
ADSB_TS = []
COMMB_MSG = []
COMMB_TS = []

support_rawtypes = ["raw", "beast", "skysense"]

parser = argparse.ArgumentParser()
parser.add_argument(
    "--source",
    help='Choose data source, "rtlsdr" or "net"',
    required=True,
    default="net",
)
parser.add_argument(
    "--connect",
    help="Define server, port and data type. Supported data types are: %s"
    % support_rawtypes,
    nargs=3,
    metavar=("SERVER", "PORT", "DATATYPE"),
    default=None,
    required=False,
)
parser.add_argument(
    "--latlon",
    help="Receiver latitude and longitude, needed for the surface position, default none",
    nargs=2,
    metavar=("LAT", "LON"),
    default=None,
    required=False,
)
parser.add_argument(
    "--show-uncertainty",
    dest="uncertainty",
    help="Display uncertainty values, default off",
    action="store_true",
    required=False,
    default=False,
)
parser.add_argument(
    "--dumpto",
    help="Folder to dump decoded output, default none",
    required=False,
    default=None,
)
args = parser.parse_args()

SOURCE = args.source
LATLON = args.latlon
UNCERTAINTY = args.uncertainty
DUMPTO = args.dumpto

if SOURCE == "rtlsdr":
    pass
elif SOURCE == "net":
    if args.connect is None:
        print("Error: --connect argument must not be empty.")
    else:
        SERVER, PORT, DATATYPE = args.connect
        if DATATYPE not in support_rawtypes:
            print(
                "Data type not supported, avaiable ones are %s"
                % support_rawtypes
            )

else:
    print('Source must be "rtlsdr" or "net".')
    sys.exit(1)

if DUMPTO is not None:
    # append to current folder except root is given
    if DUMPTO[0] != "/":
        DUMPTO = os.getcwd() + "/" + DUMPTO

    if not os.path.isdir(DUMPTO):
        print("Error: dump folder (%s) does not exist" % DUMPTO)
        sys.exit(1)


class ModesClient(BaseClient):
    def __init__(self, host, port, rawtype):
        super(ModesClient, self).__init__(host, port, rawtype)

    def handle_messages(self, messages):
        local_buffer_adsb_msg = []
        local_buffer_adsb_ts = []
        local_buffer_ehs_msg = []
        local_buffer_ehs_ts = []

        for msg, t in messages:
            if len(msg) < 28:  # only process long messages
                continue

            df = pms.df(msg)

            if df == 17 or df == 18:
                local_buffer_adsb_msg.append(msg)
                local_buffer_adsb_ts.append(t)
            elif df == 20 or df == 21:
                local_buffer_ehs_msg.append(msg)
                local_buffer_ehs_ts.append(t)
            else:
                continue

        LOCK.acquire()
        ADSB_MSG.extend(local_buffer_adsb_msg)
        ADSB_TS.extend(local_buffer_adsb_ts)
        COMMB_MSG.extend(local_buffer_ehs_msg)
        COMMB_TS.extend(local_buffer_ehs_ts)
        LOCK.release()


class ModesRtlReader(RtlReader):
    """docstring for ModesRtlReader."""

    def __init__(self):
        super(ModesRtlReader, self).__init__()

    def handle_messages(self, messages):
        local_buffer_adsb_msg = []
        local_buffer_adsb_ts = []
        local_buffer_ehs_msg = []
        local_buffer_ehs_ts = []

        for msg, t in messages:
            if len(msg) < 28:  # only process long messages
                continue

            df = pms.df(msg)

            if df == 17 or df == 18:
                local_buffer_adsb_msg.append(msg)
                local_buffer_adsb_ts.append(t)
            elif df == 20 or df == 21:
                local_buffer_ehs_msg.append(msg)
                local_buffer_ehs_ts.append(t)
            else:
                continue

        LOCK.acquire()
        ADSB_MSG.extend(local_buffer_adsb_msg)
        ADSB_TS.extend(local_buffer_adsb_ts)
        COMMB_MSG.extend(local_buffer_ehs_msg)
        COMMB_TS.extend(local_buffer_ehs_ts)
        # print(len(ADSB_MSG))
        # print(len(COMMB_MSG))
        LOCK.release()


# redirect all stdout to null, avoiding messing up with the screen
sys.stdout = open(os.devnull, "w")

if SOURCE == "net":
    client = ModesClient(host=SERVER, port=PORT, rawtype=DATATYPE)
    client.daemon = True
    client.start()
elif SOURCE == "rtlsdr":
    rtl = ModesRtlReader()
    # rtl.debug = True
    rtl.daemon = True
    rtl.start()

stream = Stream(latlon=LATLON, dumpto=DUMPTO)

try:
    screen = Screen(uncertainty=UNCERTAINTY)
    screen.daemon = True
    screen.start()

    while True:
        if len(ADSB_MSG) > 1:
            LOCK.acquire()
            stream.process_raw(ADSB_TS, ADSB_MSG, COMMB_TS, COMMB_MSG)
            ADSB_MSG = []
            ADSB_TS = []
            COMMB_MSG = []
            COMMB_TS = []
            LOCK.release()

        acs = stream.get_aircraft()
        try:
            screen.update_data(acs)
            screen.update()
            time.sleep(1)
        except KeyboardInterrupt:
            raise
        except:
            continue

except KeyboardInterrupt:
    sys.exit(0)

finally:
    curses.endwin()
