'''
/** 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
 
'''
# -------------------------------------------------------------------------
# There is only ONE poll, this is a GUI and if there is something to send it should be set to the poll

from __future__ import annotations

from tkinter import StringVar, IntVar

from app_config import AppConfig, ConfigSavable
from glob_fun import fromHexDigitToByte, fromDtmfDigitToByte
from glob_gui import JtkWinToplevel, TV_Entry, LogPanel, GUI_hide_show_window,\
    JtkPanelPackTop, JtkLabel 
from ipp_parser import  Qsk5_req_send_dtmf
import qpystat
import tkinter.ttk as ttk


class QsdtmfGui (ConfigSavable,GUI_hide_show_window):

    # ----------------------------------------------------------------
    def __init__(self, stat : qpystat.Qpystat):
        self.stat = stat
        
        self.stat.appconfig.addMyselfToSavables(self)

        self._toplevel = JtkWinToplevel("DTMF window")
        
        aframe=JtkPanelPackTop(self._toplevel)     
        
        aframe.addItem(JtkLabel(aframe,"Press ENTER to send DTMF", style='Header1.TLabel',anchor='center' ))
        
        aframe.addItem(self._newOnlyDtmfPanel(aframe))
#        self._newHexDataPanel(aframe).pack(fill='x')    
        aframe.addItem(self._newDelayParamsPanel(aframe))
        aframe.addItem(self._newLogPanel(aframe),fill='both',expand=True)
        
        aframe.pack(fill='both',expand=True)
        
        self.GUI_hide_window()
        
        self.dtmf_println("QsdtmfGui init complete")

    # ------------------------------------------------------------------
    # Since I need to set a global vlass var and pithon does not have inline assignment
    def _newLogPanel(self, parent_panel) -> ttk.Widget:
        self._qsdtmf_log = LogPanel(parent_panel,"DTMF Log")
        return self._qsdtmf_log 

    # -------------------------------------------------------------------
    # prints something on the application log
    def dtmf_println(self, msg):
        self._qsdtmf_log.println(msg)    
        
    # --------------------------------------------------------------------
    # show a window that has been hidden using the withdraw method
    def GUI_show_window(self):
        self._toplevel.deiconify()    

    # --------------------------------------------------------------------
    # hide completely a window
    def GUI_hide_window(self):
        self._toplevel.withdraw()    

    # ------------------------------------------------------------------------------
    # returns the number of digits AND the actual byte array
    # this handles correctly ODD number if digits
    # @paeam source a string of chars holding "digits"
    # @param converter a function that takes a char and convert it to the proper value
    def _convertGenericToBytes(self, source : str, converter ):
        
        msb = 0
        nibble_index=0
        abytea = bytearray()
        
        for achar in source:
            adigit = converter(achar)
            if adigit > 15:
                break
            
            if (nibble_index & 1) == 0:
                msb = adigit
            else:
                abyte = msb << 4 | adigit
                abytea.append(abyte)
                
            nibble_index += 1
            
        if (nibble_index & 1) != 0:
            abyte = msb << 4
            abytea.append(abyte)
                
        return nibble_index,abytea

    # -------------------------------------------------------------------------------
    # there is nothing useful passed in args...
    # the main issue is that I cannot get the variable back
    def _callbackOnlyDtmf(self, var_name, var_type, optionsl):
        
        source : str =self.edit_only_dtmf.get()
        
        destination : str = ''
        
        dtmf_digits = set("#*ABCD0123456789")
        for achar in source:
            if achar in dtmf_digits:
                destination = destination + achar
            else:
                destination = destination + '0'
                
        self.edit_only_dtmf.set(destination)

    # -------------------------------------------------------------------------------
    # make a new frame and put an input line in it
    def _newOnlyDtmfPanel(self, parent):

        panel=ttk.Frame(parent,padding='3')
        
        ttk.Label(panel,text="Only DTMF chars ").pack(side='left')
        
        # this variable will store whatever the user has typed
        self.edit_only_dtmf = StringVar(panel)
        self.edit_only_dtmf.trace_add('write', self._callbackOnlyDtmf)
        
        input_entry = TV_Entry(panel, self.edit_only_dtmf)
        input_entry.pack(side='left', fill='x', expand=True)

        # if one press enter does the given action
        input_entry.bind('<Return>', self._sendOnlyDtmfEnter)
        
        return panel
    
    
    # -------------------------------------------------------------------------------
    def _sendOnlyDtmfEnter(self, _extra=None):
        aline = self.edit_only_dtmf.get()
        
        nibbles, abytes = self._convertGenericToBytes(aline, fromDtmfDigitToByte)
        self.dtmf_println("Send DTMF len="+str(nibbles)+" message="+str(abytes))
        
        cmd = Qsk5_req_send_dtmf(self.play_len_cs.get(),self.play_mute_cs.get(),nibbles, abytes, False)
        self.stat.qconnect.queuePut(cmd)


    # -------------------------------------------------------------------------------
    # there is nothing useful passed in args...
    def _callbackHex(self, *args):
        source : str =self.edit_only_hex.get()
        destination : str = ''
        
        hex_digits = set("0123456789abcdefABCDEF")
        for achar in source:
            if achar in hex_digits:
                destination = destination + achar
            else:
                destination = destination + '0'
        self.edit_only_hex.set(destination)

    # -------------------------------------------------------------------------------
    # Use this when you are sending a prepared HEX packet
    # every digit is a HEX nibble
    def _newHexDataPanel(self, parent):

        panel=ttk.Frame(parent,padding='3')
        
        ttk.Label(panel,text="HEX string MSB | LSB ").pack(side='left')
        
        # this variable will store whatever the user has typed
        self.edit_only_hex = StringVar(panel,value='')
        
        self.edit_only_hex.trace_add('write', self._callbackHex)
        
        input_entry = ttk.Entry(panel, font=('calibri',13), textvariable=self.edit_only_hex)
        input_entry.pack(side='left', fill='x', expand=True)

        # if one press enter does the given action
        input_entry.bind('<Return>', self._sendOnlyHexEnter)
        
        return panel
    
    # -------------------------------------------------------------------------------
    # Provide the space to sed delay parameters
    def _newDelayParamsPanel(self, parent):

        panel=ttk.Frame(parent,padding='3')
        
        ttk.Label(panel,text="Play len (cs) ").pack(side='left')
        
        self.play_len_cs = IntVar(panel,value=20)
        ttk.Entry(panel, font=('calibri',13), textvariable=self.play_len_cs, width=5).pack(side='left')

        ttk.Label(panel,text="  Play mute (cs) ").pack(side='left')

        self.play_mute_cs = IntVar(panel,value=5)
        ttk.Entry(panel, font=('calibri',13), textvariable=self.play_mute_cs, width=5).pack(side='left')
        
        return panel
    
    # -------------------------------------------------------------------------------
    # Transform the line into a sequence of bytes, where every digit is a piece
    def _sendOnlyHexEnter(self, _extra=None):

        aline = self.edit_only_hex.get()
        
        nibbles, barray = self._convertGenericToBytes(aline, fromHexDigitToByte)
        self.dtmf_println("Send HEX len="+str(nibbles)+" message="+str(barray))
        
        cmd = Qsk5_req_send_dtmf(self.play_len_cs.get(),self.play_mute_cs.get(),nibbles,barray, False)
        self.stat.qconnect.queuePut(cmd)


    # -------------------------------------------------------------------
    # implement the config savable
    def appImportConfig(self, cfg : AppConfig ):
        adict = cfg.getDictValue("qsdtmf_cfg", {})
        
        try:
            self._toplevel.setGeometry(adict['gui_cfg'])
        except Exception as _exc :
            pass            

    # -------------------------------------------------------------------
    # implement the config savable
    def appSaveConfig(self, cfg : AppConfig ):
        adict = dict()

        adict['gui_cfg'] = self._toplevel.getGeometry()

        cfg.setDictValue("qsdtmf_cfg", adict )            
    
    

        
        

