import math
from collections import Counter
from math import log
from pathlib import Path
from types import SimpleNamespace

import construct as c
import schemas_ping2
from schemas_ping2 import parse_nmea, parse_nmea_rmc
import matplotlib.pyplot as plt
import numpy as np

def from_construct(a_construct):
    if isinstance(a_construct, c.ListContainer):
        return list(from_construct(i) for i in a_construct)
    if isinstance(a_construct, c.Container):
        if set(a_construct.keys()) == {
            'data', 'value', 'offset1', 'offset2', 'length'
        }:
            return from_construct(a_construct.value)
        return SimpleNamespace(**{
            k: from_construct(v) for k, v in a_construct.items() if k != '_io'
        })
    else:
        return a_construct


if __name__ == '__main__':
    # filename = Path('data','noise.ping_packets')
    # filename = Path('data', 'good barge at 25m.ping_packets')
    filename = Path('data', 'Ping2-Fri Sep 27 16-34-30 2019-10.ping_packets')

    parsed = c.GreedyRange(schemas_ping2.ping_schema).parse_file(filename)

    ping_packets = from_construct(parsed)
    # talkers = Counter()
    # sentences = Counter()
    # talker_sentences = Counter()
    #
    # for pkt in ping_packets:
    #     if pkt.message_id == schemas_ping2.message_id_schema.NMEA0183:
    #         nmea = parse_nmea(pkt.payload)
    #         talkers[nmea.talker_id] += 1
    #         sentences[nmea.sentence_id] += 1
    #         talker_sentences[nmea.talker_id + nmea.sentence_id] += 1
    #
    #         if nmea.sentence_id == 'RMC':
    #             print(parse_nmea_rmc(nmea.words))
    #
    # print(f'nmea talkers: {talkers}')
    # print(f'nmea sentences: {sentences}')
    # print(f'talker sentences: {talker_sentences}')

    # nmea talkers: Counter({'GN': 13, 'GP': 9, 'GL': 6})
    # nmea sentences: Counter({'GSV': 15, 'GSA': 5, 'GLL': 2, 'RMC': 2, 'VTG': 2, 'GGA': 2})
    # GGA = Global Positioning System Fix Data. Time, Position and fix
    #       related data for a GPS receiver
    # GLL = Geographic Position – Latitude/Longitude
    #       useful!
    # GSV:  Satellites in view - don't care
    # RMC = Recommended Minimum Navigation Information
    #       useful!
    # GSA = GPS DOP and active satellites
    # VTG = Track Made Good and Ground Speed
    #       useful!

    # probably only need rmc

    p6_packets = [from_construct(schemas_ping2.profile6_schema.parse(
        pkt.payload
    )) for pkt in ping_packets if
        pkt.message_id == schemas_ping2.message_id_schema.PROFILE6]

    min_time = p6_packets[0].timestamp_msec / 1000
    max_time = p6_packets[-1].timestamp_msec / 1000
    if not (min_time < max_time):
        min_time = 0
        max_time = 0.1 * len(p6_packets)
    n_time = len(p6_packets)
    min_dist_mm = min(p6.start_mm for p6 in p6_packets)
    max_dist_mm = max(p6.start_mm + p6.length_mm for p6 in p6_packets)
    n_dist = 1000

    imdata = []

    for p6 in p6_packets:
        db = schemas_ping2.get_ranges_db(p6)
        imrow = np.interp(
            np.linspace(min_dist_mm, max_dist_mm, n_dist),
            np.linspace(p6.start_mm, p6.start_mm + p6.length_mm, len(db)),
            db
        )
        imdata.append(imrow)
    x = np.shape(imdata)

    im = plt.pcolormesh(
        np.linspace(min_dist_mm, max_dist_mm, n_dist) / 1000,
        np.linspace(min_time, max_time, n_time),
        imdata,
        # cmap='ocean'
    )
    plt.title(filename)
    plt.colorbar().set_label('decibels')
    plt.xlabel('distance (meters)')
    plt.ylabel('time (seconds)')

    plt.show()