#!/usr/bin/env python3

from collections import OrderedDict
from contextlib import closing
import json
import math
from urllib.request import urlopen
import sys


BASE_URL = 'http://localhost:8080'


def greatcircle(lat0, lon0, lat1, lon1):
    lat0 = math.radians(lat0)
    lon0 = math.radians(lon0)
    lat1 = math.radians(lat1)
    lon1 = math.radians(lon1)

    # avoid NaN
    if abs(lat0 - lat1) < 0.0001 and abs(lon0 - lon1) < 0.0001:
        return 0.0

    return 6371e3 * math.acos(math.sin(lat0) * math.sin(lat1) + math.cos(lat0) * math.cos(lat1) * math.cos(abs(lon0 - lon1)))


def config_stats():
    print('graph_title dump1090 Message Statistics')
    print('graph_vlabel messages per ${graph_period}')
    print('graph_category sensors')
    print('graph_args --base 1000')
    fields = OrderedDict()
    fields['mode_s_local'] = "Mode S Local"
    fields['mode_ac_local'] = "Mode AC Local"
    fields['mode_s_remote'] = "Mode S Remote"
    fields['mode_ac_remote'] = "Mode AC Remote"
    fields['positions'] = "Positions * 10"
    fields['strong_signal_local'] = "Strong (>-3dBFS) * 10"
    for name, label in fields.items():
        print('%s.label %s' % (name, label))
        print('%s.type DERIVE' % name)
        print('%s.min 0' % name)
    fields['strong_signal_local'] = "Strong Signal (>-3dBFS)"
    print('mode_ac_local.graph no')
    print('mode_ac_remote.graph no')
    for name in ('positions', 'strong_signal_local'):
        print('%s.cdef %s,10,*' % (name, name))


def config_tracks():
    print('graph_title dump1090 Tracks')
    print('graph_vlabel tracks per ${graph_period}')
    print('graph_category sensors')
    print('graph_period hour')
    print('graph_args --base 1000 --lower-limit 0')
    fields = OrderedDict()
    fields['tracks'] = "Tracks"
    fields['tracks_single'] = "Tracks (single position)"
    for name, label in fields.items():
        print('%s.label %s' % (name, label))
        print('%s.type DERIVE' % name)
        print('%s.min 0' % name)


def config_aircraft():
    print('graph_title dump1090 Aircraft')
    print('graph_vlabel Aircraft')
    print('graph_category sensors')
    print('graph_args --base 1000 --lower-limit 0')
    print('aircraft_total.label Aircraft (total)')
    print('aircraft_total.draw AREA')
    print('aircraft_position.label Aircraft (w/ position)')
    print('aircraft_adsb.label Aircraft (ADS-B)')
    print('aircraft_mlat.label Aircraft (MLAT)')


def config_distance():
    print('graph_title dump1090 Distance')
    print('graph_vlabel Distance (NM)')
    print('graph_category sensors')
    print('graph_args --base 1000 --lower-limit 0')
    print('graph_args_after ' + ' '.join([
        '"LINE1:a87c5bd0e89d8182#00CC00:Max Dist (ADS-B) "',
        '"GPRINT:a87c5bd0e89d8182:LAST:%6.2lf%s"',
        '"GPRINT:a87c5bd0e89d8182:MIN:%6.2lf%s"',
        '"GPRINT:a87c5bd0e89d8182:AVERAGE:%6.2lf%s"',
        '"GPRINT:a87c5bd0e89d8182:MAX:%6.2lf%s\\\\j"',
        '"LINE1:ad50975a7d027257#0066B3:Max Dist (MLAT)  "',
        '"GPRINT:ad50975a7d027257:LAST:%6.2lf%s"',
        '"GPRINT:ad50975a7d027257:MIN:%6.2lf%s"',
        '"GPRINT:ad50975a7d027257:AVERAGE:%6.2lf%s"',
        '"GPRINT:ad50975a7d027257:MAX:%6.2lf%s\\\\j"'
    ]))
    print('distance_max_meters.label Distance (ADS-B)')
    print('distance_max_meters.cdef distance_max_meters,1852,/')
    print('distance_max_meters.draw LINE0.01')
    print('distance_max_meters_mlat.label Distance (MLAT)')
    print('distance_max_meters_mlat.cdef distance_max_meters_mlat,1852,/')
    print('distance_max_meters_mlat.draw LINE0.01')


