'''
/** 
 * Original work Copyright 2024 damiano IU3QGD
 * https://to-be-defined
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.

 * Addition to the licence: NO company with more than 50employees can use this SW and you are NOT entitled to store this software 
 * on ANY storage that in some way attempts to monetize it (eg: github)
 * corporations and banks are too rich and too powerful, they MUST be split and ALL the money given back to the state

Show radio counters, to find out possible problems...
  
''' 

from __future__ import annotations

import struct
from tkinter import ttk, messagebox
import typing

from app_csv import CsvTable
from glob_gui import JtkTableColdef, JtkTable, JtkPanelPackLeft, JtkPanelPackTop
from glob_ippqs import Qsk5_req_radio_poll, Qsk5_res_Counters
import qpystat


# The # type: ignore is for mypy to stop complaining that it cannot find the correct tyep
qcountcol_idx="qcountcol_idx"
qcountcol_csize="qcountcol_csize"
qcountcol_vname="qcountcol_vname"
qcountcol_cvalue="qcountcol_cvalue"
qcountcol_cdesc="qcountcol_cdesc"
     
# -------------------------------------------------------
# Generic way to define a map from a column name to some properties        
qcountcol_map = { 
    qcountcol_idx        : JtkTableColdef(qcountcol_idx    ,'Nr.',True, 40), 
    qcountcol_csize      : JtkTableColdef(qcountcol_csize  ,"Size",True,40),
    qcountcol_vname      : JtkTableColdef(qcountcol_vname  ,"Var Name",False,300),
    qcountcol_cvalue     : JtkTableColdef(qcountcol_cvalue ,"Value",True,100),
    qcountcol_cdesc      : JtkTableColdef(qcountcol_cdesc  ,"Description",False, 500),
    }

# =====================================================================
# Need a button to request the counters and a way to update the table
class Qcounters_gui ():

    # ----------------------------------------------------------------
    def __init__(self, stat : qpystat.Qpystat, parent_frame : ttk.Widget ):
        self.stat = stat

        self._work_panel = ttk.Frame(parent_frame)
        
        self._qcounters_list : qcounters_list = qcounters_list()
        
        c_panel=self._newCenterPanel(self._work_panel)
        
        c_panel.pack(fill='both', expand=True)


    # ------------------------------------------------------------------------
    def getWorkPanel(self) -> ttk.Frame:
        return self._work_panel
        
    # ------------------------------------------------------------------------
    def _println(self, msg : str ):
        self.stat.app_println(msg)
        
    # -------------------------------------------------------------------------------
    # On center panel there is the table and scroll bar
    # NOTE: The layout of this is described by caller
    # https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/ttk-Treeview.html
    def _newCenterPanel(self, parent_panel):
        a_panel = JtkPanelPackTop(parent_panel)
        
        a_panel.addItem(self._newButtonsPanel(a_panel))
        
        self._table_view = JtkTable(a_panel, qcountcol_map );
        a_panel.addItem(self._table_view.getComponent(),fill='both',expand=True)
        
        return a_panel

    
    # -------------------------------------------------------------------------------
    def _newButtonsPanel(self, parent_panel) -> ttk.Frame:
        a_panel = JtkPanelPackLeft(parent_panel)

        a_panel.addItem(ttk.Button(a_panel,text='Get Counters',command=self._clickGetCounters))
        
        return a_panel
        

    # -------------------------------------------------------------------------------
    def _clickGetCounters(self):
        a_req = Qsk5_req_radio_poll(0b1000) 
        self.stat.qconnect.queuePut(a_req)

    # ------------------------------------------------------------------------
    def showInfo(self, a_message : str ):
        messagebox.showinfo("Counters message", a_message, parent=self._work_panel, type='ok')    
        
    # ------------------------------------------------------------------------
    # w_size = struct.calcsize(a_format)
    # struct.unpack(a_format, self.ee_bytearray[start_from:start_from+w_size])

    def parse_chunk(self, chunk : Qsk5_res_Counters):
        

        a_byteb = chunk.c_struct
        
        r_index=0;
        
        for row in self._qcounters_list.qcounters_list:
            e_row : Qcounters_row = row
            
            if e_row.c_size_b == 1:
                a_list = struct.unpack_from('B',a_byteb,r_index)
                e_row.c_value = a_list[0]
                r_index += 1
            elif e_row.c_size_b == 2:
                a_list = struct.unpack_from('H',a_byteb,r_index)
                e_row.c_value = a_list[0]
                r_index += 2
            else:
                self._println("UNSUPPORTED "+str(e_row.v_name))
                
        
        self._work_panel.after_idle(self.GUI_refresh)




    # -------------------------------------------------------------------
    # At any time it should be possible to filter the entries and show them
    # Note that this may be called at the beginning , when there is nothing in the list...
    def GUI_refresh(self ):    
        
        for row in self._qcounters_list.qcounters_list:
            e_row : Qcounters_row = row
            
            self._jtable_ensureVisible(e_row)

    # ------------------------------------------------------------------------
    # Utility, to make code cleaner
    # NOTE that part of the magic works because the channel number is a unique key
    # This MUST be run from swing thread
    def _jtable_ensureVisible(self, a_row : Qcounters_row ):

        if self._table_view.row_exist(a_row.row_idx):
            self._jtable_refresh_using_row(a_row)
        else:
            v_values=a_row.getValuesForTreeview()
            self._table_view.row_append(a_row.row_idx,v_values)


    # ------------------------------------------------------------------------------
    # this should update the swing table content for the given row
    def _jtable_refresh_using_row(self, a_row : Qcounters_row ):

        if not a_row:
            return
            
        self._table_view.set_row(a_row.row_idx,a_row.getValuesForTreeview(),'')   


