'''
/** 
 * 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

This is now handling beeps
the table is of fixed size

  
''' 

from __future__ import annotations

import csv
from tkinter import ttk, IntVar, messagebox
import tkinter
import typing

from app_csv import CsvTable, Csv_Writer, Csv_Reader
from glob_eeprom import GlobEeprom, EEblock
from glob_fun import getResourcesFname
from glob_gui import EE_events_listener, JtkPanelGrid, TV_Entry, \
    JtkPanelPackTop, JtkLabel, JtkPanelPackLeft, JtkPanelTabbed
import qpystat
import qseeprom_gui


# =====================================================================
# the table with the list of FM channels
# It should take the data from the global EEPROM repository
# It will be signalled when new EEPROM data is received
class Qsbeep_gui (EE_events_listener,CsvTable):

    # ----------------------------------------------------------------
    def __init__(self, parent_obj : qseeprom_gui.Qseeprom_gui , parent_frame : ttk.Frame ):
      
        self._parent_obj : qseeprom_gui.Qseeprom_gui = parent_obj
        self._stat : qpystat.Qpystat = parent_obj._stat

        self.work_panel = ttk.Frame(parent_frame)
        
        self.c_panel=self._newCenterPanel(self.work_panel)
        
        self.c_panel.pack(fill='both', expand=True)


    # ------------------------------------------------------------------------
    def tkraise(self):
        self.work_panel.tkraise()
        
    # ------------------------------------------------------------------------
    def _println(self, msg : str ):
        self._parent_obj._println(msg)

    # ------------------------------------------------------------------------
    def showInfo(self, a_message : str ):
        messagebox.showinfo("Beep", a_message, parent=self.work_panel, type='ok')    
        
    # -------------------------------------------------------------------------------
    # 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):
        
        apanel = JtkPanelPackTop( parent_panel) 
        
        apanel.addItem(JtkLabel(apanel,"Beeps and Ringtones", style='Header1.TLabel',anchor='center' ))
        apanel.addItem(self._newTabPanel(apanel))
        apanel.addItem(self._new_apply_default_panel(apanel))
        
        return apanel


    # -------------------------------------------------------------------------------
    def _newBasicBeep(self, parent_frame : ttk.Widget ) -> JtkPanelGrid:

        gridpanel = JtkPanelGrid(parent_frame)

        gridpanel.addItem(JtkLabel(gridpanel,"Nr."))
        gridpanel.addItem(JtkLabel(gridpanel,"Tone Hz"))
        gridpanel.addItem(JtkLabel(gridpanel,"Play time (cs)"))
        gridpanel.addItem(JtkLabel(gridpanel,"Mute time (cs)"))
        gridpanel.addItem(JtkLabel(gridpanel,"Note"))
        
        gridpanel.nextRow()

        ridx_next=self._newRow(gridpanel ,0  ,0 ,'NULL')
        ridx_next=self._newRow(gridpanel ,ridx_next ,0 ,'Error')
        ridx_next=self._newRow(gridpanel ,ridx_next ,0 ,'880Hz')
        ridx_next=self._newRow(gridpanel ,ridx_next ,0 ,'Keyboard')
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 ,'Call From user')
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,0 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 ,'Call from a group')
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,0 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,5 ,'Timer Alarm')
        ridx_next=self._newRow(gridpanel ,ridx_next ,5 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,5 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,0 )
            
        return gridpanel

    # -------------------------------------------------------------------------------
    def _newChvoiceStart(self, parent_frame : ttk.Widget ) -> JtkPanelGrid:

        gridpanel = JtkPanelGrid(parent_frame)

        gridpanel.addItem(JtkLabel(gridpanel,"Nr."))
        gridpanel.addItem(JtkLabel(gridpanel,"Tone Hz"))
        gridpanel.addItem(JtkLabel(gridpanel,"Play time (cs)"))
        gridpanel.addItem(JtkLabel(gridpanel,"Mute time (cs)"))
        gridpanel.addItem(JtkLabel(gridpanel,"Note"))
        
        gridpanel.nextRow()

        ridx_next=self._newRow(gridpanel ,16 ,3 ,'call voice start')
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,0 )

        return gridpanel

    # -------------------------------------------------------------------------------
    def _newChvoiceEnd(self, parent_frame : ttk.Widget ) -> JtkPanelGrid:

        gridpanel = JtkPanelGrid(parent_frame)

        gridpanel.addItem(JtkLabel(gridpanel,"Nr."))
        gridpanel.addItem(JtkLabel(gridpanel,"Tone Hz"))
        gridpanel.addItem(JtkLabel(gridpanel,"Play time (cs)"))
        gridpanel.addItem(JtkLabel(gridpanel,"Mute time (cs)"))
        gridpanel.addItem(JtkLabel(gridpanel,"Note"))
        
        gridpanel.nextRow()

        ridx_next=self._newRow(gridpanel ,24 ,3 ,'Call voice end')
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,0 )

        return gridpanel

    # -------------------------------------------------------------------------------
    def _newRxmsgr(self, parent_frame : ttk.Widget ) -> JtkPanelGrid:

        gridpanel = JtkPanelGrid(parent_frame)

        gridpanel.addItem(JtkLabel(gridpanel,"Nr."))
        gridpanel.addItem(JtkLabel(gridpanel,"Tone Hz"))
        gridpanel.addItem(JtkLabel(gridpanel,"Play time (cs)"))
        gridpanel.addItem(JtkLabel(gridpanel,"Mute time (cs)"))
        gridpanel.addItem(JtkLabel(gridpanel,"Note"))
        
        gridpanel.nextRow()

        ridx_next=self._newRow(gridpanel ,32 ,3 ,'Rx Message')
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,3 )
        ridx_next=self._newRow(gridpanel ,ridx_next ,0 )

        return gridpanel

    
    # ---------------------------------------------------------------------
    def _newTabPanel(self, parent_panel : ttk.Frame ) -> ttk.Widget:
        
        self._qsbeep_list : typing.List[Qsbeep_row] = []

        a_panel=JtkPanelTabbed(parent_panel)
                
        a_panel.addItem(self._newBasicBeep(a_panel),"Base Beeps")
        a_panel.addItem(self._newChvoiceStart(a_panel),"Beep Voice Start")
        a_panel.addItem(self._newChvoiceEnd(a_panel),"Beep Voice End")
        a_panel.addItem(self._newRxmsgr(a_panel),"Beep Rx Message")

        return a_panel

    # ---------------------------------------------------------------------
    def _newRow (self, gridpanel : JtkPanelGrid, r_index, mute_cs, note='' ) -> int:
        self._qsbeep_list.append(Qsbeep_row(self, gridpanel ,r_index ,mute_cs ,note))
        gridpanel.nextRow()
        return r_index+1

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

        a_panel.addItem(ttk.Button(a_panel,text="Optimal Default", command=self._click_optimal_default ))
        a_panel.addItem(JtkLabel(a_panel,"Press Write to save on radio"))

        return a_panel
        
    # ------------------------------------------------------------------------
    def updateGuiFromEeprom(self):
        
        for row in self._qsbeep_list:
            row.updateRowFromEeprom(self._stat.globeeprom)

    # -----------------------------------------------------------------
    def update_EEblock_from_GUI(self):

        self._println("qsbeep.update_EEblock_from_GUI CALL")

        for row in self._qsbeep_list:
            row.update_EEblock_from_GUI(self._stat.globeeprom)
        
    # ----------------------------------------------------------
    # override CSV
    def csv_tableName(self) -> str:
        return 'radio_beep'
    
    # ----------------------------------------------------------
    # override CSV
    def csv_write_header(self, a_writer : Csv_Writer):
        a_writer.writerow(Qsbeep_row.csv_heading)
        
    # ---------------------------------------------------------
    # in a different thread than swing, write the table to this csv writer
    def csv_write_table(self, a_writer : Csv_Writer):
        
        for row in self._qsbeep_list:
            v_list = row.csv_get_values()
            a_writer.writerow(v_list)

    # -------------------------------------------------------------
    # the difference is that clipboard will insert from a given point
    # for CSV, instead, I am given the row index            
    def csv_parse_row(self, row_values : typing.List[str] ):
        r_iter = iter(row_values)
        
        r_idx = int(next(r_iter))
        
        a_row : Qsbeep_row = self._qsbeep_list[r_idx]
        
        a_row.csv_parse_row(r_iter)

    # ---------------------------------------------------------------------
    def _click_optimal_default(self):

        fpath = getResourcesFname('qsbeep_default.csv')
        with open(fpath, 'r', newline='') as csv_file:
            self._csv_parse(csv_file)

    # ---------------------------------------------------------------------
    def _csv_parse(self, csv_file ):
        
        c_reader : Csv_Reader = csv.reader(csv_file, delimiter='\t', quotechar='\\', quoting=csv.QUOTE_MINIMAL)
        
        for row in c_reader:
            self.csv_parse_row(row)

        