def fetch_stats():
    response = urlopen(BASE_URL + '/data/stats.json', None, 5.0).read().decode('utf-8')
    stats = json.loads(response)['total']

    if 'local' in stats:
        print('mode_s_local.value %d' % sum(stats['local']['accepted']))
        print('mode_ac_local.value %d' % stats['local']['modeac'])
        print('strong_signal_local.value %d' % stats['local']['strong_signals'])
    if 'remote' in stats:
        print('mode_s_remote.value %d' % sum(stats['remote']['accepted']))
        print('mode_ac_remote.value %d' % stats['remote']['modeac'])
    if 'cpr' in stats:
        print('positions.value %d' % (stats['cpr']['global_ok'] + stats['cpr']['local_ok'],))


def fetch_tracks():
    response = urlopen(BASE_URL + '/data/stats.json', None, 5.0).read().decode('utf-8')
    stats = json.loads(response)['total']

    if 'tracks' in stats:
        print('tracks.value %d' % stats['tracks']['all'])
        print('tracks_single.value %d' % stats['tracks']['single_message'])


def fetch_aircraft():
    response = urlopen(BASE_URL + '/data/aircraft.json', None, 5.0).read().decode('utf-8')
    aircraft = json.loads(response)['aircraft']

    total = 0
    with_pos = 0
    adsb = 0
    mlat = 0
    for plane in aircraft:
        if plane['seen'] < 30.0:
            total += 1
        if plane.get('seen_pos', 3600.0) < 30.0:
            with_pos += 1
            if 'lat' in plane.get('mlat', ()):
                mlat += 1
            else:
                adsb += 1

    print('aircraft_total.value %d' % total)
    print('aircraft_position.value %d' % with_pos)
    print('aircraft_adsb.value %d' % adsb)
    print('aircraft_mlat.value %d' % mlat)


def fetch_distance():
    response = urlopen(BASE_URL + '/data/receiver.json', None, 5.0).read().decode('utf-8')
    receiver = json.loads(response)
    rlat = None
    rlon = None
    if 'lat' in receiver:
        rlat = receiver['lat']
        rlon = receiver['lon']

    response = urlopen(BASE_URL + '/data/aircraft.json', None, 5.0).read().decode('utf-8')
    aircraft = json.loads(response)['aircraft']

    max_adsb = -1.0
    max_mlat = -1.0
    for plane in aircraft:
        if 'lat' in plane and plane.get('seen_pos', 3600.0) < 30.0:
            distance = greatcircle(rlat, rlon, plane['lat'], plane['lon'])
            if 'lat' in plane.get('mlat', ()):
                max_mlat = max(max_mlat, distance)
            else:
                max_adsb = max(max_adsb, distance)

    if max_adsb < 0.0:
        max_adsb = 'U'
    if max_mlat < 0.0:
        max_mlat = 'U'
    print('distance_max_meters.value %s' % max_adsb)
    print('distance_max_meters_mlat.value %s' % max_mlat)


if __name__ == '__main__':
    cmd = sys.argv[0]
    if len(sys.argv) > 1 and sys.argv[1] == 'config':
        if cmd.endswith('_stats'):
            config_stats()
        elif cmd.endswith('_tracks'):
            config_tracks()
        elif cmd.endswith('_aircraft'):
            config_aircraft()
        elif cmd.endswith('_distance'):
            config_distance()
        else:
            sys.exit(1)
    else:
        if cmd.endswith('_stats'):
            fetch_stats()
        elif cmd.endswith('_tracks'):
            fetch_tracks()
        elif cmd.endswith('_aircraft'):
            fetch_aircraft()
        elif cmd.endswith('_distance'):
            fetch_distance()
        else:
            sys.exit(1)