# ==============================================================================
# I am adding rows in the exact order of the 'c' structure, including the size
# so, it is possible to extract the counters automagically
class Qcounters_row():

    # --------------------------------------------------------------------------
    # NOTE that the variable definition is basically useless
    def __init__(self, r_idx : int, c_size_b : int, v_name : str, c_desc : str ):

        self.row_idx : int = r_idx       # row index, to pick up values from the table click
        self.c_size_b : int = c_size_b   # size in bytes
        self.v_name : str = v_name
        self.c_desc : str = c_desc
        self.c_value : int = 0


    # -----------------------------------------------------------------
    # return the list of values to show into the table, the GUI table
    # NOTE that the order has to be consistent with the GUI definition
    def getValuesForTreeview(self):
        
        risul = (
            self.row_idx,
            self.c_size_b,
            self.v_name,
            self.c_value,
            self.c_desc
            )
            
        return risul         

        

        
# ========================================================================
# Let me try to have some decent OO wrapping in this shitty language
# The raw background data is always allocated
class qcounters_list(CsvTable):
    
    # -----------------------------------------------------------------
    # I need to preallocate list and never deallocate them
    # NOTE that squelch goes from zero to 9, inclusive
    def __init__(self):
        
        self.qcounters_list : typing.List[Qcounters_row] = []
        self._rows_count=0;
        
        # this MUST be in the same order as the 'c' struct 
        self._append_one(2,'bfsk_rx_count')
        self._append_one(2,'bfsk_rx_crcbad_count')
        self._append_one(2,'bfsk_rx_ber_count')
        self._append_one(2,'bfsk_tx_count')
        self._append_one(2,'rx_qsmsg_count')
        self._append_one(2,'rx_qstxt_count')
        self._append_one(2,'rx_qsack_count')
        self._append_one(2,'rx_ipp_count')
        self._append_one(1,'bfsk_rx_badlen_count')
        self._append_one(1,'bfsk_tx_radbusycount')
        self._append_one(1,'dtmf_ipp_rx_overflow_counter')
        self._append_one(1,'dtmf_char_rx_overflow_counter')
        self._append_one(1,'dtmf_rx_ack_counter')
        self._append_one(1,'dtmf_rx_response_counter')
        self._append_one(1,'dtmf_rx_call_counter')
        self._append_one(1,'dtmf_tx_call_counter')
        self._append_one(1,'EE_wr_address_bad_count')
        self._append_one(1,'EEprom_wr_count')
        self._append_one(1,'maintick_lost_count')
        self._append_one(1,'cpu_idle_avg','max idle is 48, the counter reloads at 48 and goes to 0')
        self._append_one(1,'adc_read_count','how many times has the ADC been read')
        self._append_one(1,'rx_qsack_bad_to')
        self._append_one(1,'rx_qsack_bad_msgid')
        self._append_one(1,'rx_agc_idx','possible values 3,2,1,0,7(-1)')
        self._append_one(1,'rx_agc_RSSI','high_th=0x54 low_th =0x42')
        self._append_one(1,'fscan_skip_step_fail')
        self._append_one(1,'tx_timeout_counter')
        self._append_one(1,'bkfm_already_tuning')
        self._append_one(1,'bkfm_already_seek')
        self._append_one(1,'dtmf_rx_parse_disabled')
        
        


        
    # -----------------------------------------------------------------------
    # crap triangle wheel missing ++
    def _append_one(self, c_size, c_name, c_desc='' ):
        a_c = Qcounters_row(self._rows_count, c_size, c_name, c_desc)
        self.qcounters_list.append(a_c)
        self._rows_count += 1
        
    # -----------------------------------------------------------------------
    # if idx is out of range, return None
    def get_row_using_idx(self, idx : int ) -> Qcounters_row:
        return self.qcounters_list[idx]
        

        
        
        
        


