
import threading
from collections.abc import Callable
from collections import deque

import numpy as np
from imgui_bundle import immapp, imgui, implot, ImVec2
import hid

from hid_lib import *

'''
Starts a thread to read the periodic data transferred 
'''
class HID_Reader:
    def __init__(self, beyond_hid: hid.device, callback: Callable[[bytes], None]):
        self.hid_dev = beyond_hid
        self.cb = callback
        self.quitting_now = False # used externally to stop the thread
    
    def quit_now(self):
        # Quit the thread 
        self.quitting_now = True

    def start(self):
        # begin the reader thread
        # quit if already started and restart it
        if(hasattr(self, "mthread")):
            if(self.mthread.is_alive()):
                self.quitting_now = True
                self.mthread.join()
        self.mthread = threading.Thread(target=self.threadworker)
        self.quitting_now = False
        self.mthread.start()

    def threadworker(self):
        # continuously check for new HID messages
        while(not self.quitting_now):
            bytesout = bytes(self.hid_dev.read(65, timeout_ms=1))
            if(len(bytesout) > 0):
                self.cb(bytesout)

class my_gui:
    def __init__(self):
        self.prox_entries = deque([0]*1000)
        self.bynd = connect_beyond()
        # bump up the data rate to 100ms
        self.bynd.send_feature_report(bytes([0, HIDCommands.RATE, 0, 100]))
        self.reader = HID_Reader(self.bynd, self.hid_rx_callback)
        self.reader.start()
    def hid_rx_callback(self, newbytes:bytes):
        # decode the data packet
        new_data = decode_data(newbytes)
        # add on the left
        self.prox_entries.appendleft(new_data.prox_distance)
        self.prox_entries.pop()
    def gui(self):
        imgui.text("Controls:")
        
        implot.push_colormap(implot.Colormap_.deep.value)
        plot_height = immapp.em_size() * 30
        if implot.begin_plot("Proximity sensor values", ImVec2(-1, plot_height)):
            implot.setup_axes("Seconds", "Prox Value")
            implot.setup_axes_limits(0, 1000*0.1, 0, 16000)
            lin = np.array(self.prox_entries)
            # lin = np.array([8, 8, 9, 7, 8, 8, 8, 9, 7, 8])
            implot.plot_line("Line", lin, xscale=0.1)
            implot.end_plot()
        

if __name__ == '__main__':
    mgui = my_gui()

    immapp.run(
        gui_function=mgui.gui,  # The Gui function to run
        window_title="Proximity Monitor",  # the window title
        window_size=(640,480),
        # window_size_auto=True,  # Auto size the application window given its widgets
        # Uncomment the next line to restore window position and size from previous run
        # window_restore_previous_geometry==True
        with_implot=True
    )

    mgui.reader.quit_now()