# ==============================================================================
# Q squelch row is made of the following components
# note that there is a value for the band and also for the level
# also, there is something on a delay for squelch... on reg_4E
class Qsbeep_row():

    csv_heading=['cbep_idx','cbep_FHz','cbep_play_cs','cbep_mute_cs','cbep_note']

    # --------------------------------------------------------------------------
    def __init__(self, parent_o : Qsbeep_gui, parent_grid : JtkPanelGrid, r_idx : int, mute_cs, r_note : str ):

        self._parent_o = parent_o
        self.r_idx     = r_idx        # row index, to pick up values from the table click
        parent_grid.addItem(JtkLabel(parent_grid,str(r_idx)))
        
        self.r_FHz     = IntVar(parent_grid)
        parent_grid.addItem(TV_Entry(parent_grid, self.r_FHz,width=6))
        
        self.r_play_cs = IntVar(parent_grid)
        parent_grid.addItem(TV_Entry(parent_grid, self.r_play_cs,width=3))
        
        self.r_mute_cs = IntVar(parent_grid, mute_cs)
        m_entry=TV_Entry(parent_grid, self.r_mute_cs,width=3)
        if mute_cs == 0:
            m_entry.configure(state=tkinter.DISABLED)
        parent_grid.addItem(m_entry)
        
        self.r_note    = r_note      
        parent_grid.addItem(JtkLabel(parent_grid,str(r_note)))
        
        # the eeprom is able to pick up blocks of 16 bytes
        b_offset = r_idx * 4
        self._r_eeaddr = 0x1670 + b_offset   # this is where the data is in the eeprom
        self._r_eebidx = b_offset % 16       # this is where in the block this beep is 
        
    # -----------------------------------------------------------------
    # must return the values as a list of strings in the same order as the header
    def csv_get_values(self) -> typing.List[str]:
        
        risul : typing.List[str] = []
        
        risul.append(str(self.r_idx))
        risul.append(str(self.r_FHz.get()))
        risul.append(str(self.r_play_cs.get()))
        risul.append(str(self.r_mute_cs.get()))
        risul.append(str(self.r_note))
        
        return risul
        
        
    # ------------------------------------------------------------------
    # this assumes tha values are in the SAME order and same format as the export !
    # note that s_split is an iterator for strings and the FIRST item (the row index) has already been taken out
    def csv_parse_row(self, r_iter ):
        if not r_iter:
            return 
        
        self.r_FHz.set(int(next(r_iter,0)))
        self.r_play_cs.set(int(next(r_iter,0)))
        self.r_mute_cs.set(int(next(r_iter,0)))
    
    # -----------------------------------------------------------------
    def updateRowFromEeprom(self, g_eeprom : GlobEeprom ):
        
        a_block : EEblock = g_eeprom.get_block_from_address(self._r_eeaddr)
        
        FHz, play_cs, mute_cs = a_block.eeprom_unpack('<HBB', self._r_eebidx)

        self.r_FHz.set(FHz)
        self.r_play_cs.set(play_cs)
        self.r_mute_cs.set(mute_cs)

    # -----------------------------------------------------------------
    # Note that what can be changed are just the values, 
    # update ONLY if the data has changed
    def update_EEblock_from_GUI(self, g_eeprom : GlobEeprom ):

        a_block : EEblock = g_eeprom.get_block_from_address(self._r_eeaddr)
        
        r_FHz = self.r_FHz.get()
        r_play_cs = self.r_play_cs.get()
        r_mute_cs = self.r_mute_cs.get()
        
        a_block.eeprom_pack_into('<HBB', self._r_eebidx, r_FHz, r_play_cs, r_mute_cs)


