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

 
 
'''
# the idea is that this allocate the main console in a GUI
# You can have the standard console in the "main thread", this is one in a GUI
# I need a model similar to Java, for reliability, so, NO variables in module
# python has a weird idea on the scope of a module variable from other modules
# Plus, no private keyword, at all
# TO have this updated on save you need to configure the editor Save Actions
# ALSO the INITIAL VALUE MUST be valid for the given format eg: yyyy-MM-dd HH:mm 

from __future__ import annotations

import os
from tkinter import ttk, messagebox

from app_config import AppConfig, ConfigSavable
from app_csv import AppCsv
from app_gui import InputParserThread
import app_gui 
from app_version import PREPPERDOCK_version
from glob_eeprom import GlobEeprom
from glob_gui import  JtkWinRoot, JtkPanelLayered
import glob_mlang
import intro_gui
from qconnect_gui import QconnectThread
import qpystat
from qscalibrate_gui import Qscalibrate_gui
from qsdtmf_gui import QsdtmfGui
from qseeprom_gui import Qseeprom_gui
from qsmsg_gui import QsmsgGui
from racommand_gui import Racommand_gui
from spectrum_gui import SpectrumGui
import tkinter as tk 
from wiradio_gui import Wiradio_gui
from wiremote_gui import Wiremote_gui


# -----------------------------------------------------------------
# The class is allocated and the the "run" is called from the main thread, since python cannot handle threads in a decent way
class QskradioMainGui (ConfigSavable):

    font_size=14

    # ----------------------------------------------------------------------
    # Constructor
    def __init__(self, stat : qpystat.Qpystat):
        self.stat=stat
        
        # add myself to the pieces that can be saved and restored
        self.stat.appconfig.addMyselfToSavables(self)
        
        # this first, since the GUI need to know the input queue
        self.stat.inputParser = InputParserThread(stat)

    # ----------------------------------------------------------------------
    def _println(self, msg : str ):
        self.stat.app_println(msg)

    # ----------------------------------------------------------------------
    # we can allocate the main Gui and ALL the remaining component
    def runThread(self):
        print ("START QskradioMainGui ")
        
        self._tkroot = JtkWinRoot(self.stat, "PrepperDock", 'prepperdock', self.on_closing, False)
        
        a_menu = QuanshengMenu(self._tkroot,self.stat)
        self._tkroot.config(menu=a_menu)
        
        self._adjustTtkStyle()
        
        # the first, since the rest of the application may need it to work...        
        self.stat.glob_mlang = glob_mlang.PrepperMlang(self.stat)

        a_panel = JtkPanelLayered(self._tkroot)

        self.stat.appmain_gui = app_gui.AppMainGui(self.stat, a_panel)
        a_panel.addItem(self.stat.appmain_gui)

        self.stat.intro_gui = intro_gui.Intro_gui(self.stat, a_panel)
        a_panel.addItem(self.stat.intro_gui)
        
        a_panel.pack(fill='both',expand=True)
        
        # ---------------------- end of gui elements that are switchable ---------------------
        
        self.stat.appcsv        = AppCsv(self.stat)
        self.stat.qconnect      = QconnectThread(self.stat)
        self.stat.qsmsg_gui     = QsmsgGui(self.stat)
        self.stat.qsdtmf_gui    = QsdtmfGui(self.stat)
        self.stat.spectrum_gui  = SpectrumGui(self.stat)
        self.stat.racommand_gui = Racommand_gui(self.stat)
        self.stat.qscalibrate_gui = Qscalibrate_gui(self.stat)
        self.stat.wiremote_gui  = Wiremote_gui(self.stat)
        self.stat.wiradio_gui   = Wiradio_gui(self.stat)
        
        self.stat.globeeprom = GlobEeprom(self.stat)     # this first, the global eeprom storage
        self.stat.eeprom_gui = Qseeprom_gui(self.stat)   # then this

        # show the intro panel (could be saved)....
        self.stat.intro_gui.tkraise()
        
        # this will run half second later, to adjust windows properties and start servers
        self._tkroot.runLater(400,self._runLaterOnsettled)

        # this is basically the Swing events thread
        self._tkroot.mainloop()

        # NOTE that you MUST save window position when they are still active
        self.stat.appconfig.saveConfigToFile()    

        print ("END QskradioMainGui ")
        
        # This is the most reliable way to terminate all the stuff
        os._exit(0)

    # ----------------------------------------------------------------------------
    # the part that runs on swing thread
    # NOTE that you can attach message box to different parents (and you should !!)
    def _swing_showMessageBox(self,a_message : str ):
        messagebox.showinfo("PrepperDock_message", a_message, parent=self._tkroot, type='ok')

    # ----------------------------------------------------------------------------
    # Anybody can call this one
    def showMessageBox(self, a_message : str ):
        self._tkroot.runIdle(self._swing_showMessageBox,a_message)

    # -----------------------------------------------------------------
    # this is what should be done, on this window closing        
    def on_closing(self):
        self.stat.inputParser.queuePut('quit')

    # --------------------------------------------------------------------
    # See https://tkdocs.com/tutorial/styles.html
    # AH, remember that ALL widgets styles begin with T
    # AH, remember that ttk.Entry font CANNOT be specified using a style ....
    # https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/ttk-map.html
    # https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/colors.html
    # NOTE that in some way the naming os "reversed", see Red.TEntry
    def _adjustTtkStyle(self):
        style = ttk.Style(self._tkroot)

        # on windows, the default theme is vista
        # and that does NOT allow to customize buttons, much
        #print(style.theme_use('classic'))

        # this changes the property for ALL widgets
        # https://www.pythontutorial.net/tkinter/ttk-style/        
        # https://wiki.tcl-lang.org/page/Changing+Widget+Colors
        style.configure(".", background='#fff9eb')
        
        style.configure("Treeview", highlightthickness=0, bd=0, font=('Calibri', self.font_size)) # Modify the font of the body
        style.configure("Treeview.Heading", font=('Calibri', self.font_size,'bold')) # Modify the font of the headings
        style.configure("TEntry", foreground = 'green', font=('Calibri', 13,'bold'), width=4) # Modify the font of the headings
        # NOTE that the background for a TEntry is set using fieldbackground
        style.configure("Yellow.TEntry", foreground = 'blue', fieldbackground='yellow', font=('Calibri', 15,'bold'), width=4)
        style.configure("Red.TEntry",    foreground = 'red', font=('Calibri', 17,'bold'), width=4) 
        style.configure("TProgressbar", thickness=10)
        style.configure("Bold.TLabel", font=("Helvetica", 12, "bold"), foreground = '#6c2c12')
        style.configure("Header1.TLabel", font=("Helvetica", 16, "bold"), foreground = '#27abe2')
        style.configure("UMisura.TLabel", font=("Helvetica", 12, "bold"))  # , background='red'
        style.configure("Log.TLabel", font=(12))

        style.configure("TButton", background='#faf1e6')
        
        style.configure("EEPanels.TButton", background='#d2dad0', font=('Helvetica', 13, 'bold'))
        
        #style.map('EEPanels.TButton',foreground=[('disabled', 'yellow'),('pressed', 'red'),('active', 'blue')],
        #          background=[('disabled', 'magenta'),('pressed', '!focus', 'cyan'),('active', 'green')],
        #          highlightcolor=[('focus', 'green'),('!focus', 'red')],
        #          relief=[('pressed', 'groove'),('!pressed', 'ridge')])         
         
         
        
        #style.configure("TLabel",background=def_background)
        #style.configure("TFrame", background=def_background)


    # --------------------------------------------------------------------
    # implement the config savable
    def appImportConfig(self, cfg : AppConfig ):
        self._tkroot.setGeometry(cfg.getDictValue("qsk5_gui", {}))

    # --------------------------------------------------------------------
    # implement the config savable
    def appSaveConfig(self, cfg : AppConfig ):
        cfg.setDictValue("qsk5_gui", self._tkroot.getGeometry())
        
    # ----------------------------------------------------------------
    # This is called when the GUI is up and running, basically, started on gui thread
    # with a delay of 500ms, needed to set the window status appropriately
    def _runLaterOnsettled(self):
        self.stat.appconfig.importPartConfig()
        
        # thread have to start once the GUI is up and running
        self.stat.inputParser.start()
        self.stat.qconnect.start()
        self.stat.wiremote_gui.start()
        self.stat.wiradio_gui.start()
        
        self._println("PrepperDock "+PREPPERDOCK_version+" started")


        
    # -------------------------------------------------------------------
    # called by another thread to shutdown the GUI
    # before shutting down, save the window position
    def endGuiConsole(self):
#        print ("endGuiConsole CALL")

        # window position must be saved before stopping GUI
        self.stat.appconfig.savePartConfig()

        # this will terminate the event loop
        # MUST be run on the gui thread to avoid concurrency issues 
        self._tkroot.runIdle(self._tkroot.destroy)

    # ------------------------------------------------------
    # Example on how you can raise different panels to top        
    def raiseMain_gui (self):
        self.stat.appmain_gui.tkraise()

            
        
# ===========================================================================        
# Want to wrap the whole menu mess in here
# This part of the gui must do nothing until all pieces are actually in place
# NOTE that the constructor creates the menu structure

class QuanshengMenu(tk.Menu):

    # ------------------------------------------------------
    def __init__(self, guiroot, stat : qpystat.Qpystat):
        tk.Menu.__init__(self,guiroot)
        
        self.stat=stat;
        
        preppermenu = tk.Menu(self,tearoff=0)
        
        preppermenu.add_command(label="Home", command=self._showIntro)
        preppermenu.add_command(label="Advanced", command=self._showConsole)
        preppermenu.add_command(label="Radio Command", command=self._showRadioCommand)
        preppermenu.add_command(label="Calibration", command=self._showQscalibrate)
        preppermenu.add_command(label="Wiremote", command=self._showWiremote)
        preppermenu.add_command(label="Wiradio", command=self._showWiradio)

        self.add_cascade(label="Prepper Menu", menu=preppermenu)

    # ------------------------------------------------------
    # should allow a user to select the topdir where resources are stored
    # normally in user home directory
    def _selectResources(self):
        self.stat.glob_mlang.GUI_show_window()
    
    def _showConsole(self):
        self.stat.qsk5_gui.raiseMain_gui()

    def _showIntro(self):
        self.stat.intro_gui.tkraise()

    def _showRadioCommand(self):
        self.stat.racommand_gui.GUI_show_window()

    def _showQscalibrate(self):
        self.stat.qscalibrate_gui.GUI_show_window()

    def _showWiremote(self):
        self.stat.wiremote_gui.GUI_show_window()

    def _showWiradio(self):
        self.stat.wiradio_gui.GUI_show_window()

